I have an interface with a naive implementation, say
interface MyService {
void doIt();
}
class MyServicePlain implements MyService{
#Inject
SomeOtherInterface
public void doIt () {
}
}
I want to make a cache that caches the doIt, so I wrote a wrapper :
class CachingMyService implements MyService {
#Inject
MyService inner;
int cacheThingie;
public int doIt() {
if (cached) ... {
return cacheThingie;
}
else {
result = inner.doIt();
addToCache(result);
return result;
}
}
}
Then, I add both implementations to my Binder:
public class ApplicationBinder extends AbstractBinder {
protected void configure() {
this.bind(MyServicePlain.class).to(MyService.class).in(Singleton.class).ranked(2);
this.bind(CachingMyService.class).to(MyService.class).in(Singleton.class).ranked(2);
}
}
I get errors complaining about:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no
object available for injection at
SystemInjecteeImpl(requiredType=MyService,parent=CachingMyService},position=-1,optional=false,self=false,unqualified=null,1102650897)
I trief using Qualitifaction like this:
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface NonCached {
}
#NonCached
class MyServicePlain implements MyService{
}
And using that:
class CachingMyService implements MyService {
#Inject #NonCached
MyService inner;
But that does not work either.
What is the proper way to wrap a caching service like this? And how can I make hk2 choose the proper implementations?
You need to use the qualifiedBy(Annotation) method when you want to qualify different types. You also need to annotate each injection point with a different qualifier annotation.
First you need the annotations and have a way to get an instance of them (the qualifiedBy method requires an annotation instance)
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface NonCached {
class Literal extends AnnotationLiteral<NonCached> implements NonCached {
public static final NonCached INSTANCE = new Literal();
private Literal() {
}
}
}
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface Cached {
class Literal extends AnnotationLiteral<Cached> implements Cached {
public static final Cached INSTANCE = new Literal();
private Literal() {
}
}
}
Then when you bind them used qualifiedBy
this.bind(MyServicePlain.class).to(MyService.class)
.in(Singleton.class).qualifiedBy(NonCached.Literal.INSTANCE);
this.bind(CachingMyService.class).to(MyService.class)
.in(Singleton.class).qualifiedBy(Cached.Literal.INSTANCE);
Then when you inject them, add the applicable qualifier
#Inject
#NonCached
MyService service;
#Inject
#Cached
MyService service;
Related
Having the following class structure:
public abstract class A {
String someProperty = "property"
public abstract void doSomething();
}
#Service
public class Aa extends A {
#Override
public abstract void doSomething() {
System.out.println("I did");
}
}
#Service
public class Ab extends A {
#Override
public abstract void doSomething() {
System.out.println("I did something else");
}
}
I need a way to tell Spring which A concrete class to Autowire in my Foo service, based on a property in a properties file.
#Service
public class Foo {
#Autowire
private A assignMeAConcreteClass;
}
And in my properties file I have this:
should-Aa-be-used: {true, false}
Remove the #Service annotation, instead write a #Bean-annotated method in a configuration class that reads the properties, and returns the appropriate A instance.
Not a new way but in your case I think that a possible suitable way would be to use
FactoryBean in the class that wants to inject the bean conditionally.
The idea is simple : you implement FactoryBean by parameterizing it with the interface of the bean that you want to inject and override getObject() to inject the wished implementation :
public class FactoryBeanA implements FactoryBean<A> {
#Autowired
private ApplicationContext applicationContext;
#Value("${should-Aa-be-used}")
private boolean shouldBeUsed;
#Override
public A getObject() {
if (shouldBeUsed) {
return applicationContext.getBean(Aa.class));
return applicationContext.getBean(Ab.class));
}
}
But FactoryBean instances are not classic beans. You have to configure it specifically.
You could configure it in a Spring Java configuration in this way :
#Configuration
public class FactoryBeanAConfiguration{
#Bean(name = "factoryBeanA")
public FactoryBeanA factoryBeanA() {
return new FactoryBeanA();
}
#Bean
public beanA() throws Exception {
return factoryBeanA().getObject();
}
}
I have a class with 2 static nested classes that do the same operation on 2 different generic types.
I exposed the 2 classes as beans and added #Autowired for the constructors as I usually do.
Here is the basic setup
abstract class <T> Parent implements MyInterface<T> {
private final Service service;
Parent(Service service){ this.service = service; }
#Override public final void doInterfaceThing(T thing){
T correctedT = map(thing);
service.doTheThing(correctedT);
}
protected abstract T map(T t);
#Service
public static class ImplA extends Parent<A> {
#Autowired ImplA (Service service){ super(service); }
A map(A a){ //map a }
}
#Service
public static class ImplB extends Parent<B> {
#Autowired ImplB (Service service){ super(service); }
B map(B b){ //map b }
}
}
And in another class I have
#Service
public class Doer {
private final List<MyInterface<A>> aImpls;
#Autowired public Doer(List<MyInterface<A>> aImpls){ this.aImpls = aImpls; }
public void doImportantThingWithA(A a){
aImpls.get(0).doInterfaceThing(a);
}
}
When I run the app, everything appears to be injected correctly and when I put a breakpoint in the ImplA and ImplB constructors, I have a not-null value for "service". I also have an ImplA bean in the aImpls list in Doer.
When I call doImportantThingWithA(a) however, "service" is null inside ImplA and I obviously die.
I'm not sure how this is possible because:
I see a nonnull value in my constructors for service which is a final field.
If spring is injecting ImplA and ImplB into another class, it should already have either injected a Service into ImplA or ImplB, or thrown an exception on bean initialization. I have nothing set to lazily load and all bean dependencies are required.
The reason for the nested classes is because the only thing that changes between the 2 implementations is the map() function. Trying to avoid extra classes for 1 line of varying code.
More info:
When I add a breakpoint in Parent.doInterfaceThing(), if I add a watch on "service" I get null as the value. If I add a getService() method, and then call getService() instead of referring directly to this.service, I get the correct bean for service. I don't know the implications of this but something seems weird with the proxying.
It looks like what is causing the issue is Parent.doInterfaceThing();
If I remove final from the method signature, "service" field is correctly populated and the code works as expected.
I don't understand at all why changing a method signature affects the injected value of final fields in my class... but it works now.
What I meant with my "use mappers" comment was something like this:
class MyInterfaceImpl implements MyInterface {
#Autowired
private final Service service;
#Override public final <T> void doInterfaceThing(T thing, UnaryOperator<T> mapper){
T correctedT = mapper.apply(thing);
service.doTheThing(correctedT);
}
// new interface to allow autowiring despite type erasure
public interface MapperA extends UnaryOperator<A> {
public A map(A toMap);
default A apply(A a){ map(a); }
}
#Component
static class AMapper implements MapperA {
public A map(A a) { // ... }
}
public interface MapperB extends UnaryOperator<B> {
public B map(B toMap);
default B apply(B b){ map(b); }
}
#Component
static class BMapper implements MapperB {
public B map(B a) { // ... }
}
}
This does have a few more lines than the original, but not much; however, you do have a better Separation of Concern. I do wonder how autowiring works in your code with the generics, it does look as if that might cause problems.
Your client would look like this:
#Service
public class Doer {
private final List<MapperA> aMappers;
private final MyInterface myInterface;
#Autowired public Doer(MyInterface if, List<MapperA> mappers){
this.myInterface = if;
this.aImpls = mappers; }
public void doImportantThingWithA(A a){
aMappers.stream().map(m -> m.map(a)).forEach(myInterface::doInterfaceThing);
}
}
I am trying to inject a custom annotation using the Guice bindInterceptor into my currently instantiated Service.java class. Unfortunately when I call myMethod() the OnAnnotationEvent::invoke method is not called. How can I use Guice to call OnAnnotationEvent::invoke when the #OnAnnotation annotation tag is used on a method in the current class?
My code looks like this:
Service.java
//Instantiated by another service
public class Service extends AbstractVerticle {
private DataAccess dataAccess;
#Inject
public void setDataAccess(DataAccess dataAccess){
this.dataAccess = dataAccess;
}
#Override
public void start() throws Exception {
Guice.createInjector(new DataAccessModule()).injectMembers(this);
myMethod();
}
#MyAnnotation
public void myMethod() {
dataAccess.doStuff();
}
}
DataAccessModule.java
public class DataAccessModule extends AbstractModule {
#Override
protected void configure() {
OnAnnotationEvent onAnnotationEvent = new OnAnnotationEvent();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyAnnotation.class), onAnnotationEvent);
bind(DataAcess.class).to(DataAccessImpl.class);
}
}
OnAnnotationEvent
public class OnAnnotationEvent implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Annotation called on: " + invocation.getMethod().getName();
return invocation.proceed();
}
}
MyAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {}
I think that your problem is that you creating new injector that does not knows anything about your class. If you just need injector in your class - use #Inject private Injector injector;. If you need to load some aditional modules locally you just need to create child injector :
#Inject private baseInjector;
...
injector = baseInjector.createChildInjector(new Module1(),new Moddule2());
This doesn't work because your Service instance isn't managed by Guice. To make it work you must either create Service with Guice or annotate method doStuff in DataAccessImpl with MyAnnotation.
Because I have some generics which need to be passed to the newly produced object, I am creating a producer. But while producer works, the EntityManager is not injected because producer creates an instance with operator new instead of using CDI.
How can I produce an object with CDI support?
The code:
Qualifier:
#Qualifier
#Retention(RUNTIME)
#Target(
{ FIELD, TYPE, METHOD })
public #interface Multiselector
{
Class<? extends Dbo> clazz();
}
Producer:
#SessionScoped
public class MultiselectorProducer implements Serializable
{
#Produces
#Multiselector(clazz = SpecialDbo.class)
public MultiselectorService<SpecialDbo> produce()
{
return new MultiselectorService<SpecialDbo>(SpecialDbo.class);
}
}
Service class:
#Stateful
#LocalBean
public class MultiselectorService<T extends Dbo> implements Serializable
{
#Inject
private EntityManager em;
private List<T> itemList;
public MultiselectorService()
{
}
public MultiselectorService(Class<? extends Dbo> clazz)
{
itemList = em.createQuery("some Sql String", clazz);
}
....
}
NOTE: The EntityManager is a custom crud service which is otherwise injected correctly
Any improvement suggestions over the code are welcome. Thanks!
You have mixed a lot of unrelated things:
Your service MultiselectorService is an EJB, and you cannot produce it with a producer. EJB is registered once application is created and then depending on the scope it creates instances.
You have a method public void MultiselectorService(Class<? extends Dbo> clazz) with the name similar to constructor, it against convention.
Assume that you have fixed that method to be a constructor, but then line 'itemList = em.createQuery("some Sql String", clazz);' will fail with NPE. Because em will be initialized only after bean creation. there are two ways to do it:
Inject entity manager into constructor (this is against EJB spec, if you will still use EJB)
Execute initialization operation in method with annotation '#PostConstruct'
Do you have a producer for EntityManager ? e.g. you cannot just inject entity manager, you need to provide as a resource for EJB, with annotation #PersistenceContext
I understand what you try to achieve. The main problem is that manually created beans are not managed by container, this means that interceptors and decorators won't apply (e.g. PostConstruct and Transactional annotation will not work). Check here. So far the best way to achieve this is:
public interface SpecialDboMultiselectorService extends MultiselectorService {
}
#Stateless
public class SpecialDboMultiselectorServiceImpl extends MultiselectorServiceImpl<SpecialDbo> implements SpecialDboMultiselectorService
{
public SpecialDboMultiselectorServiceImpl() {
super(SpecialDbo.class);
}
}
public class MultiselectorServiceImpl<T extends Dbo> implements MultiselectorService {
#Inject
private EntityManager em;
private Class<? extends Dbo> clazz;
private List<T> itemList;
public MultiselectorService(Class<? extends Dbo> clazz) {
this.clazz = clazz
}
#PostConstruct
public void init() {
itemList = em.createQuery("some Sql String", clazz);
}
}
and inject SpecialDboMultiselectorService.
Let's pretend that I have an interface called IValidator that looks like the following:
public interface IValidator {
/**
* Returns true if the specified strings are valid.
*/
public boolean validate(List<String> someStrings);
}
Now let's say that I have two implementations of IValidator:
public class StrictValidator implements IValidator {
public boolean validate(List<String> someStrings) {
//some strict validation code
return false;
}
}
public class LaissezFaireValidator implements IValidator {
public boolean validate(List<String> someStrings) {
//some easy-going validation code
return true;
}
}
Now let's add a servlet that uses an injected instance of IValidator:
#Service
#At("/rest")
public class MyServlet extends AbstractServlet {
private final IValidator validator;
#Inject
public MyServlet(final IValidator validator) {
this.validator = validator;
}
#Post
#At("/validate")
#LaissezFaire
public Reply<?> validate(Request request) {
//get the strings to validate out of the request object
List<String> strings = (List<String>) restUtil.parseRequest(request, List.class);
//validate the request
if (!this.validator.validate(strings)) {
return Reply.saying().status(409);
} else {
return Reply.saying().noContent();
}
}
}
Of course we'll also need to bind IValidator to StrictValidator in a module:
public class ValidatorModule implements Module {
#Override
protected void configure() {
bind(IValiator.class).to(StrictValidator.class);
}
}
But what happens if I want to conditionally bind IValidator to StrictValidator in one case, but instead bind it to LaissezFaireValidator in some other case?
Did you notice the #LaissezFaire annotation on MyServlet.validate above? That's an interceptor that looks like this:
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface LaissezFaire { }
public class LaissezFaireInterceptor implements MethodInterceptor {
private boolean debug;
private IValidator validator;
#Inject
public void setDebug(#Named("debug.enabled") boolean debugEnabled) {
this.debug = debugEnabled;
}
#Inject
public void setValidator(final IValidator validator) {
this.validator = validator;
}
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if (debug) {
if (!this.validator.validate(strings)) {
return Reply.saying().status(409);
} else {
return Reply.saying().noContent();
}
} else {
return invocation.proceed();
}
}
}
And once again we need some bindings to set up the interceptor:
public class InterceptorModule implements Module {
#Override
protected void configure() {
final MethodInterceptor lfInterceptor = new LaissezFaireInterceptor();
requestInjection(lfInterceptor);
bindInterceptor(Matchers.subclassesOf(AbstractServlet.class), Matchers.AnnotatedWith(LaissezFaire.class), lfInterceptor);
}
}
According to the ValidatorModule, the LaissezFaireInterceptor class will get an instance of StrictValidator when InterceptorModule calls requestInjection(lfInterceptor);.
Instead, I'd like MyServlet to get an instance of StrictValidator and LaissezFaireInterceptor to get an instance of LaissezFaireValidator.
According to the Google Guice docs, I could use a named annotation when I request injection. The constructor of MyServlet would be modified to look like the following:
#Inject
public MyServlet(#Named("strict") final IValidator validator) {
this.validator = validator;
}
and the setValidator method of LaissezFaireInterceptor would be modified to look like the following:
#Inject
public void setValidator(#Named("laissezfaire") final IValidator validator) {
this.validator = validator;
}
and finally ValidatorModule would be modified to look like the following:
public class ValidatorModule implements Module {
#Override
protected void configure() {
bind(IValiator.class).annotatedWith(Names.named("strict")).to(StrictValidator.class);
bind(IValidator.class).annotatedWith(Names.named("laissezfaire")).to(LaissezFaireValidator.class);
}
}
This is all well and good except that the docs specifically say to avoid this approach because the string names can't be checked by the compiler. In addition, it means that I have to add an #Named annotation to every place in the code that requests an IValidator by injection, or else the binding will fail.
I had really hoped that Provider Bindings could solve this problem for me, but they don't appear to know anything about the context in which the binding is being made. Since they don't know the type of the class that is requesting the binding, I can't choose which type of IValidator to return from the get() method.
Is there a better way to approach this problem?
While Condit supplied some excellent suggestions, we opted to solve this problem with a more straightforward solution.
As above, we created the IValidator interface, as well as the StrictValidator and LaissezFaireValidator classes. We used the ValidatorModule to bind IValidator to StrictValidator in the default case. As a reminder, it looks like this:
public class ValidatorModule implements Module {
#Override
protected void configure() {
//in the default case, inject an instance of StrictValidator
bind(IValiator.class).to(StrictValidator.class);
}
}
In the vast majority of cases, StrictValidator is the required implementation, as the LaissezFaireInterceptor is a cheat that is used for testing.
Wherever we wanted a StrictValidator (like we do in MyServlet), we injected an instance of IValidator:
public class MyServlet extends AbstractServlet {
private final IValidator validator;
#Inject
public MyServlet(final IValidator validator) {
this.validator = validator;
}
//... there's more code here (look above) ...
}
And wherever we wanted an instance of LaissezFaireValidator, we asked for its concrete implementation to be injected in place of IValidator:
public class LaissezFaireInterceptor implements MethodInterceptor {
private final IValidator validator;
//... a bunch of other code goes here (see above) ...
#Inject
public void setValidator(final LaissezFaireValidator validator) {
this.validator = validator;
}
//... and a bunch more code goes here (again, see above) ...
}
In this way, we were able to conditionally inject the required implementation based on the context of the injection without introducing any extra annotations or factories.
Sure, it's not as Guicy as it could be, but it works.