I just learned something useful by trying a concrete example. I invoked:
System.out.println("uri=" +
UriBuilder.fromUri(uriInfo.getBaseUri()).path(getClass()).build());
and this exception is thrown:
java.lang.IllegalArgumentException: The class, class
adcaster.server.resources.TerminalsResource$$EnhancerByGuice$$13b1709e is
not annotated with @Path
at
com.sun.jersey.api.uri.UriBuilderImpl.path(UriBuilderImpl.java:217)
at
adcaster.server.resources.TerminalsResource.listTerminals(TerminalsResource.java:73)
Here are my assumptions:
1) For proxy by encapsulation, you need a method to return the unproxied
object: "Object getInjectableObject(Object proxy)". You can look up Jersey
annotations and inject fields directly into this object.
2) For proxy by extension, you need a method to return the class being
proxied: "Class<?> getInjectableClass(Class<?> proxy)". You must look up
Jersey annotations on that class (not the proxy) and inject fields into the
proxy object.
So here are my updated recommendations...
- Have IoC framework implement the following methods:
/**
* Returns the object that fields should be injected into.
*
* @param o the object returned by getInstance()
* @return the object that fields should be injected into
*/
public Object getInjectableObject(Object o);
/**
* Returns the class to search for Jersey annotations.
*
* @param c a class passed to Jersey (may be a proxy)
* @return the class to search for Jersey annotations
*/
public Class<?> getInjectableClass(Class<?> c);
- Then have UriBuilderImpl invoke getInjectableClass()
- There seems to be a typo in the exception message "class, class".
What do you think?
Gili
Gili wrote:
>
>
> Paul Sandoz wrote:
>>
>> The important point here is that the returned instance can be injected
>> on by Jersey correctly. That is why the method is called
>> getInjectableInstance. The single use-case that has been driving this
>> so far has been Spring-AOP, where proxy by encapsulation can occur
>> rather than proxy by extension (see snippet of Spring-based code at
>> end of email).
>>
>> Given an instance of Foo and an instance of Foo$$EnhancerByGuice$
>> $45c70c66 are the fields on the class Foo accessible and can those
>> fields be modified when given an instance of Foo$$EnhancerByGuice$
>> $45c70c66. If so then getInjectableInstance can just return the
>> instance that is passed in.
>>
>
> Unfortunately this won't work. I just fired up the debugger against Guice
> proxies and it seems I was right the first time around. Guice is using
> CGLIB to construct proxies that contain the data directly instead of
> redirecting method calls to an unproxied class.
>
> If I were to simply return o, Jersey wouldn't be able to find the @Path
> annotation because the proxy subclass does not contain it.
>
> I am suggesting the following:
>
> 1) Proxy by encapsulation (proxy methods redirect to unproxied object)
>
> Class<?> getInjectableClass(Object original)
> {
> return getInjectableObject(original).getClass();
> }
>
> Object getInjectableObject(Original original)
> {
> // return unproxied object
> }
>
> 2) Proxy by extension (proxy contains actual data)
>
> Class<?> getInjectableClass(Object original)
> {
> return original.getClass().getSuperclass();
> }
>
> Object getInjectableObject(Original original)
> {
> return original;
> }
>
> Jersey would then look up @Path and other annotations on the class
> returned by getInjectableClass() and inject into the object returned by
> getInjectableObject().
>
> The only thing I don't like about the above methods is that Spring's
> implementation of getInjectableClass() needs to invoke
> getInjectableObject() a second time. Ideally we want a single method that
> returns both Class and Object at the same time.
>
> Gili
>
--
View this message in context: http://n2.nabble.com/Simplifying-Jersey-life-cycle-and-IoC-integration-tp1367641p1573484.html
Sent from the Jersey mailing list archive at Nabble.com.