java - Contextually Binding Two Different Interface Implementations with Google Guice -
let's pretend have interface called ivalidator
looks following:
public interface ivalidator { /** * returns true if specified strings valid. */ public boolean validate(list<string> somestrings); }
now let's have 2 implementations of ivalidator
:
public class strictvalidator implements ivalidator { public boolean validate(list<string> somestrings) { //some strict validation code homecoming false; } } public class laissezfairevalidator implements ivalidator { public boolean validate(list<string> somestrings) { //some easy-going validation code homecoming true; } }
now let's add together servlet uses 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 strings validate out of request object list<string> strings = (list<string>) restutil.parserequest(request, list.class); //validate request if (!this.validator.validate(strings)) { homecoming reply.saying().status(409); } else { homecoming reply.saying().nocontent(); } } }
of course of study we'll need bind ivalidator
strictvalidator
in module:
public class validatormodule implements module { @override protected void configure() { bind(ivaliator.class).to(strictvalidator.class); } }
but happens if want conditionally bind ivalidator
strictvalidator
in 1 case, instead bind laissezfairevalidator
in other case?
did notice @laissezfaire
annotation on myservlet.validate
above? that's interceptor looks 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)) { homecoming reply.saying().status(409); } else { homecoming reply.saying().nocontent(); } } else { homecoming invocation.proceed(); } } }
and 1 time 1 time again need bindings set 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 validatormodule
, laissezfaireinterceptor
class instance of strictvalidator
when interceptormodule
calls requestinjection(lfinterceptor);
.
instead, i'd myservlet
instance of strictvalidator
, laissezfaireinterceptor
instance of laissezfairevalidator
.
according the google guice docs, utilize named annotation when request injection. constructor of myservlet
modified following:
@inject public myservlet(@named("strict") final ivalidator validator) { this.validator = validator; }
and setvalidator
method of laissezfaireinterceptor
modified following:
@inject public void setvalidator(@named("laissezfaire") final ivalidator validator) { this.validator = validator; }
and validatormodule
modified 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 , except docs avoid approach because string names can't checked compiler. in addition, means have add together @named
annotation every place in code requests ivalidator
injection, or else binding fail.
i had hoped provider bindings solve problem me, don't appear know context in binding beingness made. since don't know type of class requesting binding, can't take type of ivalidator
homecoming get()
method.
is there improve way approach problem?
while condit supplied first-class suggestions, opted solve problem more straightforward solution.
as above, created ivalidator
interface, strictvalidator
, laissezfairevalidator
classes. used validatormodule
bind ivalidator
strictvalidator
in default case. reminder, looks this:
public class validatormodule implements module { @override protected void configure() { //in default case, inject instance of strictvalidator bind(ivaliator.class).to(strictvalidator.class); } }
in vast bulk of cases, strictvalidator
required implementation, laissezfaireinterceptor
cheat used testing.
wherever wanted strictvalidator
(like in myservlet
), injected 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 wanted instance of laissezfairevalidator
, asked concrete implementation injected in place of ivalidator
:
public class laissezfaireinterceptor implements methodinterceptor { private final ivalidator validator; //... bunch of other code goes here (see above) ... @inject public void setvalidator(final laissezfairevalidator validator) { this.validator = validator; } //... , bunch more code goes here (again, see above) ... }
in way, able conditionally inject required implementation based on context of injection without introducing annotations or factories.
sure, it's not guicy be, works.
java servlets guice
No comments:
Post a Comment