2011-12-03 22 views
23

Tôi có một vấn đề deserializing một chuỗi JSON bằng cách sử dụng Jackson (nhưng tôi không có vấn đề serializing một đối tượng để JSON).Deserializing JSON với Jackson - Tại sao JsonMappingException "Không có hàm tạo phù hợp"?

Dưới đây tôi trình bày các lớp tôi sử dụng. vấn đề này được đưa ra khi tôi rececive một JSON-string (một ProtocolContainer đã được đăng ở nơi khác và lấy thông qua webservice) và muốn deserialize nó:

JSON-chuỗi:

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

tôi cố gắng deserialize như điều này:

ProtocolContainer ret = ProtocolContainer.Create(jsonString); 

và mã thực hiện trong ProtocolContainer có thể xem bên dưới. Ngoại lệ:

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]

Tôi thực sự đánh giá cao một số đầu vào tại đây =) Thx!

ProtocolContainer.java - một lớp container mà đóng gói của tôi "SubPackets":

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 - một lớp cha cho tất cả datapackets tôi

public class DataPacket 
{ 

} 

LoginRequestReply. java - một DataPacket

package MyPackage.DataPackets; 

import MyPackage.DataPacket; 

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

Theo dõi: Sau khi một số điều phiền toái, tôi không nhận được lỗi sau: * JsonMappingException: Không thể khởi tạo giá trị kiểu [loại đơn giản, lớp MyPackage.ProtocolContainer] từ chuỗi JSON; không có hàm tạo chuỗi đơn/phương thức factory *. Nếu tôi thêm một constructor mà có một String, sau đó không có lỗi nhưng Object là "trống rỗng" ... Tôi không nghĩ rằng nó cần thiết để thêm hỗ trợ thực hiện trong constructor. ** Tôi nên sửa lỗi này như thế nào? ** – Ted

Trả lời

31

Các thông báo lỗi cho biết tất cả, ProtocolContainer của bạn không có hàm tạo mặc định nên Jackson không thể tạo một thể hiện của nó. (Vì cách duy nhất để tạo ProtocolContainer là bằng cách chuyển vào một DataPacket.)

+1

có, tôi đã thêm một hàm tạo rỗng. Lạ lùng của nó, vì tôi đã có một lỗi khác trước đây, khi tôi có một nhà xây dựng trống ... Dù sao, vấn đề đặc biệt này được giải quyết ... không có tôi phải đối phó với điều "__type" mà .NET thêm vào serialization ... – Ted

+0

Hmm, do đó, lỗi đã trở lại, sắp xếp. Bây giờ tôi nhận được điều này: * JsonMappingException: Không thể khởi tạo giá trị kiểu [loại đơn giản, lớp MyPackage.ProtocolContainer] từ chuỗi JSON; không có hàm tạo chuỗi đơn/phương thức factory *. Nếu tôi thêm một constructor mà có một String, sau đó không có lỗi nhưng đối tượng là "trống" ... Tôi không nghĩ rằng nó cần thiết để thêm hỗ trợ thực hiện trong constructor ... – Ted

+0

Tôi quên đặt constructor mặc định, bây giờ nó hoạt động, nhờ ^^ – bzhWarrior

15

Trong trường hợp này, bạn có thể thêm chú thích @JsonCreator vào hàm tạo. Có hai cách có thể thực hiện:

  • Nếu bạn chỉ thêm chú thích đó, thì toàn bộ JSON khớp đầu tiên được ràng buộc để nhập đối số duy nhất (`DataPacket '). Tôi cho rằng bạn không muốn làm điều đó.
  • Nếu bạn cũng thêm @JsonProperty chú thích trước khi cãi nhau, sau đó bất động sản phù hợp với tên đó JSON được truyền cho constructor (chú thích là bắt buộc vì Java byte code KHÔNG chứa tên của phương pháp hoặc constructor đối số) - Tôi nghi ngờ bạn muốn @JsonProperty("SubPacket")

Điều này hoạt động nếu thông tin cần thiết cho hàm khởi tạo đến từ JSON. Nếu không, bạn cần phải thêm hàm tạo no-arg thay thế.

Nhân tiện, thông báo lỗi có vẻ sai trong trường hợp này. Nó chỉ nên được đưa ra nếu dữ liệu JSON khớp với giá trị kỳ vọng nếu một chuỗi JSON.

2

Quy tắc ngón tay cái: Thêm hàm tạo mặc định cho từng lớp bạn sử dụng làm lớp ánh xạ. Bạn đã bỏ lỡ vấn đề này và phát sinh!

Chỉ cần thêm một hàm tạo mặc định và nó sẽ hoạt động.

+0

Không ai trong số các câu trả lời ở trên là chính xác, điều duy nhất mà làm việc cho tôi là \t ConsolidationUserAndManagerCredentialsRequest công cộng() { \t \t siêu(); \t} Không có 'super()' nào hoạt động. – Siddharth

1

Tôi đang gặp sự cố và không có câu trả lời nào phù hợp với tôi. có vẻ như trường hợp ngoại lệ được ném ra là rất chung chung và được ném cho n số nguyên nhân. Vì vậy, một sửa chữa có thể không làm việc cho tất cả mọi người. Trường hợp của tôi: chúng tôi có phản hồi json trong đó thẻ tín dụng là loại phức tạp nhưng không bắt buộc. khi không có dữ liệu creditcard, chúng tôi đã nhận được một chuỗi rỗng trong phản ứng:

"creditcard": ""

Nhưng Thẻ tín dụng là một loại phức tạp đối với chúng tôi:

<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> 

Chúng tôi đã tìm ra , nếu không có dữ liệu creditcard, chúng ta nên có một cái gì đó như thế này trong phản ứng json:

"creditcard": {}

và không "creditcard": ""

nó đã khắc phục sự cố này.

1

Một khả năng khác nếu bạn sử dụng Lombok! Tôi đã không tìm ra lý do.

@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; 
     } 
    } 
    ... 
} 

Nếu chú thích hàm tạo lombok được sử dụng ở lớp ngoài, lớp bên trong ngay cả khi viết tất cả hàm tạo args theo cách thủ công, nó vẫn không thể tìm thấy hàm tạo. Nếu bạn sử dụng @AllArgsConstructor trên Maintenance thay vì viết của riêng bạn, jackson sẽ deserialise thành công. Tôi đã có cùng trải nghiệm ngày hôm nay, thêm @AllArgsConstructor giải quyết nó.

Các vấn đề liên quan