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.
Related
I have an interface IInterface.java like below:
public interface IInterface {
void printIt();
}
And there are two implementation classes for this: ImplementationA.java and ImplementationB.java
#Component
public class ImplementationA implements IInterface {
#Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
#Component
public class ImplementationB implements IInterface {
#Override
public void printIt() {
System.out.println("Inside ImplementationB");
}
}
Now I have a listener class, which has this IInterface as a member:
#Component
#AllArgsConstructor
public class Listener {
IInterface iInterface;
public void doStuff(){
iInterface.printIt();
}
}
Now, my requirement is to inject either of ImplementationA.java or ImplementationB.java in the iInterface member of Listener.java based on certain condition.
After some research I started using the #Conditional annotation.
I added two classes ConditionA.java and ConditionB.java:
public class ConditionA implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
public class ConditionB implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
And I also changed my implementation classes as below(added the Conditional annotation):
#Component
#Conditional(ConditionA.class)
public class ImplementationA implements IInterface {
#Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
#Component
#Conditional(ConditionB.class)
public class ImplementationB implements IInterface {
#Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
This seems to work like a charm for me. Whichever implementation class I need to inject I just return true from its corresponding Condition class and return false from rest of the implementation class's Condition class.
However this next part is where I am facing the challenge:
So from the above solution, I was hardcoding the return true or return false from the matches method of the corresponding Condition class. What if I need to return a dynamic value based on another component.
Lets say I have a spring Component class MyCustomConfig which has a member customFlag and if this member is set to true, we need to inject ImplementationA.class.
I had tried the below(made the class #Component and also autowired MyCustomConfig):
#Component
public class ConditionA implements Condition {
#Autowired
MyCustomConfig myCustomConfig;
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return myCustomConfig.getCustomFlag();
}
}
However this simply does not work. myCustomConfig is not autowired and I get a null pointer exception.
Could someone please help me with this.
I think there is no chance for what you need with the use of implements Condition.
If you inspect the documentation for interface Condition which is what the class that you provide to #Conditional should do, in your case ConditionA and ConditionB it says:
Conditions must follow the same restrictions as
BeanFactoryPostProcessor and take care to never interact with bean
instances. For more fine-grained control of conditions that interact
with #Configuration beans consider implementing the
ConfigurationCondition interface.
Maybe this answer would provide a workaround for you as it mentioned above in documentation that in the case that you want to interfere with other beans you should implement your own custom ConfigurationCondition.
Just check that the phase where this ConfigurationCondition will run will be after the beans that you need are registered
I would register the bean using a configuration class and a #Bean as follows:
#Configuration
public class ImplementationConfig {
#Bean
public IInterface implementation(MyCustomConfig myCustomConfig) {
if (myCustomConfig.getCustomFlag()) {
return new ImplementationA();
} else {
return new ImplementationB();
}
}
}
You simply drop the Spring-related annotations in both ImplementationA and ImplementationB:
public class ImplementationA implements IInterface {
#Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
public class ImplementationB implements IInterface {
#Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
And finally, you can drop the Condition classes.
Check this link https://stackoverflow.com/a/70351394/7237884 here.
The docs say
Conditions must follow the same restrictions as BeanFactoryPostProcessor and take care to never interact with bean instances. For more fine-grained control of conditions that interact with #Configuration beans consider implementing the ConfigurationCondition interface.
Currently I have the following setup (to keep it small I did not post all annotations):
public class MessageRestService {
private MessageService messageService;
MessageRestService(MessageService messageService) {
this.messageService = messageService;
}
#GetMapping
public Response getAllMessages() {
return messageService.getAllMessages();
}
}
public interface MessageService {
String getAllMessages();
}
public class MessageServiceImpl implements MessageService {
#Override
public String getAllMessages() {
...
return messageDao.getAllMessages();
}
}
Now I'm trying to add a decorator class to this implementation, where before the call additional things can be done (e.g. access check or logging,...).
Therefore I tried to create a decorator class which can do f.ex. logging, before the actual implementation gets called.
#Singleton
public class MessageDecorator implements MessageService {
#Inject
private final MessageService messageService;
#Override
public String getAllMessages() {
// here we can log
return messageService.getAllMessages();
}
}
The project is compiling without problems, but calling the getAllMessages() method, the decorator does not get called, the process (works) as before, but without logging anything.
I'm honestly stuck, I have seen once a working example of this, but I do not remember exactly anymore what was different to my approach or where I did a mistake / forgot to change something.
all
I have some questions regarding Google Guice. Any help is appreciated.
I have a handler interface and an implementation of it.
public interface Handler {
void handle();
}
public class HandlerImpl implements Handler {
private Filter filterOne;
#Override
void handler() {
filterOne.foo();
}
}
Filter is another interface:
public interface Filter {
void foo();
}
There are multiple implementation of it.
public class FilterOne implements Filter {
void foo() {
}
}
public class FilterTwo implements Filter {
void foo() {
}
}
Then in my Guice module:
public class HandlerModule extends AbstractModel {
#Override
protected void configure() {
bind(Handler.class).to(HandlerImpl.class);
}
#Provides
#Singleton
public Handler provideHandler(#Named("filterOne")filter filterOne) {
return new HandlerImpl(filterOne);
}
#Provides
#Singleton
#Named("filterOne")
public Filter provideFilterOne() {
return new FilterOne();
}
#Provides
#Singleton
#Named("filterTwo")
public Filter provideFilterTwo() {
return new FilterTwo();
}
}
With above implementation, I'm always getting the error - Could not find a suitable constructor in HandlerImpl. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
I'm using #Named to differ two filters. Am I using it wrong?
Is it because I have two implementations of Filter and the Guice cannot tell which one to use when try to provide the HandlerImpl?
You are binding Handler.class twice:
In configure() method: bind(Handler.class).to(HandlerImpl.class);
As a provider:
#Singleton
public Handler provideHandler(#Named("filterOne")filter filterOne) {
return new HandlerImpl(filterOne);
}
The first of these bindings can't work, since HandlerImpl doesn't have a constructor annotated with #Inject. If you fix it though, it still won't work - you can't provide multiple bindings for the same key.
TL;DR: remove the bind(Handler.class).to(HandlerImpl.class); from the configure() method
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 have a class
EntiyFacadeImpl.java
#Stateless
public class EntityFacadeImpl implements EntityFacade {
#EJB
ICustomerBean customerBean;
public void printCustomer(Customer c) {
customerBean.printCustomer(c);
customerBean.additionalFieldsHandler(c.getAdditionalFields().toString());
}
}
Where ICustomerBean is #Local interface and have two implementation classes CustomerBean.java and CustomerBeanExt.java where later one extends CustomerBean.java
#Stateless(name = "CustomerBean")
public class CustomerBean implements ICustomerBean {
public void printCustomer(Customer customer) {
System.out.println(customer);
}
public void additionalFieldsHandler(String additionalFields) {
// an empty implemetation here
}
}
#Stateless(name = "CustomerExtBean")
public class CustomerExtBean extends CustomerBean implements ICustomerBean {
#Override
public void additionalFieldsHandler(String additionalFields) {
// some custom implemetation
System.out.println("Additional Fields: "+additionalFields);
}
}
ICustomer interface looks like this
#Local
public interface ICustomerBean {
public void printCustomer(Customer c);
public void additionalFieldsHandler(String additionalFields);
}
My aim is that whenever I inject my EntityFacade (interface for EntityFacadeImpl) in SimpleRESTPojo.java only, I want CustomerExtBean to be inject in it, while when any other class injects it I want CustomerBean to be injected
#Path("/pojo")
public class SimpleRESTPojo {
#EJB
private EntityFacade entityFacade;
}
My app's entry point is EntityFacade only. Is there a way to achieve this?
Actually, after reading your question, it looks like you're trying to introduce tight coupling. CDI doesn't make EntityFacade aware of where it was injected in to. I don't see a way to do this.
What you could do is create an extended version of EntityFacade that used this injection point:
#Inject
#Extended //or whatever qualifier you come up with
private ICustomerBean customerBean;
and then use that same qualifier on the extended EntityFacade.