2013-04-10 55 views
50

我試圖反序列化使用傑克遜1.9.10這個類的一個實例的重載構造一類:如何反序列化使用JsonCreator

public class Person { 

@JsonCreator 
public Person(@JsonProperty("name") String name, 
     @JsonProperty("age") int age) { 
    // ... person with both name and age 
} 

@JsonCreator 
public Person(@JsonProperty("name") String name) { 
    // ... person with just a name 
} 
} 

當我試試這個,我得到以下

衝突的基於屬性的創造者:已經有... {interface org.codehaus.jackson.annotate.JsonCreator @ org.codehaus.jackson.annotate.JsonCreator()}],遇到...,註釋:{interface org.codehaus。 jackson.annotate.JsonCreator @ org.codehaus.jackson.annotate.JsonCreator()}]

有沒有一種方法可以使用Jackson重載構造函數來反序列化一個類?

謝謝

+4

正如答案所指出的,不,您必須指定一個且唯一的構造函數。在你的情況下,離開那個需要多個參數的那個,這將工作得很好。 「Missing」參數將採用null(對象)或默認值(對於基元)。 – StaxMan 2013-04-10 21:24:56

+0

謝謝。允許多個構造函數將是一個很好的功能。實際上,我的例子有點做作。我試圖使用的對象實際上有完全不同的參數列表,一個是正常創建的,另一個是使用Throwable創建的...我會看看我能做什麼,也許有一個空構造函數和getter/setter可以扔 – geejay 2013-04-11 07:25:39

+0

是的,我確定它會很好,但是規則可以變得相當複雜,具有不同的排列方式。始終可以爲RFE提交新功能和特性。 – StaxMan 2013-04-15 23:12:58

回答

83

雖然沒有正確記錄,但每個類型只能有一個創建者。您可以在您的類型中擁有儘可能多的構造函數,但只有其中一個應具有@JsonCreator註釋。

+20

這是一個相當重要的細節... – Gus 2015-01-23 21:03:23

33

這對傑克遜數據綁定2.7.0仍然適用。

傑克遜@JsonCreator annotation 2.5 javadocJackson annotations documentation語法(構造小號和工廠方法小號)讓認爲確實是一個可以馬克多個構造。

標記註釋,可用於將構造函數和工廠方法定義爲用於實例化關聯類的新實例的標記註釋。

望着在被識別的代碼,它看起來像傑克遜CreatorCollector無視重載構造,因爲它只checks the first argument of the constructor

Class<?> oldType = oldOne.getRawParameterType(0); 
Class<?> newType = newOne.getRawParameterType(0); 

if (oldType == newType) { 
    throw new IllegalArgumentException("Conflicting "+TYPE_DESCS[typeIndex] 
      +" creators: already had explicitly marked "+oldOne+", encountered "+newOne); 
} 
  • oldOne是第一識別構造的創造者。
  • newOne是重載構造函數的創建者。

這意味着,代碼類似將無法​​正常工作

@JsonCreator 
public Phone(@JsonProperty("value") String value) { 
    this.value = value; 
    this.country = ""; 
} 

@JsonCreator 
public Phone(@JsonProperty("country") String country, @JsonProperty("value") String value) { 
    this.value = value; 
    this.country = country; 
} 

assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336"); // raise error here 
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336"); 

但這個代碼將工作:

@JsonCreator 
public Phone(@JsonProperty("value") String value) { 
    this.value = value; 
    enabled = true; 
} 

@JsonCreator 
public Phone(@JsonProperty("enabled") Boolean enabled, @JsonProperty("value") String value) { 
    this.value = value; 
    this.enabled = enabled; 
} 

assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336"); 
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\",\"enabled\":true}", Phone.class).value).isEqualTo("+336"); 

這是一個有點哈克,可能不是面向未來


該文檔對於如何創建對象是模糊的;從我從代碼集,雖然,那就是它可以混合不同的方法:

例如人們可以有註釋與@JsonCreator

@JsonCreator 
public Phone(@JsonProperty("value") String value) { 
    this.value = value; 
    enabled = true; 
} 

@JsonCreator 
public Phone(@JsonProperty("enabled") Boolean enabled, @JsonProperty("value") String value) { 
    this.value = value; 
    this.enabled = enabled; 
} 

@JsonCreator 
public static Phone toPhone(String value) { 
    return new Phone(value); 
} 

assertThat(new ObjectMapper().readValue("\"+336\"", Phone.class).value).isEqualTo("+336"); 
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336"); 
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\",\"enabled\":true}", Phone.class).value).isEqualTo("+336"); 

它的工作原理,但它不是理想的靜態工廠方法。最後它可能是有意義的,例如如果json是dynamic那麼也許應該看看使用委託構造函數來處理負載變化比使用多註釋構造函數更優雅。

還要注意的是傑克遜orders creators by priority,例如在此代碼:

// Simple 
@JsonCreator 
public Phone(@JsonProperty("value") String value) { 
    this.value = value; 
} 

// more 
@JsonCreator 
public Phone(Map<String, Object> properties) { 
    value = (String) properties.get("value"); 

    // more logic 
} 

assertThat(new ObjectMapper().readValue("\"+336\"", Phone.class).value).isEqualTo("+336"); 
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336"); 
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\",\"enabled\":true}", Phone.class).value).isEqualTo("+336"); 

這次傑克遜不會引發錯誤,但傑克遜將只使用委託構造Phone(Map<String, Object> properties),這意味着Phone(@JsonProperty("value") String value)是沒用過。

+3

恕我直言,這應該是被接受的答案,因爲它提供了完整的解釋與很好的例子 – matiou 2017-03-23 20:08:22