2015-09-22 24 views
4

在我看來,傑克遜JDK8數據類型模塊偶爾會忽略參數名稱模塊,這似乎有點令人驚訝,因爲它們都需要JDK8並解決具體使用情況到JDK8。傑克遜JDK8數據類型和參數名稱模塊不能一起玩

這裏的問題是我找不到一個方法來使JSON反序列化工作沒有明確指定參數名稱(這是參數名稱模塊應該是什麼)。只有當試圖在容器對象構造函數中傳遞特定於JDK8的類型(Optional<T>)時(即,通常,這可以工作,並且我已經測試過),它也表現出這種行爲。該代碼使用javac參數-parameters進行編譯。

問題是 - 如何使它工作,以便我可以利用參數名稱模塊(即不需要在構造函數中指定註釋+值,並讓它通過參數名稱找出屬性名稱)?

我可能被誤認爲沒有看過引擎蓋下的代碼,所以我想聽聽是否有一些我錯過了。

讓我們考慮這個簡單的例子。

版本堆棧(所有最新版本撰寫本文時):

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具有價值,s2Optional.emptymap是空),但前提是容器構造函數的定義如上。我把它在下列組合工作:
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) 

我在這裏錯過了什麼?

+0

查看其他討論[here](https://github.com/FasterXML/jackson-module-parameter-names/issues/26)和[here](https://github.com/FasterXML/jackson-datatype -jdk8 /問題/ 16)。 – quantum

回答

3

我認爲這是由於傑克遜2.6關於檢測多參數構造函數的一個剩餘問題:儘管檢測到參數名稱,但是不使用@JsonCreator註釋來標記構造函數本身作爲候選。 這是希望能夠解決2。7(原本應該固定爲2.6),但暫時是必要的。

如果您將@JsonCreator添加到構造函數並刪除@JsonProperty註釋,事情應該按預期工作。在Github上

+1

感謝您的回覆和努力 - 您的方法可行,實際上整個問題可能是一個騙局/ IDE,因爲我發現編譯設置中無法解釋的javac參數。更重要的是 - 反序列化不需要任何註釋,它只是起作用。 – quantum

2

CP我的回答:

我測試過下面的代碼和測試通過:

public class OptionalTest { 

    @Test 
    public void shouldDeserialize() throws IOException { 

     // given 
     ObjectMapper objectMapper = new ObjectMapper(); 
     objectMapper.registerModule(new Jdk8Module()); 
     objectMapper.registerModule(new ParameterNamesModule()); 

     // when 
     String json = "{\"s1\":\"a\",\"map\":{}}"; 
     SimpleTest simpleTest = objectMapper.readValue(json, SimpleTest.class); 

     then(simpleTest).isEqualToComparingFieldByField(new SimpleTest(Optional.of("a"), Optional.empty(), new HashMap<>())); 
    } 

    private static class SimpleTest { 
     private Optional<String> s1; 
     private Optional<String> s2; 
     private Map<String, String> map; 

     private SimpleTest(Optional<String> s1, Optional<String> s2, 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); 
     } 
    } 
} 

請注意,這是針對最新的狀態在傑克遜參數名稱模塊測試所有依賴設置爲2.6.2。

+1

我可以在我的終端上確認測試通過 - 很可能我們是在追逐鬼,因爲這看起來像是一個IDE問題('-parameters' javac選項已從編譯器選項中消失)。感謝您的幫助和時間給你們倆。 – quantum

+1

序列化也可以,忘記將其包含在上面的代碼中。 :) – lpandzic