Please excuse the length of this posting. I am trying to get all of the useful information in it and anticipate questions people might have.
I have a series of RESTful web services that have been implemented with Jersey and running in Jetty. Everything works fine with the un-obfuscated version of the jar file. But when I obfuscate with Proguard I get a 500 error with the message
The ResourceConfig instance does not contain any root resource classes.
As part of my package I have an extremely simple ping service just so I can test connectivity and the basic Jersey configuration.
My code that starts up jetty with jersey looks like this:
ServletHolder sh = new ServletHolder(ServletContainer.class);
sh.setInitParameter("com.sun.jersey.config.property.packages", "com.sw.pr.hq");
sh.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
"com.sun.jersey.api.core.PackagesResourceConfig");
ServletContextHandler sch = new ServletContextHandler(server, "/pr");
sch.addServlet(sh, "/");
When I try to hit my ping url from a browser the debug log shows the following lines:
Jan 13, 2011 9:33:35 AM com.sun.jersey.api.core.PackagesResourceConfig init
[java] INFO: Scanning for root resource and provider classes in the packages:
[java] com.sw.pr.hq
So I am of the opinion that jetty is configured and running correctly. Like I said, the un-obfuscated version of this application works fine.
The stack trace that appears when I try to ping appears at the bottom of this posting, but the most troubling line is:
[java] SEVERE: The ResourceConfig instance does not contain any root resource classes.
[java] 2011-01-13 09:33:35.585:WARN:/pr:unavailable
My proguard configuration looks like this (comments removed for brevity). Note that when I do a jar -tvf obfuscated.jar call I see the class com.sw.pr.HQServerResource.class file there.
-dontskipnonpubliclibraryclasses
-renamesourcefileattribute SourceFile
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-overloadaggressively
-repackageclasses com.sw.rtm
-adaptresourcefilenames **.properties,**.png,**.css
-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF
-keep public class * {
public *;
}
-keepclassmembernames class * {
java.lang.Class class$(java.lang.String);
java.lang.Class class$(java.lang.String, boolean);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
My ping resource class looks like this:
@Path("/")
public class HQServerResource {
@GET
@Produces(MediaType.APPLICATION_XML)
@Path("/ping")
public PingResponse pingGet(@Context HttpServletRequest httpRequest) {
LOGGER.debug("pingGet()");
return getPingResponse(httpRequest);
}
}
Now I will enter into my speculation phase due to my unfamiliarity with Proguard.
I am of the opinion that my problem boils down to Proguard mashing my @Path annotations in my class file. But I have the directive (-keepattributes Annotation) in my proguard configuration file. Hence I am now lost.
Any guidance would be appreciated.
STACK TRACE:
[java] com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes. [java] at com.sun.jersey.server.impl.application.RootResourceUriRules.(RootResourceUriRules.java:103) [java] at com.sun.jersey.server.impl.application.WebApplicationImpl._initiate(WebApplicationImpl.java:1182) [java] at com.sun.jersey.server.impl.application.WebApplicationImpl.access$600(WebApplicationImpl.java:161) [java] at com.sun.jersey.server.impl.application.WebApplicationImpl$12.f(WebApplicationImpl.java:698) [java] at com.sun.jersey.server.impl.application.WebApplicationImpl$12.f(WebApplicationImpl.java:695) [java] at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:197) [java] at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:695) [java] at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:690) [java] at com.sun.jersey.spi.container.servlet.ServletContainer.initiate(ServletContainer.java:438) [java] at com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:287) [java] at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:587) [java] at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:213) [java] at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:342) [java] at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:516) [java] at javax.servlet.GenericServlet.init(GenericServlet.java:211) [java] at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:431) [java] at org.eclipse.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:330) [java] at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:510)
I believe I have tracked down the problem I was having. The issue is that proguard, by default, doesn't include the directory entries in the obfuscated jar file.
So my obfuscated jar file contents looked something like this.
com/sw/pr/hq/HQServerResource.class
com/sw/pr/hq/a.class
com/sw/pr/hq/a.class
Note, no directory entries.
when I add the -keepdirectories directive to my proguard file my obfuscated jar file looks like this.
com/
com/sw/
com/sw/pr/
com/sw/pr/hq/
com/sw/pr/hq/HQServerResource.class
com/sw/pr/hq/a.class
com/sw/pr/hq/a.class
When this is done, Servlet is able to traverse the directories looking for my @Path annotated resources.
One bloody directive, days of pain.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With