Monday, 15 April 2013

java - Contextually Binding Two Different Interface Implementations with Google Guice -



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