简体   繁体   中英

gson.JsonObject and class loading creating very odd situations

I have some maven projects with dependencies back to:

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.1</version>
    </dependency>

resulting in download of a single gson-2.8.1.jar file. I retrieve a copy of this file using the "clean package" maven build so I can reference a single directory for shared libraries used by classes dynamically loaded by my web application.

Due to the war file build policies (using "clean install deploy" maven build) the war file is also getting a copy of the gson-2.8.1.jar file in its WEB-INF/lib directory. As far as I know, these are all from the same jar file.

However, when running the web application and using a call like:

           JsonObject retVal = null;
           try {
              paramData.add(0, userID);
              paramData.add(0, session);
              retVal = (JsonObject) method.invoke(null,
                 paramData.toArray(new Object[0]));
           } catch (Exception e) {

I get an odd exception like:

"Caused by: java.lang.ClassCastException: com.google.gson.JsonObject cannot be cast to com.google.gson.JsonObject"

I don't understand why the same JsonObject class loaded from the gson-2.8.1.jar file in the shared library directory is not compatible with the JsonObject class that may be being loaded from the gson-2.8.1.jar in the war file. They have the same size, etc. and are the same class... because they all originated from the same gson-2.8.1.jar file...

I've tried to isolate the classes so only the one jar file in the shared library directory is called (eg, removing it from the war file). However, in some cases I'll create a class not found exception when attempting to dynamically load the class.

I realize my description is hard to follow. Is there some reason the JsonObject loaded from this jar would result in Java thinking it has two incompatible classes solely because they may have been loaded by different class loaders when what is loaded is the same object?

What you're observing is expected classloading behavior. If you load the same Foo class from two different sources, from the JVM perspective these are two different classes and as such cannot be casted to one another (ie Foo cannot be cast to Foo ). Likewise, if you have the same class Foo loaded from two different classloaders, these also cannot be cast to one another.

To resolve this issue, simply eliminate one of the copies. Since you have gone through the effort of setting up a shared library (which is the preferred approach), simply remove the gson jar from your apps WEB-INF/lib dir by changing the scope of your maven dependency to `provided.

For example:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.1</version>
    <scope>provided</scope>
</dependency>

This tells maven to include this dependency at compile time, but not at runtime (because we know it will be provided by the shared library).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM