Как обработать Findbugs "Непереходное несериализуемое поле экземпляра в сериализуемом классе"? - PullRequest
52 голосов
/ 01 февраля 2011

Рассмотрим класс ниже.Если я запусту 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. У меня довольно много наборов и списков в моем фактическом коде, и я боюсь, что это будет слишком сильно засорять мой код.

Есть ли лучшие способы?

Ответы [ 7 ]

28 голосов
/ 01 февраля 2011

Однако лучше всего кодировать против интерфейсов вместо бетона Реализации.

Я утверждаю, что нет, в данном случае это не так. Findbugs совершенно правильно говорит вам, что вы рискуете наткнуться на NotSerializableException, как только у вас появится несериализуемая реализация Set в этой области. Это то, с чем вам следует иметь дело. Как, это зависит от дизайна ваших классов.

  • Если эти коллекции инициализируются внутри класса и никогда не устанавливаются извне, то я не вижу абсолютно ничего плохого в объявлении конкретного типа для поля, поскольку поля в любом случае являются деталями реализации. Используйте тип интерфейса в общедоступном интерфейсе.
  • Если коллекция передается в класс через открытый интерфейс, вы должны убедиться, что она действительно Serializable. Для этого создайте интерфейс SerializableSet extends Set, Serializable и используйте его для своего поля. Тогда либо:
    • Используйте SerializableSet в открытом интерфейсе и предоставьте классы реализации, которые его реализуют.
    • Проверьте коллекции, переданные классу через instanceof Serializable, и, если это не так, скопируйте их в нечто, что есть.
12 голосов
/ 10 апреля 2012

Я знаю, что это старый вопрос, на который уже дан ответ, но другие знают, что вы можете установить поле Set<Integer> как временное, если вы не заинтересованы в сериализации этого конкретного поля, которое исправит ошибку FindBugs.

public class TestClass implements Serializable {

    private static final long serialVersionUID = 1905162041950251407L;
    private transient Set<Integer> mySet;

}

Я предпочитаю этот метод вместо того, чтобы заставлять пользователей вашего API приводить к вашему конкретному типу, если только он не является внутренним, тогда ответ Михаила Боргвардта имеет больше смысла.

9 голосов
/ 07 мая 2015

Вы можете избавиться от этих Critical предупреждений, добавив в ваш класс следующие методы:

private void writeObject(ObjectOutputStream stream)
        throws IOException {
    stream.defaultWriteObject();
}

private void readObject(ObjectInputStream stream)
        throws IOException, ClassNotFoundException {
    stream.defaultReadObject();
}
8 голосов
/ 06 мая 2012

Вы можете использовать помощник захвата, чтобы гарантировать, что переданный в 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, не проверяя / не требуя конкретных деталей реализации.

6 голосов
/ 27 июня 2012

Я использую фильтр 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

1 голос
/ 03 сентября 2015

Используйте конкретный 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);
    }
}
0 голосов
/ 05 декабря 2017

В случае, если вы используете findbugs-maven-plugin и вам необходимо сохранить поле, и это поле является классом, не реализующим интерфейс Serializable, например поле, которое имеет класс, определенный в третьей стороне.Вы можете вручную настроить файл исключения для findbugs,

Если это единственный случай, добавьте его в файл исключения: 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>

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 - внутренний метод для сериализации).

...