问题
I was hopeful that Jersey would deploy easily to Google App Engine, as it is supposedly supported ( http://code.google.com/p/googleappengine/wiki/WillItPlayInJava ) and several people mention they made it work ( http://tugdualgrall.blogspot.ca/2010/02/create-and-deploy-jax-rs-rest-service.html) But it does not work...
- I created a new project with the gae plugin for eclipse (using gae sdk 1.7.3)
I added to my web.xml :
<servlet> <servlet-name>Jersey REST Service</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>sample.hello.resources</param-value> </init-param> <init-param> <param-name>com.sun.jersey.config.feature.DisableWADL</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>I added to the classpath : jersey-bundle-1.14.jar (I even tried with only core, servlet, and server AND I even tried with 1.5 only)
but I still get stuck with this :
WARNING: failed Jersey REST Service: java.lang.IncompatibleClassChangeError: Implementing class
Oct 27, 2012 6:17:06 PM com.google.apphosting.utils.jetty.JettyLogger warn
WARNING: failed com.google.appengine.tools.development.DevAppEngineWebAppContext@68c12474{/,/Users/anthony/workspaces/gae/restfulapp/war}: java.lang.IncompatibleClassChangeError: Implementing class
Oct 27, 2012 6:17:06 PM com.google.apphosting.utils.jetty.JettyLogger warn
WARNING: failed JettyContainerService$ApiProxyHandler@365878d2: java.lang.IncompatibleClassChangeError: Implementing class
Oct 27, 2012 6:17:06 PM com.google.apphosting.utils.jetty.JettyLogger warn
WARNING: Error starting handlers
java.lang.IncompatibleClassChangeError: Implementing class
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at com.google.appengine.tools.development.IsolatedAppClassLoader.loadClass(IsolatedAppClassLoader.java:207)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at com.sun.jersey.api.core.ScanningResourceConfig.init(ScanningResourceConfig.java:79)
at com.sun.jersey.api.core.PackagesResourceConfig.init(PackagesResourceConfig.java:104)
at com.sun.jersey.api.core.PackagesResourceConfig.<init>(PackagesResourceConfig.java:78)
at com.sun.jersey.api.core.PackagesResourceConfig.<init>(PackagesResourceConfig.java:89)
at com.sun.jersey.spi.container.servlet.WebComponent.createResourceConfig(WebComponent.java:696)
at com.sun.jersey.spi.container.servlet.WebComponent.createResourceConfig(WebComponent.java:674)
at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:206)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:373)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:556)
at javax.servlet.GenericServlet.init(GenericServlet.java:212)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:440)
at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:263)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:224)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:205)
at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:249)
at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:157)
at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:333)
at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48)
at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:269)
at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:245)
What did I miss ? Should I use another jax-rs implementation for gae ? Thanks for your answers !
回答1:
OK, I found out : apparently (looking at the stack trace I posted in the question) , GAE did not allow Jersey to use its classloader to scan the available rest resources. So, I read in detail the Jersey documentation the Jersey documentation regarding the deployments and I found out that I can manually specify the Rest resources to Jersey.
Here is the web.xml :
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>sample.hello.bean.MyApplication</param-value>
</init-param>
</servlet>
You can notice I now have an Application class :
package sample.hello.bean;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import sample.hello.resources.HelloResource;
public class MyApplication extends Application {
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloResource.class);
return s;
}
}
Just specify manually your rest resources adding them to the set. Works with jersey-bundle-1.14.jar
回答2:
Thanks This helped me too. But the jersey documentation also says we can configure using packages. Don't we have any other option to declare in packages. Because for every new resource we need to modify the MyApplication class
回答3:
<!-- Add following dependency in pom.xml -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
来源:https://stackoverflow.com/questions/13102977/failed-jersey-rest-service-java-lang-incompatibleclasschangeerror-implementing