在Jboss 7上使用Jersey 2

10

有人成功地在JBoss 7.x上部署过Jersey 2.x吗? 我尝试使用JBoss 7.1.1部署Jersey 2.5,但遇到了以下错误:

"java.lang.NoSuchMethodError: javax.ws.rs.core.Application.getProperties()Ljava/util/Map;"

我认为这个问题是因为JBoss捆绑了RestEasy,它是一个JAX-RS 1.0的实现,而Jersey是一个JAX-RS 2.0的实现。所以我采取了以下步骤来禁用RestEasy:

1)在我的web.xml文件中添加了以下内容:

<context-param>
    <param-name>resteasy.scan</param-name>
    <param-value>false</param-value>
</context-param>
<context-param>
    <param-name>resteasy.scan.providers</param-name>
    <param-value>false</param-value>
</context-param>
<context-param>
    <param-name>resteasy.scan.resources</param-name>
    <param-value>false</param-value>
</context-param>

2) 参考这里的讨论,我修改了JBoss的standalone.xml、module.xml和domain.xml文件,删除了对JAXRS1.1/RestEasy的所有引用。

3) 这导致另一个错误:"java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor",我通过在pom.xml中添加以下内容解决了这个问题:

<dependency>
    <groupId>asm</groupId>
    <artifactId>asm</artifactId>
    <version>3.3.1</version>
</dependency>

最终我的应用程序已经成功部署,但是现在我似乎无法访问我的Jersey资源。Jetty 8工作正常。不过,我也能够运行Jersey 1.x,而不需要执行步骤#2和#3,但如果可能的话,我更愿意使用Jersey 2.x。

此外,我还尝试创建了一个jboss-deployment-structure.xml文件,但是我仍然会遇到先前的错误,例如“java.lang.NoSuchMethodError:javax.ws.rs.core.Application.getProperties()Ljava/util/Map;”。

<?xml version="1.0" encoding="UTF-8"?>  
<jboss-deployment-structure>
  <deployment>
    <exclusions>
            <module name="org.jboss.resteasy.resteasy-atom-provider"/>  
            <module name="org.jboss.resteasy.resteasy-cdi"/>  
            <module name="org.jboss.resteasy.resteasy-jackson-provider"/>  
            <module name="org.jboss.resteasy.resteasy-jaxb-provider"/>  
            <module name="org.jboss.resteasy.resteasy-jaxrs"/>  
            <module name="org.jboss.resteasy.resteasy-jettison-provider"/>  
            <module name="org.jboss.resteasy.resteasy-jsapi"/>  
            <module name="org.jboss.resteasy.resteasy-multipart-provider"/>  
            <module name="org.jboss.resteasy.resteasy-yaml-provider"/>  
            <module name="org.apache.log4j"/>  
            <module name="org.apache.commons.pool"/>  
            <module name="javax.ws.rs.api"/>
    </exclusions>
  </deployment>
</jboss-deployment-structure>

有人在使用 Jboss 和 Jersey 2.x 方面有什么好的经验吗?任何帮助都将不胜感激。


这与冲突的J2EE库有关。请确定Jersey 2使用的Java版本以及您的Jboss版本提供的J2EE库版本。请检查它们。 - erhanasikoglu
1
由于javax.ws.rs.core.Application位于javax.ws.rs.api模块中,因此在jboss-deployment-structure.xml中排除它应该会删除该类。您使用EAR或WAR,在哪里放置了jboss-deployment-structure.xml?您可以将类别“jboss.modules”设置为TRACE以打开日志记录,或查看MBean jboss.modules:type = ModuleLoader以获取更多信息。 - Erhard Siegl
@Erhard:我正在使用WAR,并尝试将jboss-deployment-structure.xml添加到WEB-INF和META-INF,但结果相同。将日志级别设置为跟踪会发现jboss-deployment-structure.xml确实没有排除JAXRS 1.x javax.ws.rs.core.application,所以我正在研究原因。Erhan,我还尝试通过Maven使用Java7编译器编译我的WAR(JBoss使用Java7,但我使用Java6编译WAR),但是什么也没变。 - Minh Nguyen
1
很抱歉,我不确定为什么在你的情况下无法运行。将Hibernate 4换成3或JSF 2换成1.2对我来说效果很好。但是我总是用一个模块替换另一个模块(其他插槽)。也许javaee.api即使被排除了也会拉取javax.ws.rs.api事件。我建议暂时删除javaee.api模块上对javax.ws.rs.api的依赖,或创建一个新的模块javax.ws.rs.api并包含您的Jersey实现,并将其包含在WEB-INF/jboss-deployment-structure.xml中。但我不能保证它有帮助。 - Erhard Siegl
似乎javaee.api会通过传递方式拉取javax.ws.rs.api模块。请参见此处:https://community.jboss.org/thread/231153 - Piotr Gwiazda
5个回答

14

如果您像这样配置您的 jboss-deployment-structure.xml,则可以在 JBoss 7 上使用 Jersey 2:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>

<exclude-subsystems>
  <subsystem name="resteasy" />
</exclude-subsystems>

<exclusions>
  <module name="javaee.api" />
  <module name="javax.ws.rs.api"/>
  <module name="org.jboss.resteasy.resteasy-jaxrs" />
</exclusions>

<local-last value="true" />

</deployment>
</jboss-deployment-structure>

因为JBoss 7包含模块的依赖关系,仅排除resteasy模块本身是不够的,您需要排除整个javaee.api模块。同时确保不要排除太多模块,否则可能会破坏您的应用程序-上面的示例足以禁用resteasy。

正如您已经发现的那样,您仍然需要在web.xml中包含以下行:

  <context-param>
   <param-name>resteasy.scan</param-name>
   <param-value>false</param-value>
  </context-param>
  <context-param> 
   <param-name>resteasy.scan.providers</param-name>
   <param-value>false</param-value>
  </context-param>
  <context-param>
   <param-name>resteasy.scan.resources</param-name>
   <param-value>false</param-value>
  </context-param>

谢谢!这比修改JBoss配置文件更好。但是,您能够访问您的Jersey REST资源吗?我在所有资源上都得到了404错误。我实际上尝试使用Resteasy 3替换Jersey 2(两者都是JAX 2.0,因此最小代码更改),并且可以访问我的资源。我还必须执行与上述jboss-deployment-structure类似的操作,以使我的Resteasy 3.0不与JBoss的Resteasy 2发生冲突。 - Minh Nguyen
此外,我所有的Jersey资源在Jetty中都能正常工作,所以我认为这可能与JBoss的排除有关? - Minh Nguyen
实际上,我已经成功让Jersey读取我的资源并解决了404问题。由于某种原因,在JBoss中包扫描无法正常工作,但我可以使用单个类资源注册来解决问题。再次感谢您的帮助。 - Minh Nguyen
这个答案非常有帮助! - Rohit

3

这与这个问题类似。

只是在使用不同的子系统时进行了一些复制/粘贴。

您应该排除jaxrs子系统被激活以用于部署,将以下内容添加到META-INF/jboss-deployment-structure.xml中即可:

    <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
      <deployment>
         <!-- exclude-subsystem prevents a subsystems deployment unit processors running on a deployment -->
         <!-- which gives basically the same effect as removing the subsystem, but it only affects single deployment -->
         <exclude-subsystems>
            <subsystem name="jaxrs" />
        </exclude-subsystems>

         <!-- This is needed in any case even if you don't use exclude-subsystem above-->        
         <exclusions>  
          <module name="javax.ws.rs.api" />  
        </exclusions>  
      <deployment>
     </jboss-deployment-structure>

您可以前往 standalone.xml 并删除其中的子系统。要做到这一点,您需要删除


<subsystem xmlns="urn:jboss:domain:jaxrs:1.x">
...
...
<subsystem>

配置的一部分,扩展部分放在上面不影响。或者你可以使用CLI连接到服务器并运行。

/subsystem=jaxrs:remove()

无论如何,我建议阅读AS7中的类装入位 https://docs.jboss.org/author/display/AS72/Class+Loading+in+AS7
请注意,exclude-subsystems功能和deployment-structure:1.2 是在7.1.2中添加的,因此在7.1.1上将无法工作。
您仍然可以删除jaxrs子系统,但这会影响整个服务器。

感谢您的帮助和资源!不幸的是,我必须支持JBoss 7.1.1,所以我无法测试您的解决方案(同时对于我的缓慢回复表示歉意,我有一段时间没有处理这个问题)。然而,我想知道另一个答案是否更好,因为它可以在多个JBoss版本中使用? - Minh Nguyen

2

我遇到了几乎完全相同的问题(https://dev59.com/YHXYa4cB1Zd3GeqP7o56#38273524):

"需要在Tomcat7上运行已经在JBoss 7.1.1中运行的Jersey 2.23.1 Web应用程序。"

不幸的是,这里的任何方法都没有为我解决问题,但其中一些内容对我有所帮助,引导我找到了最终的解决方案:

  1. Turn off Resteasy package scanning in your web.xml:

    <context-param>
      <param-name>resteasy.scan</param-name>
      <param-value>false</param-value>
    </context-param>
    <context-param> 
      <param-name>resteasy.scan.providers</param-name>
      <param-value>false</param-value>
    </context-param>
    <context-param>
      <param-name>resteasy.scan.resources</param-name>
      <param-value>false</param-value>
    </context-param>
    
  2. Remove all tags with "jaxrs" from standalone.xml. Otherwise you will still face LinkageError because JBoss keeps 1.1 spec "on".

  3. Create yourApp.war!WEB-INF\jboss-deployment-structure.xml just like is pointed out here: https://docs.jboss.org/author/display/AS7/Class+Loading+in+AS7#ClassLoadinginAS7-JBossDeploymentStructureFile

这样做不仅可以消除:java.lang.NoSuchMethodError: javax.ws.rs.core.Application.getProperties()Ljava/util/Map;

还可以使JAXB正常工作(只要激活javax.xml.bind.api模块,就不会出现ClassNotFoundException for javax.xml.bind.JAXBException)。

注意1:原始问题混淆了jersey 1.x和jersey 2.x。在jersey 2.x中没有PojoMappingFeature,基础包是org.glassfish.jersey。请参阅https://jersey.java.net/documentation/latest/migration.html#mig-1-x-json

注意2:我还尝试了其他方法,比如扩展ResourceConfig并从那里扫描包或直接注册类。但没有像第3项中的适当文档那样有效。因此保持我的servlet不变:

    <servlet>
      <servlet-name>WebNize REST Service</servlet-name>
      <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
      <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>br.com.webnize.rest.service</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
      <servlet-name>WebNize REST Service</servlet-name>
      <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

希望对您有所帮助!

1
为什么这个被投票否决了?(它目前是我应用程序中的工作解决方案) - Reginaldo Santos

0

Clemens82的回答之后,排除了javaee.api模块后,我遇到了这个问题:

java.lang.NoClassDefFoundError: javax/xml/ws/Endpoint
    at java.lang.Class.getDeclaredMethods0(Native Method) [rt.jar:1.7.0_72]
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2615) [rt.jar:1.7.0_72]
    at java.lang.Class.getDeclaredMethods(Class.java:1860) [rt.jar:1.7.0_72]
    at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:152) [spring-core-4.2.5.RELEASE.jar:4.2.5.RELEASE]

为了解决这个问题,我不得不将javax.xml.ws.api依赖项添加到jboss-deployment-structure.xml中。此外,如果使用servlet,应该由容器提供javax.servlet.api
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="javax.xml.ws.api" /> <!-- Required due to exclusion of javaee.api below -->
            <module name="javax.servlet.api" /> <!-- Required due to exclusion of javaee.api below -->
        </dependencies>
        <exclude-subsystems>
            <subsystem name="resteasy" />
        </exclude-subsystems>
        <exclusions>
            <module name="javaee.api" />
            <module name="javax.ws.rs.api"/>
            <module name="org.jboss.resteasy.resteasy-jaxrs" />
        </exclusions>
        <local-last value="true" />
    </deployment>
</jboss-deployment-structure>

0

这是对我有用的组合(其中很多来自本帖中其他答案 - 感谢大家!)。

  1. Jersey 2.22.1 + JBoss EAP 6.4(基于 JBoss AS 7.5)
  2. 通过 jboss-deployment-structure.xml 排除 jaxrs 和 resteasy 子系统
  3. 没有更改任何 JBoss 模块,因为这样做会导致我的环境中的其他事情无法正常工作
  4. 通过 web.xml 中的上下文参数禁用 resteasy 扫描,如其他人所指出的那样
  5. 删除了 Jersey provider 类的 init-param,并代之以实现 javax.ws.rs.core.Application 来自注册我的 Jersey 资源类

此时,Web 应用程序已成功部署,但在尝试访问我的 REST 服务时却收到了 404 错误。

  1. 我最后做的一件事是在 web.xml 中将 Jersey 从 servlet 更改为过滤器,然后它开始工作了

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接