Jackson JDK8 Data Type モジュールは、JDK8 を要求し、JDK8 に関する特定のユースケースを解決することを考えると、少し驚くべきように、パラメータ名モジュールを時々無視するようです。
ここでの問題は、パラメーター名を明示的に指定せずに JSON デシリアライゼーションを機能させる方法を見つけることができなかったことです (これは、パラメーター名モジュールがすべてであると想定されているものです)。また、コンテナー オブジェクト コンストラクターで JDK8 固有の型 ( Optional<T>
) を渡そうとした場合にのみ、この動作が発生します (つまり、通常、これは機能し、私はそれをテストしました)。コードは javac パラメータでコンパイルされます-parameters
。
問題は、どのようにして Parameter Names モジュールを活用できるようにするか (つまり、コンストラクターで注釈 + 値を指定する必要がなく、引数名でプロパティ名を把握できるようにすること) です。
私は間違っているかもしれませんし、ボンネットの下のコードを見ていないので、見逃しているものがあれば教えてください.
この簡単な例を考えてみましょう。
バージョン スタック (この記事の執筆時点でのすべての最新バージョン):
private val jacksonVer = "2.6.1"
private val jacksonCore: ModuleID = "com.fasterxml.jackson.core" % "jackson-core" % jacksonVer withSources() withJavadoc()
private val jacksonDataBind: ModuleID = "com.fasterxml.jackson.core" % "jackson-databind" % jacksonVer withSources() withJavadoc()
private val jacksonAnnotations: ModuleID = "com.fasterxml.jackson.core" % "jackson-annotations" % jacksonVer withSources() withJavadoc()
private val jacksonParamNames: ModuleID = "com.fasterxml.jackson.module" % "jackson-module-parameter-names" % "2.6.2" withSources() withJavadoc()
private val jacksonJdk8DataType: ModuleID = "com.fasterxml.jackson.datatype" % "jackson-datatype-jdk8" % "2.4.3" withSources() withJavadoc()
容器:
private static class SimpleTest {
@JsonProperty private Optional<String> s1;
@JsonProperty private Optional<String> s2;
@JsonProperty private Map<String, String> map;
private SimpleTest(@JsonProperty("s1") Optional<String> s1, @JsonProperty("s2") Optional<String> s2, @JsonProperty("map") Map<String, String> map) {
this.s1 = s1;
this.s2 = s2;
this.map = map;
}
static SimpleTest of(Optional<String> s1, Optional<String> s2, Map<String, String> m) {
return new SimpleTest(s1, s2, m);
}
}
シリアライゼーション:
@Test
public void testSer() throws JsonProcessingException {
SimpleTest test = SimpleTest.of(Optional.of("a"), Optional.empty(), Collections.emptyMap());
System.out.println(JacksonUtil.getMapper().writeValueAsString(test));
}
逆シリアル化:
@Test
public void testDeser() throws IOException {
String json = "{\n" +
" \"s1\" : \"a\",\n" +
" \"map\" : { }\n" +
"}";
JacksonUtil.getMapper().readValue(json, SimpleTest.class);
}
testSer()
このようなコンテナーで実行すると、次の結果が得られます。
{
"s1" : "a",
"s2" : null,
"map" : { }
}
testDeser()
このような入力で実行する
{
"s1" : "a",
"map" : { }
}
も機能し、期待される結果 (s1
値s2
がOptional.empty
あり、map
空である) が生成されますが、コンテナー コンストラクターが上記のように定義されている場合に限ります。次の組み合わせでは動作しませんでした: 1
)
private SimpleTest(Optional<String> s1, Optional<String> s2, Map<String, String> map) {...}
2)
private SimpleTest(@JsonProperty Optional<String> s1, @JsonProperty Optional<String> s2, @JsonProperty Map<String, String> map) {...}
本来、どちらも機能するはずですが、そうではありません。どちらのアプローチでも、次のスタックトレースが生成されます。
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com._3esi.load.bootstrap.ScratchPad$SimpleTest]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: {
"s1" : "a",
"map" : { }
}; line: 2, column: 3]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1106)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:294)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:131)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3731)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2724)
ここで何が欠けていますか?