Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing JSON with Jackson - Why JsonMappingException "No suitable constructor"?

Tags:

I have a problem deserializing a JSON string using Jackson (but I have no problem serializing an object to JSON).

Below I present the classes I use. The problem comes when I rececive a JSON-string (a ProtocolContainer that was serialized elsewhere and retrieved via webservice) and want to de-serialize it:

JSON-string:

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

I try to deserialize like this:

ProtocolContainer ret = ProtocolContainer.Create(jsonString); 

and the code that executes in ProtocolContainer can be seen below. The exception:

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: java.io.StringReader@4059dcb0; line: 1, column: 2]

ProtocolContainer.java - a container class that encapsulates my "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 - a superclass for all my 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; } 
like image 757
Ted Avatar asked Dec 03 '11 11:12

Ted


People also ask

Does Jackson need default constructor?

Jackson uses default (no argument) constructor to create object and then sets value using setters. so you only need @NoArgsConstructor and @Setter.

How does Jackson read nested JSON?

A JsonNode is Jackson's tree model for JSON and it can read JSON into a JsonNode instance and write a JsonNode out to JSON. To read JSON into a JsonNode with Jackson by creating ObjectMapper instance and call the readValue() method. We can access a field, array or nested object using the get() method of JsonNode class.

What is JSON mapping exception?

public class JsonMappingException extends JsonProcessingException. Checked exception used to signal fatal problems with mapping of content, distinct from low-level I/O problems (signaled using simple IOException s) or data encoding/decoding problems (signaled with JsonParseException , JsonGenerationException ).

What is the use of Jackson ObjectMapper?

ObjectMapper is the main actor class of Jackson library. ObjectMapper class ObjectMapper provides functionality for reading and writing JSON, either to and from basic POJOs (Plain Old Java Objects), or to and from a general-purpose JSON Tree Model (JsonNode), as well as related functionality for performing conversions.


2 Answers

The error messages says it all, your ProtocolContainer does not have a default constructor so Jackson is unable to create an instance of it. (Since the only current way of creating a ProtocolContainer is by passing in a DataPacket.)

like image 86
Ola Herrdahl Avatar answered Oct 02 '22 09:10

Ola Herrdahl


In this case, you could add @JsonCreator annotation to constructor. There are two ways it could be done:

  • If you only add that annotation, then the whole matching JSON is first bound to type of the only argument (`DataPacket'). I assume you do not want to do that.
  • If you also add @JsonProperty annotation before the argument, then JSON property matching that name is passed to constructor (annotation is mandatory because Java byte code does NOT contain name of method or constructor arguments) -- I suspect you want @JsonProperty("SubPacket")

This works if necessary information for constructor comes from JSON. If not, you do need to add alternate no-arg constructor.

By the way, the error message does sound wrong in this case. It should only be given if JSON data matching expected value if a JSON String.

like image 45
StaxMan Avatar answered Oct 02 '22 09:10

StaxMan