Reputation: 934
I want to find beans at runtime depending on user input, so using io.quarkus.arc.Arc.
However, I cannot figure out how to get beans with custom annotation in a reasonable way. Only got something working by implementing the annotation interface like:
InstanceHandle<Service> instanceHandleA = Arc.container()
.instance(Service.class, new SupportsJobTypeImpl(JobType.A));
InstanceHandle<Service> instanceHandleB = Arc.container()
.instance(Service.class, new SupportsJobTypeImpl(JobType.B));
class SupportsJobTypeImpl implements SupportsJobType {
JobType requestedJobType;
public SupportsJobTypeImpl(JobType requestedJobType) {
this.requestedJobType = requestedJobType;
}
@Override
public JobType value() {
return requestedJobType;
}
@Override
public Class<? extends Annotation> annotationType() {
return SupportsJobType.class;
}
}
Is there a way to get instanceHandleA, instanceHandleB with less cumbersome verbose code like SupportsJobTypeImpl?
Background info about my test code:
public enum JobType {
A,B
}
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface SupportsJobType {
JobType value();
}
@ApplicationScoped
@SupportsJobType(JobType.A)
public class ServiceForA extends Service {
}
@ApplicationScoped
@SupportsJobType(JobType.B)
public class ServiceForB extends Service {
}
UPDATE: Tried to get it working by including SupportsJobTypeImpl in the SupportsJobType annotation interface (like in the example from https://docs.jboss.org/cdi/api/2.0/javax/enterprise/util/AnnotationLiteral.html):
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface SupportsJobType {
JobType value();
public abstract class Literal extends AnnotationLiteral<SupportsJobType> implements SupportsJobType {
JobType requestedJobType;
public Literal() {
}
@Override
public JobType value() {
return requestedJobType;
}
@Override
public Class<? extends Annotation> annotationType() {
return SupportsJobType.class;
}
}
}
however, I get no bean instance from ArC by:
InstanceHandle<Service> instanceHandleA = Arc.container().instance(Service.class, new SupportsJobType.Literal() {
public JobType value() {
return JobType.A;
}
});
UPDATE2: also not working:
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface SupportsJobType {
JobType value();
class Literal extends AnnotationLiteral<SupportsJobType> implements SupportsJobType {
JobType requestedJobType;
public Literal(JobType requestedJobType) {
this.requestedJobType = requestedJobType;
}
@Override
public JobType value() {
return requestedJobType;
}
@Override
public Class<? extends Annotation> annotationType() {
return SupportsJobType.class;
}
}
}
I get no bean instance from ArC by:
InstanceHandle<Service> instanceHandleA = Arc.container().instance(Service.class, new SupportsJobType.Literal(JobType.A));
Upvotes: 1
Views: 1685
Reputation: 934
Turns out I was stumbling over a small detail like mentioned in https://stackoverflow.com/a/66980506/753724
which means I simply had to add @Unremovable
to beans resulting in:
@ApplicationScoped
@Unremovable
@SupportsJobType(JobType.A)
public class ServiceForA extends Service {
}
@ApplicationScoped
@Unremovable
@SupportsJobType(JobType.B)
public class ServiceForB extends Service {
}
With the slightly adapted Annotation class (only new static method):
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface SupportsJobType {
JobType value();
class Literal extends AnnotationLiteral<SupportsJobType> implements SupportsJobType {
JobType requestedJobType;
public Literal(JobType requestedJobType) {
this.requestedJobType = requestedJobType;
}
public static Literal of(JobType value) {
return new Literal(value);
}
@Override
public JobType value() {
return requestedJobType;
}
@Override
public Class<? extends Annotation> annotationType() {
return SupportsJobType.class;
}
}
}
the beans were found as expected by:
InstanceHandle<Service> instanceHandleA = Arc.container().instance(Service.class, SupportsJobType.Literal.of(JobType.A));
InstanceHandle<Service> instanceHandleB = Arc.container().instance(Service.class, SupportsJobType.Literal.of(JobType.B));
Upvotes: 0
Reputation: 6577
As far as I can tell, what you're doing is exactly what you should do. It is idiomatic for implementations of annotation types to be nested in the annotation type itself, be called Literal
and extend the AnnotationLiteral
class. For example (writing from memory):
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface SupportsJobType {
JobType value();
class Literal extends AnnotationLiteral<SupportsJobType> implements SupportsJobType {
private final JobType value;
public Literal(JobType value) {
this.value = value;
}
@Override
public JobType value() {
return value;
}
}
}
Upvotes: 2