Spring 使用 Jackson 和带有 Gson 的外部库启动
Spring Boot using Jackson and an external Library with Gson
我正在使用 Jackson 的 Spring 引导应用程序(版本 2.4.5)。我可以添加一个使用 gson 的 fat jar 而不影响应用程序的 Jackson 反序列化吗?
当我将 jar 添加到我的应用程序时,该应用程序到处都使用 gson 来反序列化 JSON。但是由于我使用了 Jackson 的一些特殊功能,所以失败了。
很遗憾,我无法在库中更改它。
我使用Gradle在依赖项中添加这样的fat jar:
implementation fileTree(dir: 'libs', include: ['*.jar'])
我正在像这样构建 Jacksons 对象映射器:
private static ObjectMapper getMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
mapper.registerModule(new JavaTimeModule());
return mapper;
}
下面几行会引发错误:
List<User> users = objectMapper.readValue(getReader("users.json"), new TypeReference<>() {});
java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class User (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; onek.books.backend.model.book.Book is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @445d3853)
并且 Gson 被添加到具有以下 Maven 依赖项的 fat jar 中:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson-version}</version>
</dependency>
<dependency>
<groupId>io.gsonfire</groupId>
<artifactId>gson-fire</artifactId>
<version>${gson-fire-version}</version>
</dependency>
编辑
正如所建议的那样,这不是由于 gson,我试图缩小范围并一一添加所有依赖项,none 本身导致了错误。
但是我可能找到了原因,但我不知道如何解决这个问题。这是 Jacksons typeFactory 构造它的类型的方式。对于行:
List<Book> books = objectMapper.readValue(getReader("books.json"), new TypeReference<>() {});
如果 jar 不存在,构造的类型如下所示:
result = {CollectionType@13667} "[collection type; class java.util.List, contains [simple type, class onek.books.backend.model.book.Book]]"
_elementType = {SimpleType@13669} "[simple type, class onek.books.backend.model.book.Book]"
_superClass = null
_superInterfaces = {JavaType[1]@13670}
_bindings = {TypeBindings@13671} "<Lonek/books/backend/model/book/Book;>"
_canonicalName = null
_class = {Class@352} "interface java.util.List"
_hash = -95724352
_valueHandler = null
_typeHandler = null
_asStatic = false
这是我所期望的,因为 Book-Class 属于这种类型。但是如果我添加罐子,构造的类型看起来像:
result = {SimpleType@11757} "[simple type, class java.lang.Object]"
_superClass = null
_superInterfaces = null
_bindings = {TypeBindings@11759} "<>"
_canonicalName = null
_class = {Class@595} "class java.lang.Object"
_hash = 1063877011
_valueHandler = null
_typeHandler = null
_asStatic = false
并且 jackson 将其反序列化为具有此类型的 LinkedHashmap,从而导致 ClassCastException。
但我真的不知道如何从这里继续。外部 jar 可以改变 Jackson TypeFactory 的某些部分吗?
当 Jackson 尝试反序列化未提供类型信息的对象时,它使用 LinkedHashMap
来存储对象属性值。异常可能与此有关。
我猜 fat jar 可能包含与您在项目中包含的版本不同的 Jackson 版本,并且由于某种原因,这种行为有所不同。
我不知道这是否只是问题的不准确,但为了解决问题,请尝试在 TypeReference
:
中提供实际类型
List<Book> books = objectMapper.readValue(getReader("books.json"), new TypeReference<List<Book>>() {});
请考虑阅读 this related article and 。
问题很可能出在“胖 JAR”的创建上。
创建fat JAR时注意以下事项:
META-INF/MANIFEST.MF
应忽略依赖项提供的
module-info.class
和 META-INF/versions/<i><version></i>/module-info.class
提供者依赖关系应该被忽略(后者被Multi-Release JARs使用)
- 应合并
META-INF/services/
下的文件内容(它们声明 providers for services)
- 可选:如果其中一个依赖项是 Multi-Release JARs,您可以在胖 JAR 的
MANIFEST.MF
中设置 Multi-Release: true
以允许 JRE 使用这些版本特定的 类
- 对于所有其他文件,如何处理冲突可能是特定于应用程序的
如果您使用插件生成胖 JAR,那么它可能会提供这些转换的设置(或者可能默认执行它们)。
我正在使用 Jackson 的 Spring 引导应用程序(版本 2.4.5)。我可以添加一个使用 gson 的 fat jar 而不影响应用程序的 Jackson 反序列化吗?
当我将 jar 添加到我的应用程序时,该应用程序到处都使用 gson 来反序列化 JSON。但是由于我使用了 Jackson 的一些特殊功能,所以失败了。
很遗憾,我无法在库中更改它。
我使用Gradle在依赖项中添加这样的fat jar:
implementation fileTree(dir: 'libs', include: ['*.jar'])
我正在像这样构建 Jacksons 对象映射器:
private static ObjectMapper getMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
mapper.registerModule(new JavaTimeModule());
return mapper;
}
下面几行会引发错误:
List<User> users = objectMapper.readValue(getReader("users.json"), new TypeReference<>() {});
java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class User (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; onek.books.backend.model.book.Book is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @445d3853)
并且 Gson 被添加到具有以下 Maven 依赖项的 fat jar 中:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson-version}</version>
</dependency>
<dependency>
<groupId>io.gsonfire</groupId>
<artifactId>gson-fire</artifactId>
<version>${gson-fire-version}</version>
</dependency>
编辑
正如所建议的那样,这不是由于 gson,我试图缩小范围并一一添加所有依赖项,none 本身导致了错误。
但是我可能找到了原因,但我不知道如何解决这个问题。这是 Jacksons typeFactory 构造它的类型的方式。对于行:
List<Book> books = objectMapper.readValue(getReader("books.json"), new TypeReference<>() {});
如果 jar 不存在,构造的类型如下所示:
result = {CollectionType@13667} "[collection type; class java.util.List, contains [simple type, class onek.books.backend.model.book.Book]]"
_elementType = {SimpleType@13669} "[simple type, class onek.books.backend.model.book.Book]"
_superClass = null
_superInterfaces = {JavaType[1]@13670}
_bindings = {TypeBindings@13671} "<Lonek/books/backend/model/book/Book;>"
_canonicalName = null
_class = {Class@352} "interface java.util.List"
_hash = -95724352
_valueHandler = null
_typeHandler = null
_asStatic = false
这是我所期望的,因为 Book-Class 属于这种类型。但是如果我添加罐子,构造的类型看起来像:
result = {SimpleType@11757} "[simple type, class java.lang.Object]"
_superClass = null
_superInterfaces = null
_bindings = {TypeBindings@11759} "<>"
_canonicalName = null
_class = {Class@595} "class java.lang.Object"
_hash = 1063877011
_valueHandler = null
_typeHandler = null
_asStatic = false
并且 jackson 将其反序列化为具有此类型的 LinkedHashmap,从而导致 ClassCastException。
但我真的不知道如何从这里继续。外部 jar 可以改变 Jackson TypeFactory 的某些部分吗?
当 Jackson 尝试反序列化未提供类型信息的对象时,它使用 LinkedHashMap
来存储对象属性值。异常可能与此有关。
我猜 fat jar 可能包含与您在项目中包含的版本不同的 Jackson 版本,并且由于某种原因,这种行为有所不同。
我不知道这是否只是问题的不准确,但为了解决问题,请尝试在 TypeReference
:
List<Book> books = objectMapper.readValue(getReader("books.json"), new TypeReference<List<Book>>() {});
请考虑阅读 this related article and
问题很可能出在“胖 JAR”的创建上。
创建fat JAR时注意以下事项:
META-INF/MANIFEST.MF
应忽略依赖项提供的module-info.class
和META-INF/versions/<i><version></i>/module-info.class
提供者依赖关系应该被忽略(后者被Multi-Release JARs使用)- 应合并
META-INF/services/
下的文件内容(它们声明 providers for services) - 可选:如果其中一个依赖项是 Multi-Release JARs,您可以在胖 JAR 的
MANIFEST.MF
中设置Multi-Release: true
以允许 JRE 使用这些版本特定的 类 - 对于所有其他文件,如何处理冲突可能是特定于应用程序的
如果您使用插件生成胖 JAR,那么它可能会提供这些转换的设置(或者可能默认执行它们)。