gson.JsonObject 和 class 加载造成非常奇怪的情况
gson.JsonObject and class loading creating very odd situations
我有一些 Maven 项目依赖于:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.1</version>
</dependency>
导致下载单个 gson-2.8.1.jar 文件。我使用 "clean package" maven 构建检索此文件的副本,因此我可以引用由我的 Web 应用程序动态加载的 classes 使用的共享库的单个目录。
由于 war 文件构建策略(使用 "clean install deploy" maven 构建),war 文件也获得了 gson-2.8.1.jar 文件的副本在其 WEB-INF/lib 目录中。据我所知,这些都是来自同一个jar文件。
但是,当 运行 Web 应用程序并使用如下调用时:
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) {
我遇到一个奇怪的异常,例如:
"Caused by: java.lang.ClassCastException: com.google.gson.JsonObject cannot be cast to com.google.gson.JsonObject"
我不明白为什么从共享库目录中的 gson-2.8.1.jar 文件加载的同一个 JsonObject class 与可能的 JsonObject class 不兼容从 war 文件中的 gson-2.8.1.jar 加载。它们具有相同的大小等,并且相同 class... 因为它们都源自相同的 gson-2.8.1.jar 文件...
我试图隔离 classes,因此只调用共享库目录中的一个 jar 文件(例如,将其从 war 文件中删除)。但是,在某些情况下,我会在尝试动态加载 class.
时创建 class not found 异常
我发现我的描述很难理解。从这个 jar 加载的 JsonObject 是否有某种原因会导致 Java 认为它有两个不兼容的 class 仅仅是因为当加载的是同一个对象?
您观察到的是预期的class加载行为。如果您从两个不同的来源加载相同的 Foo
class,从 JVM 的角度来看,这是两个不同的 class,因此不能相互转换(即 Foo cannot be cast to Foo
).同样,如果您从两个不同的 classloader 加载了相同的 class Foo
,它们也不能相互转换。
要解决此问题,只需删除其中一个副本即可。由于您已经完成了设置共享库的工作(这是首选方法),只需将 maven 依赖项的范围更改为“已提供”,即可从应用程序 WEB-INF/lib 目录中删除 gson jar。
例如:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.1</version>
<scope>provided</scope>
</dependency>
这告诉 maven 在编译时包含此依赖项,但在运行时不包含(因为我们知道它将由共享库提供)。
我有一些 Maven 项目依赖于:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.1</version>
</dependency>
导致下载单个 gson-2.8.1.jar 文件。我使用 "clean package" maven 构建检索此文件的副本,因此我可以引用由我的 Web 应用程序动态加载的 classes 使用的共享库的单个目录。
由于 war 文件构建策略(使用 "clean install deploy" maven 构建),war 文件也获得了 gson-2.8.1.jar 文件的副本在其 WEB-INF/lib 目录中。据我所知,这些都是来自同一个jar文件。
但是,当 运行 Web 应用程序并使用如下调用时:
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) {
我遇到一个奇怪的异常,例如:
"Caused by: java.lang.ClassCastException: com.google.gson.JsonObject cannot be cast to com.google.gson.JsonObject"
我不明白为什么从共享库目录中的 gson-2.8.1.jar 文件加载的同一个 JsonObject class 与可能的 JsonObject class 不兼容从 war 文件中的 gson-2.8.1.jar 加载。它们具有相同的大小等,并且相同 class... 因为它们都源自相同的 gson-2.8.1.jar 文件...
我试图隔离 classes,因此只调用共享库目录中的一个 jar 文件(例如,将其从 war 文件中删除)。但是,在某些情况下,我会在尝试动态加载 class.
时创建 class not found 异常我发现我的描述很难理解。从这个 jar 加载的 JsonObject 是否有某种原因会导致 Java 认为它有两个不兼容的 class 仅仅是因为当加载的是同一个对象?
您观察到的是预期的class加载行为。如果您从两个不同的来源加载相同的 Foo
class,从 JVM 的角度来看,这是两个不同的 class,因此不能相互转换(即 Foo cannot be cast to Foo
).同样,如果您从两个不同的 classloader 加载了相同的 class Foo
,它们也不能相互转换。
要解决此问题,只需删除其中一个副本即可。由于您已经完成了设置共享库的工作(这是首选方法),只需将 maven 依赖项的范围更改为“已提供”,即可从应用程序 WEB-INF/lib 目录中删除 gson jar。
例如:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.1</version>
<scope>provided</scope>
</dependency>
这告诉 maven 在编译时包含此依赖项,但在运行时不包含(因为我们知道它将由共享库提供)。