Discussion:
Problems getting Spring auto-proxying to work in Jersey 1.10
Petter Mahlen
2012-01-03 10:04:27 UTC
Permalink
Hi,

I've been trying to get a standard aspect that we're using in all our internal services to do performance monitoring to work in Jersey, but I've not been able to find a way to configure things to work. Maybe somebody here can help. Here's what I've tried:

First, the monitoring tool we have uses Spring AOP, an internal annotation (JamonMonitored), and a bean post processor to figure out which beans to create proxies for. There is an interface for the web resource:

public interface DataIngestionResource {
DataIngestionResponse ingest(DataIngestionRequest request);
}

The implementation is:

@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
@Path("/data-ingestion")
public class JerseyDataIngestionResource implements DataIngestionResource {

private final DataIngester dataIngester;

public JerseyDataIngestionResource(DataIngester dataIngester) {
this.dataIngester = dataIngester;
}

@Override
@POST
@Path("/ingest")
@JamonMonitored(type = "type=DataIngestor,subtype=web")
public DataIngestionResponse ingest(@RequestParam DataIngestionRequest request) {
…
}
}

I'm also using the JamonMonitored annotation on other beans, notable the injected DataIngester implementation.

1. 'Regular', initial take:

In the spring configuration file, I specified:

<aop:aspectj-autoproxy />

This fails with the following error:

Jan 3, 2012 10:29:20 AM com.sun.jersey.spi.inject.Errors processErrorMessages
SEVERE: The following errors and warnings have been detected with resource and/or provider classes:
SEVERE: Missing dependency for constructor public com.shopzilla.inventory.imp.di.webapp.JerseyDataIngestionResource(com.shopzilla.inventory.imp.di.DataIngester) at parameter index 0

The error message is pretty poor, as it makes you think that the problem is with the DataIngester that is being injected. However, removing JamonMonitored from the Jersey resource and leaving it in place for the DataIngester implementation works well. So the problem is in fact not that there is a dependency missing, but that Jersey is for some reason unable to instantiate the JerseyDataIngestionResource.

2. JAX-RS annotations on interface:

Based on a post I found (http://jersey.576304.n2.nabble.com/Jersey-and-AOP-td5963266.html), I tried to move the JAX-RS annotations to the interface instead. This fails with the following error message:

Jan 3, 2012 10:30:31 AM com.sun.jersey.spi.inject.Errors processErrorMessages
SEVERE: The following errors and warnings have been detected with resource and/or provider classes:
SEVERE: Conflicting URI templates. The URI template /data-ingestion for root resource class $Proxy32 and the URI template /data-ingestion transform to the same regular expression /data-ingestion(/.*)?

So it seems there is some kind of conflict between the interface and the proxy? I'm not sure how to interpret this message.

3. Auto-proxy using CGLIB version:

The final thing I've tried is to use CGLIB for proxying by specifying

<aop:aspectj-autoproxy proxy-target-class="true"/>

This, too, fails, with the following error:

2012-01-03 10:34:07,399 [] ERROR [ContextLoader.java:227] Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataIngester' defined in class path resource [com/shopzilla/inventory/imp/di/wiring/DataIngestionConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.shopzilla.inventory.imp.di.FeedDataIngester]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given

Presumably, the issue is that the class in question uses constructor-injected parameters (something I want to keep doing), and CGLIB-generated proxies require a no-arguments constructor, or something along those lines. There are some notes in the Spring documentation (http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-proxying) suggesting that constructors are called twice, something that won't work with final members.

Does anybody have any ideas of how this could be resolved?

Thanks,
Petter
Basil
2012-01-19 11:20:40 UTC
Permalink
Post by Petter Mahlen
Hi,
I've been trying to get a standard aspect that we're using in all our
internal services to do performance monitoring to work in Jersey, but I've not
been able to find a way to configure things to work. Maybe somebody here can
Post by Petter Mahlen
First, the monitoring tool we have uses Spring AOP, an internal annotation
(JamonMonitored), and a bean post processor to figure out which beans to
Post by Petter Mahlen
public interface DataIngestionResource {
    DataIngestionResponse ingest(DataIngestionRequest request);
}
<at> Consumes({MediaType.APPLICATION_JSON})
<at> Produces({MediaType.APPLICATION_JSON})
<at> Path("/data-ingestion")
public class JerseyDataIngestionResource implements DataIngestionResource {
    private final DataIngester dataIngester;
    public JerseyDataIngestionResource(DataIngester dataIngester) {
        this.dataIngester = dataIngester;
    }
    <at> Override
    <at> POST
    <at> Path("/ingest")
    <at> JamonMonitored(type = "type=DataIngestor,subtype=web")
    public DataIngestionResponse ingest( <at> RequestParam
DataIngestionRequest request) {
Post by Petter Mahlen

   }
}
I'm also using the JamonMonitored annotation on other beans, notable the
injected DataIngester implementation.
Post by Petter Mahlen
  <aop:aspectj-autoproxy />
Jan 3, 2012 10:29:20 AM com.sun.jersey.spi.inject.Errors processErrorMessages
SEVERE: The following errors and warnings have been detected with resource
  SEVERE: Missing dependency for constructor public
com.shopzilla.inventory.imp.di.webapp.JerseyDataIngestionResource
(com.shopzilla.inventory.imp.di.DataIngester) at parameter index 0
Post by Petter Mahlen
The error message is pretty poor, as it makes you think that the problem is
with the DataIngester that is being injected. However, removing JamonMonitored
from the Jersey resource and leaving it in place for the DataIngester
implementation works well. So the problem is in fact not that there is a
dependency missing, but that Jersey is for some reason unable to instantiate
the JerseyDataIngestionResource.
Post by Petter Mahlen
Based on a post I found (http://jersey.576304.n2.nabble.com/Jersey-and-AOP-
td5963266.html), I tried to move the JAX-RS annotations to the interface
Post by Petter Mahlen
Jan 3, 2012 10:30:31 AM com.sun.jersey.spi.inject.Errors processErrorMessages
SEVERE: The following errors and warnings have been detected with resource
  SEVERE: Conflicting URI templates. The URI template /data-ingestion for
root resource class $Proxy32 and the URI template /data-ingestion transform to
the same regular expression /data-ingestion(/.*)?
Post by Petter Mahlen
So it seems there is some kind of conflict between the interface and the
proxy? I'm not sure how to interpret this message.
Post by Petter Mahlen
The final thing I've tried is to use CGLIB for proxying by specifying 
  <aop:aspectj-autoproxy proxy-target-class="true"/>
2012-01-03 10:34:07,399 [] ERROR [ContextLoader.java:227] Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'dataIngester' defined in class path resource
[com/shopzilla/inventory/imp/di/wiring/DataIngestionConfiguration.class]:
Initialization of bean failed; nested exception is
org.springframework.aop.framework.AopConfigException: Could not generate CGLIB
subclass of class [class com.shopzilla.inventory.imp.di.FeedDataIngester]:
Common causes of this problem include using a final class or a non-visible
class; nested exception is java.lang.IllegalArgumentException: Superclass has
no null constructors but no arguments were given
Post by Petter Mahlen
Presumably, the issue is that the class in question uses constructor-
injected parameters (something I want to keep doing), and CGLIB-generated
proxies require a no-arguments constructor, or something along those lines.
There are some notes in the Spring documentation
(http://static.springsource.org/spring/docs/3.1.x/spring-framework-
reference/html/aop.html#aop-proxying) suggesting that constructors are called
twice, something that won't work with final members.
Post by Petter Mahlen
Does anybody have any ideas of how this could be resolved?
Thanks,
Petter
Hi Petter,

Is this issue resolved? I'm also facing the same issue.

Thanks
Basil

Loading...