Is it safe to remove #Named annotations without a name? - java

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?

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

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

Related

Why does JPMS allow annotation types as services

In introducing JPMS services, section 7.7.4 of the Java Language Specification notes that "The service type must be a class type, an interface type, or an annotation type."
I'm struggling to see the point of permitting an annotation. My understanding is that the JPMS notion of a service is something for which we expect to select an implementation at runtime. It also seems that, to be useful, the implementation needs at least the possibility of being something other than the original class that identifies the service being requested. But I believe an annotation cannot use "extends" so this could never happen? From that, I reach the belief that if I try to make a service out of an annotation type, I'd inevitably end up with a situation where the only thing that could ever be returned by a service lookup on, for example, SomeAnnotation.class would be exactly SomeAnnotation. That seems pointless, so I must assume I'm missing something.
Can anyone shed light on this, and perhaps offer examples of how an annotation might be a "service"?
It seems that you have missed another addition to the service providers. Within a named module, a service provider may return the implementation from a static method:
If the service provider declares a provider method, then the service loader invokes that method to obtain an instance of the service provider. A provider method is a public static method named "provider" with no formal parameters and a return type that is assignable to the service's interface or class.
In this case, the service provider itself need not be assignable to the service's interface or class.
from ServiceLoader
So the following would work:
module Example.Module {
uses example.Anno;
provides example.Anno with example.AnnoProvider;
}
package example;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Anno {
int value();
}
package example;
#Anno(42)
public class AnnoProvider {
public static Anno provider() {
return AnnoProvider.class.getAnnotation(Anno.class);
}
}
package example;
import java.util.ServiceLoader;
public class ServiceUser {
public static void main(String[] args) {
for(Anno a: ServiceLoader.load(Anno.class)) {
System.out.println(a.value());
}
}
}
While in Java an annotation interface cannot explicitly extend any interfaces (but implicitly it always extends java.lang.annotation.Annotation), it can be implemented. I.e. it is syntactically possible to write a concrete class implementing an annotation interface, though according to JLS 9.6. Annotation Types such a class does not represent an annotation type:
a subclass or subinterface of an annotation type is never itself an
annotation type
Thus I believe that the original question boils down to "why would anyone want to explicitly implement an annotation interface?". This question has already been asked and answered on SO: Use cases for implementing annotations. The accepted answer there proposes to do this in order to partially overcome the limitation that a value of an annotation element must be either a constant expression, or a class literal, or an enum constant (see JLS 9.7.1. Normal Annotations): one may implement an annotation interface to "annotate" the implementing class with an "annotation" that includes dynamic data taken e.g. from a config file, a database, etc. Obviously, such a technique also requires small changes in the code that reads annotations, as the class implementing an annotation interface is not actually annotated, but instead its instance can be used as an instance of an annotation as if it was retrieved e.g. via java.lang.Class.getAnnotationsByType.

Difference between #Inject and #ValueMapValue annotations

While reading AEM documentation about using models,
I couldn't figure out what is the difference between #Inject and #ValueMapValue annotation above the field.
I tried using both, and they both seems the same, so I must be missing something.
They are not the same, #Inject is a general purpose annotation that makes the value available from a number of injectors.
#ValueMapValue is an injector specific annotation that will specifically pick value from valuemap injector. It is equivalent to #Inject #Source("valuemap")
When the injected value is available only from one injector, their behavior would be the same, however if the same property is provided by two different injectors (say script-binding and valuemap) they might inject different values. Read more here.

Java Annotations in narrow scope

If we have an annotation that is used to set certain Class-specific Constants, declared this way:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Tooltip {
String value();
}
Used like so:
package applicationroot
#Tooltip("createCubeTool.tipText")
public class CreateCubeTool extends EditingTool
{
}
with this in the supertype:
public abstract class EditingTool
{
public String getToolTipText()
{
//Don't worry about this, other than that it requires a custom value Per Concrete class.
return null == tooltip ? null : Translate.text(tooltip.value());
}
}
Where should the annotation be declared?
Leaving aside questions regarding the overall structure of the project, it occurred to me that this particular annotation is only useful in subclasses of the scope of the ModelingTool type. Does it make sense to declare it in an entirely separate package, package applicationroot.tool.annotations; as one contributor suggested, or would it be better declared as a member of the ModelingTool type that uses it?
All references that I have found so far talk about how to declare a custom annotation, but not where they fit into a project's overall structure.
In general, if the text is variable for some reasons, for example it needs to be formatted or transformed before output, declaring it as an instance member maybe the better idea.
On the contrary, a decided CONSTANT can be defined in the meta info of an annotation. Remarkably, you have to use reflection to get the meta info which may degrade performance. The reflection brings a deep call stack.
In this case, I don't think it's worth using annotation. You have little expected benefit from the refactor, except an ostensibly elegant code.

Java, Named Bean, wildcard?

We need to retrieve multiple class-instances during runtime, withoud manually maintaining a list of all available Types.
Possible Approaches:
Retrieve an instance of each type annotated with #xy
Retrieve an instance of each type implementing the interface iXY
Retrieve an instance of each type, named like xy%
Requirements:
Instance should be container managed. (CDI)
If possible, no reflection
What I tried:
Annotations, but it seems that the only way of reading annotations during runtime is reflection. Also this would return me the class-type of which I would need to create instances. (But unmanaged then)
Same for interface implementations.
The perfect way would be to evaluate an el-expression, containing a wildcard:
List<IMyInterface> instances = evaluateExpression("#{commonNameStart*}");
of couse, all the Names could be maintained somewhere in a properties file - but if possible I would like avoid that.
Basically I need something like the Hibernate-Entity-Scanner for custom Annotations.
Is there a nice way to solve this?
This can generally be achieved by injecting the interface javax.enterprise.inject.Instance, appropriately parameterized. At least the two first suggested approaches are possible. Some template pseudo-code is:
#Inject #Foo #Bar private Instance<Xxxx> myVariable;
Explanation of the code above:
Retrieve an instance of each type annotated with #xy: #xy should be a qualifier (see specs, but it is really as simple as follows):
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface XY {
}
In which case the template code would be:
#Inject #XY private Instance<Object> myVariable;
Meaning roughly "get all the CDI beans having the #XY qualifier, disregarding actual type (the <Object>)".
Retrieve an instance of each type implementing the interface iXY: Easier:
public interface XY { ... }
Injection:
#Inject private Instance<XY> myVariable;
Retrieve an instance of each type, named like xy%: This could be possible, I think the implementation would be quite awkward. I will not go into this.
Anyway, Instance is an Iterable of its type parameter (Object in the first case, XY in the second), so in your code you can enumerate the beans matching your criteria as simple as:
for( Object o : myVariable ) {
...
}

Can a Java class which implements an interface inherit the annotations automatically?

Suppose I had an interface with some annotation(s), for example:
#SpecialClass
public interface IFoo { /* ... */ }
And suppose I make a class that implements the interface:
public class Foo implements IFoo { /* ... */ }
Is it possible for class Foo to somehow "inherit" or automatically copy all or some of the annotations from IFoo and its members (e.g. automagically annotate Foo as #SpecialClass, etc.)?
This would be convenient for implementing web service classes (e.g. those generated by the JAX-WS "wsimport" tool) by just implementing their annotated interfaces without explicitly having to copy the interface annotations to the implementing class (e.g. javax.jws.WebService, javax.xml.ws.RequestWrapper, etc).
EDIT: I'm leaving this answer here for general information and future readers, but Andreas pointed out an important bit of the Javadoc which I'd missed:
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
In other words, it wouldn't help in this situation. Also it's only useful if you have control over the annotation itself, of course.
I suspect the real answer is that you simply have to apply the annotation everywhere. If you're worried about forgetting one, you might want to write a unit test which finds all your classes (easier said than done, I realise) and checks that the annotation is present for all classes implementing the given interface.
Have you tried applying the Inherited annotation to the SpecialClass annotation itself?
Indicates that an annotation type is automatically inherited. If an Inherited meta-annotation is present on an annotation type declaration, and the user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class's superclass will automatically be queried for the annotation type. This process will be repeated until an annotation for this type is found, or the top of the class hierarchy (Object) is reached. If no superclass has an annotation for this type, then the query will indicate that the class in question has no such annotation.
That certainly sounds like exactly what you want.

Categories