Guice provides two variations of so-called binding annotations, which seem to really break down to class- and instance-level annotations:
"Class-level":
bind(Service.class).annotatedWith(Red.class).to(RedServiceImpl.class);
#Red
public class SomeService implements Service { ... }
Service redSvc = injector.getInstance(SomeService.class);
"Instance-level":
bind(Service.class).annotatedWith(Names.named("Blue").to(BlueServiceImpl.class);
#Blue blueSvc = injector.getInstance(Service.class);
When is one method preferential over the other? It seems that class-level annotations are more absolute/inflexible than instance-level. Pros/cons/caveats/pitfalls of either method?
I'm not sure I understand your question. Your use of binding annotations is irregular. You wouldn't typically annotate a local variable or a class, but rather fields and parameters.
Your first code example will cause the injector to return SomeService, but not because of your annotation or your binding, but because SomeService is a concrete implementation. Had you asked for this instead:
Service redSvc = injector.getInstance(Service.class);
You will get an error:
1) No implementation for com.example.Service was bound.
while locating com.example.Service
Your second example is also incorrect. If you use Names to define a binding, you must use #Named to access that binding. Using #Blue would cause a compiler error. The correct usage would be #Named(value="Blue").
The common best practice for a binding annotation is this:
#BindingAnnotation
#Target({ FIELD, PARAMETER, METHOD })
#Retention(RUNTIME)
public #interface MyAnno
In that case, both of these would be compile errors:
#Red // not allowed
public class SomeService implements Service { ... }
#Blue // not allowed
blueSvc = injector.getInstance(Service.class);
The only real difference is that in one case you bind for a whole annotation, and in the other case you bind to an annotation with specific arguments. Not all annotations even take arguments, in which case, binding with the annotation class is perfectly normal.
Related
Suppose I have a class that looks like this:
public class MyClass {
#Inject
public MyClass(#Foo("whatever") Bar dependency) {
// ...
}
}
And I wanted to have some custom logic that can see we're injecting an object of type Bar with an annotation of type #Foo("whatever") and construct a corresponding Bar object...something like a Guice Provider, but that gets more context information about the injection site. Does Guice let me do something like that?
What you're describing isn't possible through normal Guice: Providers are intended to be zero-argument pure functions and there's no way to plumb the injection site information into them as you would a flexible callback function.
You can approximate what you want, though, two different ways:
If you know every single possible value of #Foo's parameter, you can make your #Foo a binding annotation and bind it by providing a Annotation-compatible equals and hashCode. This provides the most intuitive experience: You can do anything with your #Foo you can do with any other type, such as using #Foo in constructors or injecting #Foo("value") Provider<Bar> barProvider.
#Override public void configure() {
for (String value : PREDEFINED_VALUES) {
bind(Bar.class)
.annotatedWith(new FooImpl(value))
.toProvider(new BarProvider(value));
}
}
If you want #Foo to work for arbitrary parameters, you'll need to extend Guice with custom injections. This won't work for constructor injection or alongside any other #Inject annotations, but it will allow you to inspect types after Guice injection is finished to augment them as you see fit (e.g. detecting and reacting to #Foo annotations on fields).
See the example in the Guice docs for more information there.
Internally, Guice's core is effectively a Map<Key, Provider>, where a Key represents a pair of a possibly-parameterized type and an optional binding annotation. The former binding annotation trick works because Guice can map your injection request to a Provider all on its own, where the latter skips Guice's map so you can inspect/construct/inject instances all on your own.
If you're willing to skip the annotation part of your solution, you could inject a BarProvider or BarFactory that exposes a forFoo(String) method, which would give you consistent injection without knowing all your String values ahead of time. This would allow you to use assisted injection or AutoFactory to generate your factory (if you want to generate one instance per call), or let you write a straightforward factory yourself for added flexibility.
public class MyClass {
private final Bar dependency;
#Inject
public MyClass(BarProvider barProvider) {
dependency = barProvider.forFoo("whatever");
// ...
}
}
In Weld, I can do the following to get dynamically inject config values from some source:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ TYPE, METHOD, FIELD, PARAMETER })
public static #interface ConfigValue {
#Nonbinding
String value();
}
#Produces
#Dependent
#ConfigValue("")
public String stringValue(InjectionPoint ip) {
ConfigValue configValue = ip.getAnnotated().getAnnotation(ConfigValue.class);
return myConfigMap.get(configValue.value());
}
The equivalent Spring, however, matches based on the value of the #ConfigValue annotation.
I would like Spring to call a method to allow me to inject custom values for all fields annotated with #ConfigValue.
I'm aware of this: http://joshlong.com/jl/blogPost/supporting_your_own_field_or_method_injection_annotation_processors_in_spring.html
However that's a very complex solution for a seemingly simple problem. I'm wondering if there's a simpler solution...
Spring has InjectionPoint class. The catch is that your #ConfigValue annotation should not have Qualifier annotation. Then you can have a single method to produces various values.
However, if you choose to have #Qualifier on your #ConfigValue annotation, then you will have to have multiple producing methods one for each value of #ConfigValue. I dont seem to have come across anything equivalent to #Nonbinding though.
I have tested this for user object, not String.
PS: another approach is to have one "defining" annotation and one "non-defining" annotation on the injection point to serve your need.
I have defined an annotation for validation like this:
#Documented
#Constraint(validatedBy = MyValidator.class)
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomValid {
//required methods
}
Now, I want to decide the "validatedBy" class at runtime. Like I have a field in my class:
public class MyClass {
#MyCustomValid
MyObject myObject;
}
How do I pass the ConstraintValidator class at runtime. I have different implementations for different cases.
Annotations are compiled into the code at compile time and they can't change, so you need a hack.
Create a validation class which delegates to another validator. The delegate needs to be created at runtime, using whatever algorithm you design. Note that the code might be used concurrently, so you need a thread-safe initialization.
I have a annotation that does include several other annotations, pretty much like this one here:
#Component // Spring Component
#Interface OsgiService { boolean isFactory() }
meaning that all classes annotated with #OsgiService shall automatically also be annotated as #Component. Which works fine.
Now however, I'd like to add another annotation, that has a parameter which is dependent of the isFactory parameter of #OsgiService.
#Component // Spring Component
#Scope(isFactory() ? "prototype" : "singleton")
#Interface OsgiService { boolean isFactory() }
Which does not work. However, as isFactory property of an annotation requires to be a static value, shouldn't it be possible to have something like this?
I don't think this is possible.
You can create two annotations: #OsgiService and #OsgiServiceFactory
This is regarding use of annotations in Java. I associated an annotation with a method while declaring it in the interface. While implementing, how can I ensure that the annotation is carried along with #Override annotation and if not, it should throw a compilation error?
Thanks.
You can't enforce this in the compiler, no. It is the job of the tools which use those annotations to check all superclasses and interfaces when looking for annotations on a given class.
For example, Spring's AnnotationsUtils takes a class to examine for annotations, and crawls all over its inheritence tree looking for them, because the compiler and JVM does not do this for you.
You can't.
You need to write some code to do this (either on your applciation load time, or using apt)
I had the same scenario, and created an annotation of my own:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.ANNOTATION_TYPE)
public #interface DependsOn {
Class<? extends Annotation>[] value();
/**
* Specifies whether all dependencies are required (default),
* or any one of them suffices
*/
boolean all() default true;
}
and applied it to other annotations, like:
#Retention(value = RetentionPolicy.RUNTIME)
#Target(value = ElementType.TYPE)
#DependsOn(value={Override.class})
public #interface CustomAnnotation {
}
Imporant: have in mind that #Override has a compile-time (SOURCE) retention policy, i.e. it isn't available at run-time.