Как обрабатывать Findbugs "Непрерывное несериализуемое поле экземпляра в сериализованном классе"?
Рассмотрим следующий класс. Если я запустил Findbugs против него, это даст мне ошибку ( "Непрерывное несериализуемое поле экземпляра в сериализуемом классе" ) в строке 5, но не в строке 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 }
Это правильно, потому что java.util.Set никогда не реализует Serializable в своей иерархии и java.util.HashSet.
Однако лучше всего использовать код вместо интерфейсов вместо конкретных реализаций.
Как я могу лучше всего справиться с этим?
Я могу добавить @Suppresswarnings (justification = "No bug", values = "SE_BAD_FIELD" ) в строке 3. У меня довольно много наборов и списков в моем фактическом коде, и я боюсь, что это пометит мой код слишком много.
Есть ли лучшие способы?
Ответы
Ответ 1
Однако лучше всего использовать код вместо интерфейсов вместо бетона реализации.
Я утверждаю, что нет, в этом случае это не так. Findbugs совершенно правильно сообщает вам, что вы рискуете запуском в NotSerializableException
, как только в этом поле будет реализована несериализуемая реализация Set
. Это то, с чем вам нужно иметь дело. Как, это зависит от дизайна ваших классов.
- Если эти коллекции инициализируются внутри класса и никогда не устанавливаются извне, я абсолютно ничего не вижу в объявлении конкретного типа для поля, так как поля все равно являются деталями реализации. Используйте тип интерфейса в общедоступном интерфейсе.
- Если коллекция передается в класс через открытый интерфейс, вы должны убедиться, что они фактически
Serializable
. Для этого создайте интерфейс SerializableSet extends Set, Serializable
и используйте его для своего поля. Затем либо:
- Используйте
SerializableSet
в общедоступном интерфейсе и предоставляйте классы реализации, которые его реализуют.
- Проверять коллекции, переданные классу через
instanceof Serializable
, а если нет, скопируйте их в нечто, что есть.
Ответ 2
Я знаю, что это уже старый вопрос, который уже ответил, но только потому, что другие знают, что вы можете установить поле Set<Integer>
как переходное, если у вас нет интереса к сериализации этого конкретного поля, которое исправит вашу ошибку FindBugs.
public class TestClass implements Serializable {
private static final long serialVersionUID = 1905162041950251407L;
private transient Set<Integer> mySet;
}
Я предпочитаю этот метод вместо того, чтобы принуждать пользователей вашего API к вашему конкретному типу, если только он не является внутренним, тогда ответ Майкла Боргвардта имеет смысл.
Ответ 3
Вы можете использовать помощник захвата, чтобы убедиться, что переданный в Set поддерживает два интерфейса:
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);
}
}
Таким образом, вы можете иметь общедоступный API, который принудительно выполняет Serializable, не проверяя/не требуя конкретных деталей реализации.
Ответ 4
Я использую фильтр findbugs-exclude для коллекции-полей:
<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>
См. http://findbugs.sourceforge.net/manual/filter.html
Ответ 5
Вы можете избавиться от этих предупреждающих сообщений Critical
, добавив в свой класс следующие методы:
private void writeObject(ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
Ответ 6
Используйте конкретный набор Serializable для вашего внутреннего представления, но при использовании любых открытых интерфейсов используйте интерфейс 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);
}
}
Ответ 7
использовать
private transient Set<Integer> mySet;
Ответ 8
Если вы используете findbugs-maven-plugin и должны сохранять поле, и это поле является классом, не реализующим интерфейс Serializable, например, поле, которое имеет класс, определенный третьим лицом. Вы можете вручную настроить файл исключения для findbugs,
Если это единственный случай, добавьте его в файл exclude:
П:
<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>
Entity:
@Entity
public class Foo extends Boo {
StateMachineContext<A, B> stateMachineContext;
Хотя я не понимаю, почему добавление <Bug category="SE_BAD_FIELD"/>
не работает. Кроме того, я не согласен с решением добавления аннотации в поле типа @edu.umd.cs.findbugs.annotations.SuppressWarnings(justification="No bug", values="SE_BAD_FIELD")
, потому что строительные инструменты лучше не проникают в бизнес-код. использование плагина maven и фильтры findbugs включают и исключают
О SE_BAD_FIELD: Непрерывное несериализуемое поле экземпляра в сериализованном классе, я думаю, что он не должен проверять сущности. Поскольку javax.persistence.AttributeConverter
предлагает методы для сериализации внешней стороны поля (реализует Serializable - это внутренний метод для сериализации).