我的申请表我面临异常,
/component/ProviderServices;Lcom/sun/jersey/core/spi/factory/InjectableProviderFactory;)V
at com.sun.jersey.api.client.Client.<init>(Client.java:212)
at com.sun.jersey.api.client.Client.<init>(Client.java:150)
at com.sun.jersey.api.client.Client.create(Client.java:476)
at com.example.data.DataReader.getData(DataReader.java:25)
at com.example.data.TestServlet.doGet(TestServlet.java:41)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
我找到了这个例外的原因,但我不知道如何解决它。问题是我的类路径中有两个罐子jersey-bundle-1.1.5.1 and jersey-core-1.17.1
。 ContextResolverFactory.java
存在于具有相同包名的两个罐中。 init
方法存在于jersey-core-1.17.1中,但不存在于jersey-bundle-1.1.5.1中。在windows
构建环境中,它运行正常。这意味着JRE正确选择ContextResolverFactory.java of jersey-core-1.17.1
并执行init方法。而在linux
环境中,JRE选择ContextResolverFactory.java of jersey-bundle-1.1.5.1
并尝试调用init
方法并抛出上述异常。我不能盲目地取出一个罐子,因为两个罐子都是为了不同的商业目的而需要的。
How to fix it in both linux and windows environment?
Why it is working fine in windows environment but not in linux environment?
答案 0 :(得分:1)
我完全同意评论者的意见。本身在类路径上多次使用相同的类(在同一个包中)是不好的做法。这几乎总会引起麻烦。最好的办法是检查你是否可以使你的代码与jersey 1.17.1一起使用,并且只使用jersey-core-1.17.1 jar。
但是,我也理解在某些情况下您无法控制这些依赖关系,即第三方库依赖于某个库的特定版本,您只需要解决这些问题。
在这些情况下,重要的是要注意默认的java类加载器遵循类路径中元素的顺序。我假设Linux安装中CLASSPATH变量的顺序与Windows安装中的顺序不同。
如果您在开发过程中使用Eclipse等IDE,请检查其中的构建路径设置,并尝试以完全相同的顺序在生产中设置CLASSPATH变量。
如需参考,请查看stackoverflow上的其他问题:
Controlling the order of how JARs are loaded in the classpath
Is the order of the value inside the CLASSPATH matter?
对于Tomcat,无法定义WEB-INF / lib中JAR文件的顺序。您可以在这里做的唯一事情是将需要首先加载的JAR文件发送到生产环境中的其他目录,例如JRE / lib目录,Tomcat / common目录或Tomcat / shared目录。这些都优先于WEB-INF / lib目录。有关如何在较旧的Tomcat版本上运行的详细信息,请参阅Control the classpath ordering of jars in WEB-INF/lib on Tomcat 5?。
答案 1 :(得分:1)
当我开发自己的应用程序时,我尝试遵循的一个指导原则是,我想制作它们&#34;虚拟证明。&#34;我想让最终用户尽可能轻松。
因此,我会将应用程序的构建更改为在最终jar中包含ContextResolverFactory.class
(来自jersey-core-1.17.1.jar)。这是一般方法。用于实现此目的的具体工具可能会有所不同。
我会使用maven和maven-shade-plugin。这个插件甚至可以执行所谓的重定位,您可以在模式标记中提供原始包,并在shadedPattern标记中提供所需的新包位置:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>com.sun.jersey.core.spi.factory</pattern>
<shadedPattern>${project.groupId}.${project.artifactId}.com.sun.jersey.core.spi.factory</shadedPattern>
</relocation>
</relocations>
<artifactSet>
<includes>
<include>com.sun.jersey:jersey-core</include>
</includes>
</artifactSet>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins
</build>
即使您没有使用maven,您仍然可以创建一个小型项目,其唯一目的是重构包位置。然后,您可以将此依赖项添加到项目中,并使用它来可靠地访问init()
方法。
如果您对maven有经验,那么我强烈建议您将项目拆分为所谓的maven多模块POM项目。这将是新的构建顺序:
The Interface module
The Implementation Layer
The Runtime module
实现层通常由许多不同的模块组成,这些模块都依赖于接口模块。 Runtime模块在运行时选择正确的实现。
如果您目前只有一个实现,则可能看不到该值...但是,如果您需要添加更多实现,它会增加灵活性,因为您可以轻松添加它们。因为您的代码永远不会直接引用实现,而是始终使用接口,并且它并不关心使用哪种实现。
所以,这会让你,开发人员更难,但最终用户会更容易。无论他们是在Windows,Linux还是Mac上,它都能正常运作!
答案 2 :(得分:0)
检查源代码后,我注意到init()
的所有逻辑都被移到了构造函数中。
另一个选择是简单地使用新构造函数并捕获不存在的异常情况,在这种情况下,您只需使用默认构造函数,然后使用init()
方法:
ContextResolverFactory factory = null;
try {
factory = new ContextResolverFactory(providerServies, ipf);
} catch (InvalidClassException ex) {
factory = new ContextResolverFactory().init(providerServices, ipf);
}
// ...
ContextResolver<MyType> cr = factory.resolve(type, mediaType);
if (cr == null) // handle null and not null...
希望这会有所帮助。祝你好运!