Is it safe to remove @Named annotations without a name?

2.9k views Asked by At

A tonne of code at my company uses the javax.inject.Named annotation with the default value, which the Javadoc indicates is the empty string "".

For example:

@Named
public class Foo {
   ... 
}

This does not appear to add any value, since the empty string doesn't have any semantic meaning. If I remove the @Named annotations will there be any harmful effects?

The question What is javax.inject.Named annotation supposed to be used for? describes how @Named functions, but doesn't explain any special significance of the empty string, or why it would be necessary or beneficial to omit the actual name.

The question When should you explicitly name a Managed Bean? likewise talks about when you would want to use names to differentiate injectable beans, but doesn't provide any rationale for the use of the empty string as a name.

Can I delete these un-named @Named annotations without breaking anything?

2

There are 2 answers

1
Daniel Pryden On

It's impossible to know if you will break anything without analyzing all the code that constructs injection keys and all the code that injects any of these bindings.

In some JSR-330 implementations (e.g. Dagger) it's not possible to use a @Named annotation with a value constructed at runtime, but in other implementations (e.g. Guice) it is possible and in fact commonly done.

For example, I could imagine a Guice module like:

public final class DynamicFooModule extends AbstractModule {
    private final String whichFoo;

    public DynamicFooModule(String whichFoo) {
        this.whichFoo = whichFoo;
    }

    @Override
    protected void configure() {
        Key<Foo> fooKey = Key.get(Foo.class, Names.named(whichFoo));
        Provider<Foo> fooProvider = getProvider(fooKey);
        bind(Foo.class).toProvider(fooProvider);
    }
}

This provides a binding for an unannotated Foo which delegates to a @Named(x) Foo, where x is determined by a constructor argument to the module -- which could be constructed at runtime, or derived from some default somewhere, etc.

You could imagine code building an injector like:

Injector injector = Guice.createInjector(
    ...,
    new DynamicFooModule(getSelectedFooConfig()),
    ...);

Where getSelectedFooConfig() might return "" as a default or fallback.

In a situation like that, @Named without any name could be a reasonable fallback value to use. If your application is doing anything like that, then it is not safe to remove the @Named bindings, because an un-annotated binding is not equivalent to a binding with an empty string.

I still would argue that this is not a good design: it would be better to use a dedicated qualifier annotation for this purpose (e.g. @ConfigBased("foo-config")) rather than just using @Named. If you were doing that then you could at least identify which strings were being used (or, better yet, eschew strings and use an enum instead).

0
chepukha On

@Named (javax.inject.Named) is equivalent of @Component (org.springframework.stereotype.Component).

When used to annotated a class, it indicates that the class will be scanned and registered. If name is not given, DI framework will use the class type when injecting dependencies.

In short, you can't remove those @Named annotation. If you do, everything will be compiled as normal. However, at runtime, you'll get runtime error something like cannot find bean xyz.