我在使用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:没有合适的构造函数 找到类型[简单类型,类 MyPackage.ProtocolContainer]:不能 从JSON对象实例化(需要添加/启用类型信息?) 在[来源:java.io.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;
}
答案 0 :(得分:31)
错误消息说明了一切,您的ProtocolContainer没有默认构造函数,因此Jackson无法创建它的实例。 (因为创建ProtocolContainer的唯一当前方法是传入DataPacket。)
答案 1 :(得分:15)
在这种情况下,您可以向构造函数添加@JsonCreator
注释。有两种方法可以做到:
@JsonProperty
注释,那么匹配该名称的JSON属性将传递给构造函数(注释是必需的,因为Java字节代码不包含方法或构造函数参数的名称) - 我怀疑你想要@JsonProperty("SubPacket")
如果构造函数的必要信息来自JSON,则此方法有效。如果没有,则需要添加备用no-arg构造函数。
顺便说一句,在这种情况下,错误消息确实是错误的。如果JSON数据与JSON字符串匹配期望值,则应该给出它。
答案 2 :(得分:2)
Thumb Rule :为您用作映射类的每个类添加默认构造函数。你错过了这个,问题出现了!
只需添加默认构造函数即可。
答案 3 :(得分:1)
我遇到了这个问题,没有一个答案对我有用。似乎抛出的异常是非常通用的,并且被抛出了n个原因。因此,一个修复可能不适合每个人。 我的情况: 我们有一个json响应,其中creditcard是一个复杂类型但是可选的。当没有信用卡数据时,我们得到一个空字符串作为回应:
“的信用卡”: “”
但信用卡对我们来说是一种复杂的类型:
<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响应中有类似的东西:
“的信用卡”:{}
而不是“信用卡”:“”
它解决了这个问题。
答案 4 :(得分:1)
如果您使用 Lombok ,则另一种可能性!我还没找到原因。
@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;
}
}
...
}
如果在外部类中使用了lombok构造函数注释,那么内部类即使手动编写所有args构造函数,它仍然会抱怨构造函数无法找到。如果您在@AllArgsConstructor
上使用Maintenance
而不是自己编写,杰克逊会成功解串。我今天获得了相同的体验,添加@AllArgsConstructor
解决了它。