Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON parse error: Can not construct instance of io.starter.topic.Topic

Im learning Spring Boot and I made a demo but when I POST a request to add a Object it didn't work!

The error message is:

{     "timestamp": 1516897619316,     "status": 400,     "error": "Bad Request",     "exception": "org.springframework.http.converter.HttpMessageNotReadableException",     "message": "JSON parse error: Can not construct instance of io.starter.topic.Topic: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of io.starter.topic.Topic: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)\n at [Source: java.io.PushbackInputStream@1ff3f09a; line: 2, column: 9]",     "path": "/topics/" } 

My Entity:

public class Topic {     private String id;     private String name;     private String author;     private String desc;      public Topic(String id, String name, String author, String desc) {          this.id = id;         this.name = name;         this.author = author;         this.desc = desc;     }     //getters and setters 

My controller:

public class TopicController {      @Autowired     private TopicService topicService;       @RequestMapping(value = "/topics", method = RequestMethod.POST)     public void addTopic(@RequestBody Topic topic) {         topicService.addTopic(topic);     } 

My service:

@Service public class TopicService {     private List<Topic> topics = new ArrayList<>(Arrays.asList(             new Topic("1", "topic1", "Martin", "T1"),             new Topic("2", "topic2", "Jessie", "T2")               ));        public void addTopic(Topic topic) {          topics.add(topic);     }  } 

My json:

{     "id": "3",     "name": "topic3",     "author": "Jessie3",     "desc": "T3" } 

Please Help !

like image 802
hackerang Avatar asked Jan 25 '18 16:01

hackerang


2 Answers

For deserialisation purposes Topic must have a zero-arg constructor.

For example:

public class Topic {     private String id;     private String name;     private String author;     private String desc;      // for deserialisation     public Topic() {}          public Topic(String id, String name, String author, String desc) {             this.id = id;         this.name = name;         this.author = author;         this.desc = desc;     }      // getters and setters  }      

This is the default behaviour of the Jackson library.

like image 154
glytching Avatar answered Sep 17 '22 14:09

glytching


You need to annotate the constructor with @JsonCreator:

Marker annotation that can be used to define constructors and factory methods as one to use for instantiating new instances of the associated class.

NOTE: when annotating creator methods (constructors, factory methods), method must either be:

  • Single-argument constructor/factory method without JsonProperty annotation for the argument: if so, this is so-called "delegate creator", in which case Jackson first binds JSON into type of the argument, and then calls creator. This is often used in conjunction with JsonValue (used for serialization).
  • Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to

Also note that all JsonProperty annotations must specify actual name (NOT empty String for "default") unless you use one of extension modules that can detect parameter name; this because default JDK versions before 8 have not been able to store and/or retrieve parameter names from bytecode. But with JDK 8 (or using helper libraries such as Paranamer, or other JVM languages like Scala or Kotlin), specifying name is optional.

Like this:

@JsonCreator public Topic(@JsonProperty("id") String id, @JsonProperty("name") String name,              @JsonProperty("author") String author, @JsonProperty("desc") String desc) {     this.id = id;     this.name = name;     this.author = author;     this.desc = desc; } 
like image 30
Andreas Avatar answered Sep 19 '22 14:09

Andreas