java serialization findbugs

java - ¿Cómo manejar un campo de instancia "no transitoria no serializable Findbugs en clase serializable"?



serialization (8)

Sin embargo, es una buena práctica codificar contra interfaces en lugar de implementaciones concretas.

Yo presento que no, en este caso no lo es. Findbugs correctamente le dice que corre el riesgo de encontrarse con una NotSerializableException tan pronto como tenga una implementación Set no serializable en ese campo. Esto es algo con lo que deberías lidiar. Cómo, eso depende del diseño de tus clases.

  • Si esas colecciones se inicializan dentro de la clase y nunca se configuran desde afuera, entonces no veo absolutamente nada de malo en declarar el tipo concreto para el campo, ya que los campos son detalles de implementación de todos modos. Utiliza el tipo de interfaz en la interfaz pública.
  • Si la colección se pasa a la clase a través de una interfaz pública, debe asegurarse de que, de hecho, se pueda Serializable . Para hacer eso, crea una interfaz SerializableSet extends Set, Serializable y SerializableSet extends Set, Serializable para tu campo. Entonces tambien:
    • Use SerializableSet en la interfaz pública y proporcione clases de implementación que lo implementen.
    • Verifique las colecciones pasadas a la clase a través de una instanceof Serializable y si no lo están, cópielas en algo que sea.

Considera la clase a continuación. Si ejecuto Findbugs contra él, me dará un error ("campo de instancia no transitoria no serializable en la clase serializable") en la línea 5, pero no en la línea 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 }

Eso es correcto porque java.util.Set nunca implementa Serializable en su jerarquía y java.util.HashSet sí lo hace. Sin embargo, es una buena práctica codificar contra interfaces en lugar de implementaciones concretas.

¿Cómo puedo manejar esto mejor?

Puedo agregar un @Suppresswarnings (justification = "No bug", values ​​= "SE_BAD_FIELD") en la línea 3. Tengo un buen número de conjuntos y listas en mi código real y me temo que va a ensuciar mi código demasiado.

¿Hay mejores formas?


En caso de que esté utilizando findbugs-maven-plugin y tenga que mantener un campo, y ese campo es una clase que no implementa la interfaz Serializable, por ejemplo, un campo que tiene una clase definida en un tercero. Puede configurar manualmente el archivo de exclusión para findbugs,

Si este es el único caso, agréguelo a un archivo de exclusión: pom:

<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> <version>3.0.3</version> <configuration> <xmlOutput>true</xmlOutput> <xmlOutputDirectory>target/findbugs/</xmlOutputDirectory> <excludeFilterFile>findbugs-exclude.xml</excludeFilterFile> <includeFilterFile>findbugs-include.xml</includeFilterFile> <failOnError>true</failOnError> </configuration> ...

exclude.xml:

<?xml version="1.0" encoding="UTF-8"?> <FindBugsFilter> <Match> <Class name="com.xxx.Foo" /> <Field type="org.springframework.statemachine.StateMachineContext"/> </Match>

Entidad:

@Entity public class Foo extends Boo { StateMachineContext<A, B> stateMachineContext;

Aunque no entiendo por qué agregar <Bug category="SE_BAD_FIELD"/> no funcionaría. Además, no estoy de acuerdo con la solución de agregar anotaciones en el campo como @edu.umd.cs.findbugs.annotations.SuppressWarnings(justification="No bug", values="SE_BAD_FIELD") , porque es mejor que las herramientas de construcción no penetren código comercial http://findbugs.sourceforge.net/manual/filter.html uso y http://findbugs.sourceforge.net/manual/filter.html complementos maven http://findbugs.sourceforge.net/manual/filter.html

Acerca de SE_BAD_FIELD: campo de instancia no transitoria no serializable en la clase serializable , creo que no debería verificar las entidades. Porque, javax.persistence.AttributeConverter ofrece métodos para serializar un lado de campo (implementa Serializable es un método interno para serializar).


Puede deshacerse de esos mensajes de advertencia Critical agregando los siguientes métodos a su clase:

private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); }


Puede usar un asistente de captura para asegurarse de que un conjunto aprobado admite dos 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 esta forma, puede tener una API pública que haga cumplir Serializable sin verificar / requerir detalles de implementación específicos.


Sé que esta es una vieja pregunta que ya ha sido respondida pero que otros saben es que puedes establecer el campo Set<Integer> como transitorio si no tienes interés en serializar ese campo en particular que arreglará tu error FindBugs.

public class TestClass implements Serializable { private static final long serialVersionUID = 1905162041950251407L; private transient Set<Integer> mySet; }

Prefiero este método en lugar de forzar a los usuarios de su API a enviar a su tipo concreto, a menos que sea solo interno, entonces la respuesta de Michael Borgwardt tiene más sentido.


Use un conjunto Serializable concreto para su representación interna, pero haga que cualquier interfaz pública use la interfaz 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); } }


Uso un filtro de findbugs-exclude para campos de colección:

<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>

Ver http://findbugs.sourceforge.net/manual/filter.html


utilizar

private transient Set<Integer> mySet;