14

In my Spring Boot application, I use com.github.spotbugs:spotbugs-maven-plugin plugin. The spotbugs check reports no issues on following class:

@Service
public class FooService {
    @Autowired
    CocoComponent cocoComponent;

    @PostConstruct
    public void init() {
        System.out.println(cocoComponent.getGreeting() + " world!");
    }
}

This works fine. However, since the autowired fields are not meant to be mutated after injection, I would prefer declaring them final. Like this:

@Service
public class BarService {
    final CocoComponent cocoComponent;

    public BarService(CocoComponent cocoComponent) {
        this.cocoComponent = cocoComponent;
    }

    @PostConstruct
    public void init() {
        System.out.println(cocoComponent.getGreeting() + " world!");
    }
}

The problem is, spotbugs check reports issue on BarService class:

[ERROR] Medium: new xxx.nnn.BarService(CocoComponent) may expose internal representation by storing an externally mutable object into BarService.cocoComponent [xxx.nnn.BarService] At BarService.java:[line 14] EI_EXPOSE_REP2

Of course I can:

  • keep using @Autowired non-final fields like in FooService
  • annotate all autowired constructors with @SuppressFBWarnings("EI_EXPOSE_REP2")

But, IMHO, neither is ideal.

My main question: Is there a way to configure spotbugs to not raise EI_EXPOSE_REP2 due storing objects of @Component (and any derivates such as @Service, @Repository, ..) annotated class in another object?

Alternatively (but not as ideal): Is there a way to configure spotbugs to not raise EI_EXPOSE_REP2 due storing mutable objects on an instance of @Component (and any derivates such as @Service, @Repository, ..) annotated class via constructor? I guess I could use a filter file but, AFAIK, there's no filter matching for annotations, so it would be based on package or class name pattern which is not pretty.

Any other suggestions to avoid polluting the code with @SuppressFBWarnings?

2
  • Have come across the same issue. Did you find anything other than suppress or use Autowired? I've put in the Suppressions for now as there's only a handful of examples at the moment but I can see it growing as our codebase
    – patrickm
    Commented Aug 8, 2022 at 8:19
  • @patrickm I just came across the same issue, and found a workaround that was acceptable to me (at least for my current situation). I added an answer describing it (it's basically, you might be able rename a method or two and have your dependency not show up as (trivially) mutable). Commented Jan 5 at 21:34

2 Answers 2

0

Using the information in the URL below as a hint, I was able to suppress the EI_EXPOSE_REP2 warning that occurs during constructor injection. (Might be a bit crude solution)

How to exclude a constructor in findbugs?

https://spotbugs.readthedocs.io/ja/latest/filter.html

spotbugs filter setting file

<FindBugsFilter ...>

    ...
    ...
    <Match>
        <Method name="&lt;init&gt;"/>
        <Bug pattern="EI_EXPOSE_REP2" />

    </Match>
    ...
    ...

</FindBugsFilter>
0

Depending on which parts of the code are under your control, you may be able to avoid problem by updating some names so that SpotBugs does not recognize your dependency as a mutable type.

This isn't an entirely satisfactory solution, since it's really just a workaround. SpotBugs is correctly noticing that your injected dependency is something whose internal state might change. I think that in the case of many service/controller relationships, that's completely appropriate.

At any rate, I ran into this same issue. My situation was essentially

class BookController {
  private final BookService bookService;

  public BookController(BookService bookService) {
    this.bookService = bookService;
  }
  // ...
}
class BookService {
  // ...
  public boolean addBook(Book book) { ... }
  // ...
}

SpotBugs flagged my code with EI_EXPOSE_REP2, since the internal state of the book service might be revealed through the book controller. Changing the name of the addBook(Book) method to something that did not start with add made the error go away. For instance, replacing addBook with adoptBook or receiveBook makes the bug go away.

After some digging, I found the list of method name prefixes that cause a class to be recognized as mutable. See MutableClasses#SETTER_LIKE_PREFIXES in the SpotBugs git repository:

    private static final List<String> SETTER_LIKE_PREFIXES = Arrays.asList(
            "set", "put", "add", "insert", "delete", "remove", "erase", "clear", "push", "pop",
            "enqueue", "dequeue", "write", "append", "replace");

Not the answer you're looking for? Browse other questions tagged or ask your own question.