JBoss7: loader constraint violation with ReastEasy and httpclient with custom HttpRequestInterceptor
Asked Answered
P

5

5

I'm using the RestEasy Client Framework in a @Named @ViewScoped Bean with JBoss-7.1.1-Final to retrieve data from a REST service with a custom HttpRequestInterceptor:

RegisterBuiltin.register(ResteasyProviderFactory.getInstance());

DefaultHttpClient httpClient = new DefaultHttpClient();
httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor("test","test"), 0);

ClientExecutor clientExecutor = new ApacheHttpClient4Executor(httpClient); //<---

//The error occurs above, the code below is only for completeness
MyRest rest = ProxyFactory.create(MyRest.class,
                                    "http://localhost:8080/rest",clientExecutor);

This works fine in a standalone client application (also ok when I remove the ClientExecutor, but I need it to authenticate REST service). The bean is in a WAR module inside an EAR, the dependency hierarchy of resteasy resolves to the following:

Resteasy dependency

There are no httpclient or httpcore in the WAR or EAR. Inside the Bean I get the following exception:

java.lang.NoClassDefFoundError: org/apache/http/HttpRequestInterceptor

Seems to be easy (although I'm wondering about the resteasy packaging) and I added org.apache.httpcomponents:httpclient with compile scope:

enter image description here

No I'm getting he following exception:

java.lang.LinkageError: loader constraint violation: when resolving method   
  "org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor.<init>    
  (Lorg/apache/http/client/HttpClient;)V"
  the class loader (instance of org/jboss/modules/ModuleClassLoader)
      of the current class, my/TestBean, and
  the class loader (instance of org/jboss/modules/ModuleClassLoader)
      for resolved class, 
  org/jboss/resteasy/client/core/executors/ApacheHttpClient4Executor,
  have different Class objects for the type org/apache/http/client/HttpClient
  used in the signature my.TestBean.init(TestBean.java:65)

Update To reproduce this you don't need REST interfaces, the error occurs while instantiating the ApacheHttpClient4Executor, but you may need the custom PreemptiveAuthInterceptor:

public class PreemptiveAuthInterceptor implements HttpRequestInterceptor
{
  private String username;
  private String password;

  public PreemptiveAuthInterceptor(String username, String password)
  {
    this.username=username;
    this.password=password;
  }

  @Override
  public void process(org.apache.http.HttpRequest request, HttpContext context) throws HttpException, IOException
  {
    AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);

    authState.setAuthScope(org.apache.http.auth.AuthScope.ANY);
    authState.setCredentials(new UsernamePasswordCredentials(username,password));
    authState.setAuthScheme(new BasicScheme());

  }
}
Precast answered 15/5, 2012 at 10:34 Comment(1)
This has been a bug for a while: issues.jboss.org/browse/AS7-2803Burschenschaft
H
10

To avoid the linkage error when deploying the application on JBoss, configure module org.apache.httpcomponents within the modules folder of the JBoss installation, but avoid including the JARs from HttpComponents with your application:

  1. Place the required JARs from HttpComponents in modules/org/apache/httpcomponents/main.
  2. List these JARs in module.xml within this directory.
  3. Add Dependencies: org.apache.httpcomponents to the MANIFEST.MF of your component.

Note that the module referred to in step 1 and 2 already exists. You may however want to include additional JARS (e.g. httpclient-cache-x.y.z.jar) or different versions.

Resolving classes within your development environment is another matter of course.

Hassan answered 29/5, 2012 at 14:10 Comment(0)
A
7

I had the same problem in similar circumstances. The HttpComponents module required was already in my JBoss (AS 7.1.1) modules directory. Therefore, all I had to do to resolve the issue was to add a manifest entry as described by Eustachius, which in Maven you can do like so:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Dependencies>org.apache.httpcomponents</Dependencies>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

The configuration is the same for the maven-war-plugin.

Antinomian answered 2/8, 2012 at 1:24 Comment(0)
M
2

If a module is needed in an Arquillian test...

Create arquillian-manifest.mf in src/test/resources with the following:

Manifest-Version: 1.0
Dependencies: org.jboss.resteasy.resteasy-jaxrs,org.apache.httpcomponents

Then when you ShrinkWrap:

WebArchive war = ShrinkWrap.create...
    .addAsManifestResource("arquillian-manifest.mf", "MANIFEST.MF")
Mark answered 1/10, 2012 at 14:42 Comment(0)
Z
0

But Add Dependencies: org.apache.httpcomponents to the MANIFEST.MF of your component.

causing an exception - Caused by: java.lang.IllegalStateException: JBAS014744: No META-INF/services/org.jboss.as.controller.Extension found for org.apache.httpcomponents:main at org.jboss.as.controller.parsing.ExtensionXml.loadModule(ExtensionXml.java:191) [jboss-as-controller-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]

Zane answered 31/10, 2014 at 2:9 Comment(0)
T
0

At last I have to use my ultimate solution:

  • define resteasy-jaxrs as provided dependency, same as httpcomponents:httpclient
  • use copy-dependency and jib maven plugin to copy higher versions of resteasy-jaxrs jars and its dependencies to main slot of resteasy-jaxrs(to find the other jars needed, check original module.xml in the main slot of base image/server, and upgrade as needed; define them in pom.xml as runtime dependency as you don't need them to compile, only need for copying jar. For example in my module.xml I see:
    <resources>
        <resource-root path="async-http-servlet-3.0-2.3.10.Final-redhat-1.jar"/>
        <resource-root path="resteasy-jaxrs-2.3.10.Final-redhat-1.jar"/>
    </resources>

, so to upgrade to 2.3.23, upgrade both.)

  • do the same to higher versions of httpcomponents:httpclient jars(because it's implicit dependency for resteasy-jaxrs)
  • create 2 modified module.xml in your project, pointing to higher versions of jar file names of both modules, then use jib plugin to overwrite the modules.xml in both main slots.

Making sure copying jars happens in a Maven build phase previous to jib building images. For example, prepare-package is before package.

My theory is, resteasy-jaxrs is implicit dependency for JBoss EAP server and their classloaders have the highest priority, so they will load the classes they want in the first place, and only the main slot, before any explicit depedencies/jboss-deployment-structure.xml dependencies/others. So the only way I have is to change main slot.

Taryntaryne answered 20/10 at 19:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.