javaclassloaderjboss7.xresteasy

JBoss7: loader constraint violation with ReastEasy and httpclient with custom HttpRequestInterceptor


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());

  }
}

Solution

  • 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.