2011-12-03 45 views
23

我有一個問題反序列化使用傑克遜的JSON字符串(但我沒有問題序列化對象到JSON)。用Jackson反序列化JSON - 爲什麼JsonMappingException「沒有合適的構造函數」?

下面我介紹我使用的類。問題是當我rececive一個JSON字符串(這是其他地方的序列化,並通過Web服務檢索的ProtocolContainer),並希望反序列化:

JSON字符串:

{"DataPacketJSONString":null,"DataPacketType":"MyPackage.DataPackets.LoginRequestReply","MessageId":6604,"SenderUsername":null,"SubPacket":{"__type":"LoginRequestReply:#MyPackage.DataPackets","Reason":"Wrong pass or username","Success":false,"Username":"User1"}}

我嘗試類似反序列化這個:

ProtocolContainer ret = ProtocolContainer.Create(jsonString); 

和在ProtocolContainer中執行的代碼可以在下面看到。例外:

org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class MyPackage.ProtocolContainer]: can not instantiate from JSON object (need to add/enable type information?) at [Source: [email protected]; line: 1, column: 2]

我真的很感激這裏的一些輸入=)Thx!

ProtocolContainer.java - 封裝我的 「子包」 容器類:

import java.io.IOException; 

import org.codehaus.jackson.JsonGenerationException; 
import org.codehaus.jackson.JsonParseException; 
import org.codehaus.jackson.map.JsonMappingException; 
import org.codehaus.jackson.map.ObjectMapper; 

import MyPackage.DataPackets.*; 

public class ProtocolContainer 
{ 
    public String SenderUsername; 
    public String DataPacketType; 
    public long MessageId; 
    public String DataPacketJSONString; 
    public DataPacket SubPacket; 

    public ProtocolContainer(DataPacket dp) 
    { 
     DataPacketType = dp.getClass().toString().substring(6); 
     SubPacket = dp; 
    } 

    public String toJSON() 
    { 
     try { 
      if (SubPacket != null) 
       this.DataPacketJSONString = ProtocolContainer.mapper.writeValueAsString(SubPacket); 

      return ProtocolContainer.mapper.writeValueAsString(this); 
     } catch (JsonGenerationException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (JsonMappingException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    public static ObjectMapper mapper = new ObjectMapper(); 

    public static ProtocolContainer Create(String jsonString) 
    { 
     ProtocolContainer pc = null; 
     try { 
      pc = mapper.readValue(jsonString, ProtocolContainer.class); // error here! 
     } catch (JsonParseException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (JsonMappingException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); // Exception when deserializing 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 


     try 
     { 
      if (pc != null && pc.DataPacketType == "LoginRequest") 
       pc.SubPacket = mapper.readValue(jsonString, LoginRequest.class); 
    } 
     catch (JsonParseException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (JsonMappingException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
     } 
     return pc; 
    } 
} 

DataPacket.java - 我所有的datapackets

public class DataPacket 
{ 

} 

LoginRequestReply一個超類。 java - a DataPacket

package MyPackage.DataPackets; 

import MyPackage.DataPacket; 

public class LoginRequestReply extends DataPacket 
{ 
    public boolean LoginOK; 
    public int UserId; 
} 
+1

後續:經過一些搞亂之後,我沒有收到以下錯誤: * JsonMappingException:無法從JSON字符串實例化[simple type,class MyPackage.ProtocolContainer]的值;沒有單個字符串的構造函數/工廠方法*。如果我添加一個構造函數接受一個字符串,那麼沒有錯誤,但對象是「空的」......我不認爲應該有必要在構造函數中添加實現支持。 **我應該如何解決這個問題?** – Ted

回答

31

錯誤消息說明了一切,您的ProtocolContainer沒有默認構造函數,因此Jackson無法創建它的實例。 (因爲創建ProtocolContainer的唯一當前方式是傳入一個DataPacket。)

+1

是的,我添加了一個空構造函數。它的奇怪,因爲我得到了另一個錯誤之前,當我有一個空的構造函數...無論如何,這個特定的問題已解決...不,我不得不處理.NET的序列化...添加「__type」... – Ted

+0

嗯,所以錯誤又回來了,有點。現在我明白了: * JsonMappingException:無法從JSON字符串實例化[simple type,class MyPackage.ProtocolContainer]的值;沒有單個字符串的構造函數/工廠方法*。如果我添加一個構造函數接受一個字符串,那麼沒有錯誤,但對象是「空的」...我不認爲應該有必要在構造函數中添加實現支持... – Ted

+0

我忘了把默認的構造函數,現在它的工作原理,謝謝^^ – bzhWarrior

15

在這種情況下,您可以將@JsonCreator註釋添加到構造函數中。有兩種方法可以完成:

  • 如果只添加該註釋,那麼整個匹配的JSON首先綁定到唯一參數類型(`DataPacket')。我假定你不想這樣做。
  • 如果您還前面的參數添加@JsonProperty批註,則JSON物業配套這個名字傳遞給構造函數(註釋是強制性的,因爲Java字節代碼不包含的方法或構造函數的參數名稱) - 我懷疑你想@JsonProperty("SubPacket")

如果必要,構造函數的信息來自JSON。如果沒有,你需要添加可選的無參數構造函數。

順便說一句,在這種情況下,錯誤信息聽起來不對。如果JSON字符串與JSON數據匹配期望值,那麼只能給出它。

2

Thumb規則:爲每個用作映射類的類添加默認構造函數。你錯過了這個問題出現了!

只需添加一個默認的構造函數,它應該工作。

+0

上述答案都是正確的,只是爲我工作的事情是 \t公共ConsolidationUserAndManagerCredentialsRequest(){ \t \t超(); \t} 沒有'super()'沒有什麼作用。 – Siddharth

1

我正面臨着這個問題,沒有答案爲我工作。它似乎拋出的異常是非常通用的,並引發n個原因。所以一個修復程序可能不適合每個人。 我的情況: 我們有一個json響應,其中信用卡是一個複雜類型,但可選。當沒有的信用卡數據,我們是在響應得到一個空字符串:

「的信用卡」:「」

但信用卡對我們來說是一個複雜類型:

<xs:element name="CC" minOccurs="0"> 
           <xs:complexType> 
            <xs:sequence> 
             <xs:element name="aaa" type="xs:string" minOccurs="0"/> 
             <xs:element name="bbb" type="xs:string" minOccurs="0"/> 
             <xs:element name="ccc" type="xs:string" minOccurs="0"/> 
            </xs:sequence> 
           </xs:complexType> 
          </xs:element> 

我們想通了,如果沒有的信用卡數據,我們應該有這樣的事情在JSON響應:

「的信用卡」:{}

,而不是「的信用卡」:「」

它修復了這個問題。

1

另一種可能性,如果你使用龍目島!我沒有找到原因。

@Getter 
@NoArgsConstructor 
@FieldDefaults(level = AccessLevel.PRIVATE) 
public Car implements Serializable { 
    Map<String, Object> basicInfo; 
    CarEnums.TypeEnum type; 
    List<Maintenance> maintenances; 
    public void addMaintenance(Maintenance m) { 
     // initialize if null 
     maintenances.add(m); 
    } 

    // must be static or jackson throws "inner class cannot be static" exception. Yes you see it right. 
    public static class Maintenance { 
     private Long id; 
     public class Maintenance(Long id) { // constructor causes the exception 
     this.id = id; 
     } 
    } 
    ... 
} 

如果龍目島構造標註在外部類中,內部類,即使一個手動寫入所有參數的構造,它仍然抱怨構造函數無法找到。如果您在Maintenance上使用@AllArgsConstructor而不是自己寫,jackson會成功反序列化。今天我得到了同樣的體驗,加入@AllArgsConstructor解決了它。

相關問題