Considérez la classe ci-dessous. Si j'exécute Findbugs contre cela, cela me donnera une erreur ("Champ d'instance non transitoire non sérialisable dans la classe sérialisable") sur la ligne 5 mais pas sur la ligne 7.
1 public class TestClass implements Serializable {
2
3 private static final long serialVersionUID = 1905162041950251407L;
4
5 private Set<Integer> mySet; // Findbugs error
6
7 private HashSet<Integer> myOtherSet;
8
9 }
C'est correct car Java.util.Set n'implémente jamais Serializable dans sa hiérarchie et Java.util.HashSet le fait. Cependant, il est préférable de coder contre des interfaces au lieu d'implémentations concrètes.
Comment puis-je gérer au mieux cela?
Je peux ajouter un @Suppresswarnings (justification = "Pas de bug", values = "SE_BAD_FIELD") sur la ligne 3. J'ai beaucoup d'ensembles et de listes dans mon code actuel et je crains que cela ne gâche trop mon code.
Y a-t-il de meilleures façons?
Cependant, il est préférable de coder contre des interfaces au lieu d'implémentations concrètes.
Je soutiens que non, dans ce cas, ce n'est pas le cas. Findbugs vous indique très correctement que vous risquez de rencontrer un NotSerializableException
dès que vous avez une implémentation Set
non sérialisable dans ce champ. C'est quelque chose que vous devez gérer. Comment, cela dépend de la conception de vos classes.
Serializable
. Pour ce faire, créez une interface SerializableSet extends Set, Serializable
et utilisez-le pour votre domaine. Ensuite, soit: SerializableSet
dans l'interface publique et fournissez les classes d'implémentation qui l'implémentent.instanceof Serializable
et s'ils ne le sont pas, copiez-les dans quelque chose qui l'est.Je sais que c'est une vieille question à laquelle on a déjà répondu, mais pour que les autres sachent, c'est que vous pouvez définir le Set<Integer>
champ comme transitoire si vous n'avez aucun intérêt à sérialiser ce champ particulier qui corrigera votre erreur FindBugs.
public class TestClass implements Serializable {
private static final long serialVersionUID = 1905162041950251407L;
private transient Set<Integer> mySet;
}
Je préfère cette méthode au lieu de forcer les utilisateurs de votre API à couler sur votre type de béton, à moins qu'il ne soit juste interne, la réponse de Michael Borgwardt a plus de sens.
Vous pouvez vous débarrasser de ces messages d'avertissement Critical
en ajoutant les méthodes suivantes à votre classe:
private void writeObject(ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
Vous pouvez utiliser un assistant de capture pour vous assurer qu'un ensemble transmis dans prend en charge deux interfaces:
private static class SerializableTestClass<T extends Set<?> & Serializable> implements Serializable
{
private static final long serialVersionUID = 1L;
private final T serializableSet;
private SerializableTestClass(T serializableSet)
{
this.serializableSet = serializableSet;
}
}
public static class PublicApiTestClass
{
public static <T extends Set<?> & Serializable> Serializable forSerializableSet(T set)
{
return new SerializableTestClass<T>(set);
}
}
De cette façon, vous pouvez avoir une API publique qui applique Serializable sans vérifier/nécessiter des détails d'implémentation spécifiques.
J'utilise un filtre findbugs-exclude pour les champs de collection:
<Match>
<Field type="Java.util.Map" />
<Bug pattern="SE_BAD_FIELD" />
</Match>
<Match>
<Field type="Java.util.Set" />
<Bug pattern="SE_BAD_FIELD" />
</Match>
<Match>
<Field type="Java.util.List" />
<Bug pattern="SE_BAD_FIELD" />
</Match>
Utilisez un ensemble sérialisable concret pour votre représentation interne, mais faites en sorte que toutes les interfaces publiques utilisent l'interface Set.
public class TestClass implements Serializable {
private static final long serialVersionUID = 1905162041950251407L;
private HashSet<Integer> mySet;
public TestClass(Set<Integer> s) {
super();
setMySet(s);
}
public void setMySet(Set<Integer> s) {
mySet = (s == null) ? new HashSet<>() : new HashSet<>(s);
}
}