Kong / unirest-java

Unirest in Java: Simplified, lightweight HTTP client library.
http://kong.github.io/unirest-java/
MIT License
2.58k stars 591 forks source link

java.lang.NoClassDefFoundError: Could not initialize class org.apache.http.conn.ssl.SSLConnectionSocketFactory #441

Closed gregkotsaftis closed 1 year ago

gregkotsaftis commented 2 years ago

I have an Executor that handles new simple threads which check for sms delivery. Normally this works just fine but sometimes i get: java.lang.NoClassDefFoundError: Could not initialize class org.apache.http.conn.ssl.SSLConnectionSocketFactory without any other errors. This continues for hours; all new threads fail with the same error. Then at some point the errors stop and new threads function normally. Here is part of the stack trace and the code that triggers the exception:

Exception:

... SmsDeliveryCheckRunner error
java.lang.NoClassDefFoundError: Could not initialize class org.apache.http.conn.ssl.SSLConnectionSocketFactory
    at kong.unirest.apache.SecurityConfig.createDefaultRegistry(SecurityConfig.java:85)
    at kong.unirest.apache.SecurityConfig.buildSocketFactory(SecurityConfig.java:75)
    at kong.unirest.apache.SecurityConfig.createManager(SecurityConfig.java:59)
    at kong.unirest.apache.ApacheClient.<init>(ApacheClient.java:54)
    at kong.unirest.Config.buildClient(Config.java:709)
    at kong.unirest.Config.getClient(Config.java:694)
    at kong.unirest.BaseRequest.asString(BaseRequest.java:208)
    ...my code...

Code:

HttpResponse<String> httpResponse = Unirest.post( SERVICE_URL )
  .header("Accept", "application/json")
  .header("Accept-Charset", _encoding)
  .header("Content-Type", CONTENT_TYPE)
  .header("Authorization", "Basic " + getApikey())
  .body( request )
  .asString();

In my classpath i have:

unirest-java-3.11.00.jar
httpmime-4.5.12.jar
httpcore-nio-4.4.13.jar
httpcore-4.4.13.jar
httpclient-4.5.12.jar
httpasyncclient-4.1.4.jar
commons-net-3.6.jar
commons-logging-1.2.jar
gson-2.8.6.jar
commons-codec-1.15.jar
rzkrn20 commented 2 years ago

Are you using https?

ryber commented 2 years ago

It's possible you have two different versions of SSLConnectionSocketFactory on the class path and that the JVM is grabbing the "wrong" one some of the time.

gregkotsaftis commented 2 years ago

Are you using https?

yes!

gregkotsaftis commented 2 years ago

It's possible you have two different versions of SSLConnectionSocketFactory on the class path and that the JVM is grabbing the "wrong" one some of the time.

OMG this could be a nightmare to debug and i would do not even know how to approach this. Any tools that can search and find the class in question in classpath? I have quite a few dependencies...

ryber commented 2 years ago

When you do a package with maven, there will be warnings about duplicate package/class's coming from different jars. That will tell you that your package has a conflict directly. Sometimes deployed runtimes can also have classes. Like if you are deploying to a stand alone (not embedded) tomcat for example.

If could also be that your JVM is just messed up. note that the doc for the exception says:

Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
gregkotsaftis commented 2 years ago

I used classgraph tool to clean up some jar hell mainly with JTA which was a couple of times in my classpath. But there were no duplicates for org.apache.http.conn.ssl.SSLConnectionSocketFactory! Anyway, i updated to latest version of unirest-java and will be monitoring if this issue appears again. It may take some months to be sure...

ryber commented 2 years ago

I think it's really hard to know here, these are JVM errors, not really a functional problem with unirest (IMHO), for some reason you are losing the class, one concern I have is that you are getting this error at some point after the system has been running. The init of this class happens during the init of the unirest config, which is kind of heavy thing in 3, because there are complex Apache configurations made as well as monitoring threads. Ideally this should be done once for a instance of unirest, and then left, if you are doing something to invalidate the config it would force this to happen again, and doing that a LOT would be bad. Look for where you might be messing with .config() and then, move that to happen once per JVM lifecycle.

gregkotsaftis commented 2 years ago

I never use the .config() directly! Actually all my unirest usage code is exactly like the code i provided! The only extra info I forgot to mention is about Unirest.shutDown();

I have a static helper class to register Unirest usage like this: Before calling Unirest methods I call UnirestUtil.registerShutdownHook(); Which is:

public class UnirestUtil {

    private static boolean isShutdownHookRegistered = false;

    public synchronized static void registerShutdownHook()
    {
        if( !isShutdownHookRegistered )
        {
            //Runtime.getRuntime().addShutdownHook(new Thread(Unirest::shutDown));
            Runtime.getRuntime().addShutdownHook( new Thread() {
                @Override
                public void run()
                {
                    Unirest.shutDown();
                }
            });
            isShutdownHookRegistered = true;
        }
    }
}

Now, does this rings any bells?

ryber commented 2 years ago

Yes, the shutdown would cause a re-init IF Unirest is invoked after it, not sure how that would happen after a JVM shutdown though. BTW, the RC versions of unirest don't even have this class or Apache as a dependency. You do have to be on at least Java 9 for it (but of course we are all on at least Java 11 now that 8 is no longer supported right :D)

gregkotsaftis commented 2 years ago

I have to stick with old good java 8 for now... unlucky me or is there something else i can do?