【发布时间】:2018-05-14 05:35:56
【问题描述】:
是否可以使用 Jackson 反序列化为具有私有字段和自定义参数构造函数的类而不使用注释和修改类?
我知道在 Jackson 中使用这种组合是可能的:1) Java 8,2) 使用“-parameters”选项编译,3) 参数名称与 JSON 匹配。但在 GSON 中也有可能默认情况下没有所有这些限制。
例如:
public class Person {
private final String firstName;
private final String lastName;
private final int age;
public Person(String firstName, String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
public static void main(String[] args) throws IOException {
String json = "{firstName: \"Foo\", lastName: \"Bar\", age: 30}";
System.out.println("GSON: " + deserializeGson(json)); // works fine
System.out.println("Jackson: " + deserializeJackson(json)); // error
}
public static Person deserializeJackson(String json) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
return mapper.readValue(json, Person.class);
}
public static Person deserializeGson(String json) {
Gson gson = new GsonBuilder().create();
return gson.fromJson(json, Person.class);
}
}
这对 GSON 很有效,但杰克逊会抛出:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `jacksonParametersTest.Person` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{firstName: "Foo", lastName: "Bar", age: 30}"; line: 1, column: 2]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
这在 GSON 中是可能的,所以我希望在 Jackson 中必须有某种方法,而无需修改 Person 类,无需 Java 8,也无需显式自定义反序列化器。有人知道解决办法吗?
- 更新,附加信息
Gson 似乎跳过了参数构造函数,所以它必须在幕后使用反射创建一个无参数构造函数。
此外,即使没有“-parameters”编译器标志,也有一个 Kotlin Jackson module 能够为 Kotlin 数据类执行此操作。 所以奇怪的是,Java Jackson 似乎不存在这样的解决方案。
这是 Kotlin Jackson 中可用的(又好又干净的)解决方案(IMO 也应该通过自定义模块在 Java Jackson 中可用):
val mapper = ObjectMapper()
.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
.registerModule(KotlinModule())
val person: Person = mapper.readValue(json, Person::class.java)
【问题讨论】:
-
为
person创建一个空的构造函数 -
但这需要修改类。我的问题是这是否可能不修改它,就像 Gson 一样。 (我会在我的问题中更明确地说明这一点。)
-
所以你不想注释类,你不想使用参数名称解决方案,你不想自定义反序列化器。在我尝试写答案之前还有什么其他的吗?
-
不是真的,我也没有对问题添加新的要求。情况基本上是:您的代码库之外有大量不可变的类,如何在没有样板代码的情况下有效地反序列化它们。解决方案可能在于尚不存在的自定义 Jackson 模块,或者使用“-parameter”标志。 (这个标志很麻烦,因为 1)它需要重新编译和 2)IntelliJ 忽略 Maven 编译器标志。但我已接受 Kotlin Jackson 模块作为我项目的解决方案。
-
@Kalaiselvan,我赞成您的评论,因为它对我的同事有用。但是我没有提供默认/空构造函数,我仍然能够解决它。唯一的区别是我使用的是 Windows 10,而他使用的是 Mac。
标签: java json jackson jackson2 jackson-databind