用Jackson反序列化JSON – 为什么JsonMappingException“没有合适的构造函数”?

我在使用Jackson反序列化JSON字符串时遇到问题(但我将对象序列化为JSON没有问题)。

下面我介绍我使用的课程。 当我接收一个JSON字符串(一个在其他地方序列化并通过webservice检索的ProtocolContainer)并想要反序列化它时,问题出现了:

JSON字符串:

{ “DataPacketJSONString”:NULL, “DataPacketType”: “MyPackage.DataPackets.LoginRequestReply”, “的MessageId”:6604, “SenderUsername”:NULL, “子分组”:{ “__类型”: “LoginRequestReply:#MyPackage.DataPackets”,”原因“:”错误的通行证或用户名“,”成功“:false,”用户名“:”用户1“}}

我试着像这样反序列化:

ProtocolContainer ret = ProtocolContainer.Create(jsonString); 

并且可以在下面看到在ProtocolContainer中执行的代码。 例外:

org.codehaus.jackson.map.JsonMappingException:找不到类型[simple type,class MyPackage.ProtocolContainer]的合​​适构造函数:无法在[Source:java.io.]中从JSON对象实例化(需要添加/启用类型信息?)。 StringReader @ 4059dcb0; line:1,column:2]

我真的很感激这里的一些输入=)Thx!

ProtocolContainer.java – 封装我的“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 – 我所有数据包的超类

 public class DataPacket { } 

LoginRequestReply.java – 一个DataPacket

 package MyPackage.DataPackets; import MyPackage.DataPacket; public class LoginRequestReply extends DataPacket { public boolean LoginOK; public int UserId; } 

错误消息说明了一切,您的ProtocolContainer没有默认构造函数,因此Jackson无法创建它的实例。 (因为创建ProtocolContainer的唯一当前方法是传入DataPacket。)

在这种情况下,您可以将@JsonCreator注释添加到构造函数中。 有两种方法可以做到:

  • 如果只添加该注释,那么整个匹配的JSON首先绑定到唯一参数的类型(`DataPacket’)。 我假设你不想这样做。
  • 如果你还在参数之前添加@JsonProperty注释,那么匹配该名称的JSON属性将传递给构造函数(注释是必需的,因为Java字节代码不包含方法或构造函数参数的名称) – 我怀疑你想要@JsonProperty("SubPacket")

如果构造函数的必要信息来自JSON,则此方法有效。 如果没有,则需要添加备用no-arg构造函数。

顺便说一下,在这种情况下错误消息确实是错误的。 如果JSON数据与JSON字符串匹配期望值,则应该给出它。

Thumb Rule :为您用作映射类的每个类添加默认构造函数。 你错过了这个,问题就出现了!

只需添加默认构造函数即可。

我正面临这个问题,没有一个答案对我有用。 似乎抛出的exception是非常通用的,并且被抛出了n个原因。 因此,一个修复可能不适合每个人。 我的情况:我们有一个json响应,其中creditcard是一个复杂的类型,但是可选的。 当没有信用卡数据时,我们得到一个空字符串作为回应:

“信用卡”:””

但信用卡对我们来说是一种复杂的类型:

          

我们想通了,如果没有信用卡数据,我们应该在json响应中有类似的东西:

“信用卡”:{}

而不是“信用卡”:“”

它解决了这个问题。

如果你使用龙目岛的另一种可能性! 我没有找到原因。

 @Getter @NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public Car implements Serializable { Map basicInfo; CarEnums.TypeEnum type; List 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; } } ... } 

如果在外部类中使用了lombok构造函数注释,那么内部类即使手动编写所有args构造函数,它仍然会抱怨构造函数无法找到。 如果你在Maintenance上使用@AllArgsConstructor而不是自己编写,jackson会成功反序列化。 我今天获得了同样的经验,添加@AllArgsConstructor解决了它。