JSON.decodeValue Decode Exception - java

I want to make this java code works:
RequestManager rm = Json.decodeValue(request.getBodyAsString(), RequestManager.class);
But i have this error:
io.vertx.core.json.DecodeException: Failed to decode:No suitable constructor found for type [simple type, class RequestManager]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: {"messageId":"fsdfsdf"}; line: 1, column: 2]
And here the code of my class :
public class RequestManager {
private String messageId;
private String messageContent;
public RequestManager(String messageId, String messageContent) {
this.messageId = messageId;
this.messageContent = messageContent;
}
public String getMessageId() {
return messageId;
}
public String getMessageContent() {
return messageContent;
}
}
I really don't know why it's not working and there is only few topics about it, but they were irrelevant.
Someone can help ?
EDIT--
I know have the RequestManager class like this:
public class RequestManager {
private String messageId;
private String messageContent;
public RequestManager(String messageId, String messageContent) {
this.messageId = messageId;
this.messageContent = messageContent + "check";
}
public RequestManager() {
}
public String getMessageId() {
return messageId;
}
public String getMessageContent() {
return messageContent;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public void setMessageContent(String messageContent) {
this.messageContent = messageContent;
}
}
But know when i try to print the fields of my RequestManager object created with the JSON.decodeValue it's return me null. I've already done that in the past and had the same error. I think it's because the empty constructor is used instead.
I still don't really understand....
EDIT--2
I have tried to change my class again, here it is:
#JsonIgnoreProperties(ignoreUnknown=true)
public class RequestManager {
#JsonProperty("messageId") private String messageId;
#JsonProperty("messageContent") private String messageContent;
#JsonCreator
public RequestManager(#JsonProperty("messageId") String messageId, #JsonProperty("messageContent") String messageContent) {
this.messageId = messageId;
this.messageContent = messageContent;
System.out.println("This constructor is used.");
}
public RequestManager() {
}
public String getMessageId() {
return messageId;
}
public String getMessageContent() {
return messageContent;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public void setMessageContent(String messageContent) {
this.messageContent = messageContent;
}
}
And this is in my main :
final RequestManager rm = Json.decodeValue("{\"messageId\":\"themessage\"}", RequestManager.class);
System.out.println(rm.getMessageContent());
"{\"messageId\":\"themessage\"}" = the JSON format, i'm sure of it because decodeValue would return a Decode Exception if it wasn't.
Now the field is "nullcheck" when i print it. So it means that the constructor is well used but the fields are nulls. Where am i doint it wrong ?

You could try to have an empty constructor.

It's because you have your own constructor, and JSON doesn't know what values should be passed into it.
There is documentation on their GitHub page explaining how to set up a data object that you expect to be given to you as JSON and converted to Java.
https://github.com/vert-x3/vertx-codegen#data-objects
As per the example that you linked to: http://vertx.io/blog/some-rest-with-vert-x/, notice how they explicitly provide a constructor that takes no arguments, and public setter methods
Whisky()
setName(String name)
setOrigin(String origin)
The alternative is to provide annotations: https://github.com/FasterXML/jackson-annotations. You can choose how to do it, using annotation if you want, or using a bean class (getters and setters). Annotation has the advantage that you can say things like "ignore this value when you convert to JSON", etc. You can be more explicit with annotation. I would recommend picking one and staying with it. Consistency becomes important as your projects grow.

Related

Quarkus Kafka Reactive - Deserializing SubClass (ERROR)

I am using Quarkus to receive messages from Kafka.
When I use the method with just one class, deserialization happens normally.
When my class is subclassed, I can't continue with the deserialization and an error occurs.
My Input in console kafka:
{"id":"73707ad2-0732-4592-b7e2-79b07c745e45","currentstep":"Debit-approval","payload": "{\"idCard\": 2,\"balance\": 456,\"pin\":222}","sagastatus": "STARTED","stepstatus": "{\"credit-approval\":\"STARTED\"}","type":"order-placement","version": 1}
My Method.
#Incoming("process-transaction-in")
public void process(TransactionModel transaction) throws InterruptedException { }
my deserialize class
import io.quarkus.kafka.client.serialization.ObjectMapperDeserializer;
public class TransactionDeserializer extends ObjectMapperDeserializer<TransactionModel> {
public TransactionDeserializer() {
super(TransactionModel.class);
}
My class Model
public class TransactionModel {
public TransactionModel(String id,
String currentStep,
PayloadModel payload,
String sagaStatus,
String stepStatus,
String type,
String version) {
this.id = id;
this.currentStep = currentStep;
this.payload = payload;
this.sagaStatus = sagaStatus;
this.stepStatus = stepStatus;
this.type = type;
this.version = version;
}
public String id;
public String currentStep;
public PayloadModel payload;
public String sagaStatus;
public String stepStatus;
public String type;
public String version;
public TransactionModel() {
payload = new PayloadModel();
}
}
}
The Class PayloadModel
public class PayloadModel {
public PayloadModel(String idCard,
String current,
String pin)
{
this.idCard = idCard;
this.current = current;
this.pin = pin;
}
public String idCard;
public String current;
public String pin;
public PayloadModel() {}
}
Error:
SRMSG18249: Unable to recover from the deserialization failure (topic: process-transaction), configure a DeserializationFailureHandler to recover from errors.: java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of payment.model.PayloadModel (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"idCard": 2,"balance": 456,"pin":222}')
I followed the following tutorial: https://quarkus.io/guides/kafka#kafka-serialization
Has anyone experienced this problem?
As you can see in the error log Jackson finds at least one constructor for PayloadModel class but it's not the one it's expecting since the "payload" parameter in your Kafka payload is a string and not a JSON Object. Try to change the way you serialize your data so that payload is serialized as an object.
Sorry for posting this as a response I don't have enough reputation to comment.

Spring Boot enum JSON serializer

Below is the object that I want to convert to JSON;
public class TestDto{
private ResponseType responseType;
private Long id;
private String name;
}
The ResponseType below is an enum;
public enum ResponseType{
TEST1("test message 1"), TEST2("test message 2"), TEST3("test message 3");
private String message;
}
Below is the JSON which I want to create:
{"code":"TEST1", "message":"test message 1", "id":1, "name":"name"}
and code in the JSON response points the name of the enum and the message in the JSON response points the message field of the enum.
Is there any way to do it?
Easiest way to do this is to add derived getters/setters to TestDto, and suppress JSON serialization of the responseType field.
class TestDto {
private ResponseType responseType;
private Long id;
private String name;
#JsonIgnore // Suppress JSON serialization
public ResponseType getResponseType() {
return this.responseType;
}
public void setResponseType(ResponseType responseType) {
this.responseType = responseType;
}
public String getCode() { // Derived getter for "code" property
return this.responseType.name();
}
public void setCode(String code) { // Derived setter for "code" property
this.responseType = (code == null ? null : ResponseType.valueOf(code));
}
public String getMessage() { // Derived getter for "message" property
return this.responseType.getMessage();
}
#Deprecated // Shouldn't be called by Java code, since it's a dummy stub method
#SuppressWarnings("unused")
public void setMessage(String message) { // Derived setter for "message" property
// Ignore value
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Two-way test
TestDto testDto = new TestDto();
testDto.setResponseType(ResponseType.TEST1);
testDto.setId(1L);
testDto.setName("name");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(testDto);
System.out.println(json);
TestDto testDto2 = mapper.readValue(json, TestDto.class);
System.out.println(testDto2.getResponseType());
System.out.println(testDto2.getId());
System.out.println(testDto2.getName());
Output
{"id":1,"name":"name","message":"test message 1","code":"TEST1"}
TEST1
1
name
I have updated my previous answer as it wasn't correct. You can use #JsonFormat(shape = JsonFormat.Shape.OBJECT) to indicate that the enum should be serialized like an object (based on the getters).
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum ResponseType{
TEST1("test message 1"), TEST2("test message 2"), TEST3("test message 3");
private String message;
ResponseType(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public String getCode() {
return this.toString();
}
}
After that, you must also use #JsonUnwrapped on the Enum field to avoid having it's fields serialized as an object.
public static class TestDto {
#JsonUnwrapped private ResponseType responseType;
private Long id;
private String name;
}
Running the following code
TestDto testDto = new TestDto(ResponseType.TEST1, 1234356L, "First Response");
result = mapper.writeValueAsString(testDto);
System.out.println(result);
I get the result {"message":"test message 1","code":"TEST1","id":1234356,"name":"First Response"}

Binding JSON to Arraylist in Java Spring?

I want to be able to pass in data from a POST request and hit my API in which the JSON I pass through binds to the POTD class. Within POTD, I have an ArrayList of type POTDResources, which is where I am having trouble binding the data.
I'm eventually just going to use the entire Problem object, but for right now I am just testing with two fields within the class.
I need the JSON input to be able to bind to an ArrayList of type POTDResources
I'm passing in data like the following:
{
"problemTitle": "Balancing Binary Tree",
"resources": [{"name": "youtube", "link": "http://yotube.com"}]
}
The API call first hits:
Controller
#RequestMapping(value = "/generatepotd", method = RequestMethod.POST)
#ResponseBody
public void generatePOTD(#RequestBody POTD problem) throws IOException {
POTD prob = new POTD();
prob.setProblemTitle(problem.getProblemTitle());
prob.setResources(problem.getResources());
tempGen.generateProblemOfTheDay(prob);
}
POTD Class
package com.algoq.algoq.models;
import org.springframework.context.annotation.Description;
import java.util.ArrayList;
#Description("Handles the fields required for processing problem of the day")
public class POTD {
private String subject;
private String problemTitle;
private String problemDescription;
private ArrayList<POTDResources> resources;
// POTD(String subject, String problemTitle, String problemDescription, ArrayList<POTDResources> resources) {
POTD(String problemTitle, ArrayList<POTDResources> resources) {
// this.subject = subject;
this.problemTitle = problemTitle;
// this.problemDescription = problemDescription;
this.resources = resources;
}
public POTD() {
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getProblemTitle() {
return problemTitle;
}
public void setProblemTitle(String problemTitle) {
this.problemTitle = problemTitle;
}
public String getProblemDescription() {
return problemDescription;
}
public void setProblemDescription(String problemDescription) {
this.problemDescription = problemDescription;
}
public ArrayList<POTDResources> getResources() {
return resources;
}
public void setResources(ArrayList<POTDResources> resources) {
this.resources = resources;
}
}
POTD Resource Class
package com.algoq.algoq.models;
public class POTDResources {
private String name;
private String link;
public POTDResources(String name, String link) {
this.name = name;
this.link = link;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}
Error Message
{
"timestamp": 1513192593064,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.http.converter.HttpMessageNotReadableException",
"message": "JSON parse error: Can not construct instance of com.algoq.algoq.models.POTDResources: 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 com.algoq.algoq.models.POTDResources: 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#1710624f; line: 3, column: 17] (through reference chain: com.algoq.algoq.models.POTD[\"resources\"]->java.util.ArrayList[0])",
"path": "/generatepotd"
}
Your problems lies with the error message:
no suitable constructor found
You are overriding the default constructor, and the ObjectMapper can't create an instance of your Model class.
Try to add a default constructor for POTDResources:
public POTDResources() {
}
Jackson, which is used by Spring for JSON and XML processing, can work 2 ways with Object.
Constructor and Setter based.
If it can find a constructor with the same field names and types, it will try to use that one. If no suitable constructor, then it will try to create an instance of the object, and use setters. You didn't have a suitable constructor and it failed to create the instance.
Add empty constructor to your POTDResources class:
public POTDResources() {}
The reason being that JSON mapper would first try to initialize your class, and only then would apply values to it
Your problem is that POTDResources does not have a default constructor:
public POTDResources() {}
Jackson requires a no-arg constructor.

Getting JsonMappingException while sending data to view

I am trying to show DB data to my webpage.
I have made following code when GET request to the #RequestMapping(value = "/api/binder").
but when get request came to this method it will fetch data (I have print on console and display well) but it doesn't map to my Java Script Ajax call, it's showing me an error.
Following is my code for to fetch data :
#Autowired
IBinderViewRepository repository;
#RequestMapping(method= RequestMethod.GET)
public #ResponseBody
List<BinderResponse> getBinders(){
List<BinderView> binders = repository.getBinders();
List<BinderResponse> responses = new ArrayList<>();
ModelMapper mapper = Mapper.getInstance();
for(int i = 0; i < binders.size(); i++){
System.out.println("In Loop");
BinderResponse response = mapper.map(binders.get(i),BinderResponse.class);
System.out.println("Data :: " + response.getBinderName());
responses.add(response);
}
return responses;
}
but it shows me following error :
HTTP Status 500 - Could not write JSON: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.ngl.dto.outgoing.BinderResponse["valid"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.ngl.dto.outgoing.BinderResponse["valid"])
Here is ajax call from knockout js :
ajax.get('api/binder').done(function(response){ ... }
Here BinderView and BinderResponse have same fields :
private String binderName;
private String binderAddress1;
and getter setter as well in both.
and repository.genBinders() method bring data from DB.
Here is insert method and works fine for me :
#RequestMapping(method= RequestMethod.POST,consumes = "application/json")
public #ResponseBody
IWebApiResponse addBinder(#RequestBody AddBinderForm binder){
.....
}
Shall I have to put any json annotation on my BinderResponse class ?
I don't understand where am i wrong ?Anyone pleas guide me.
UPDATE :
public class BinderResponse extends WebApiResponseBase {
private String binderName;
private String binderAddress1;
public String getBinderName() {
return binderName;
}
public void setBinderName(String binderName) {
this.binderName = binderName;
}
public String getBinderAddress1() {
return binderAddress1;
}
public void setBinderAddress1(String binderAddress1) {
this.binderAddress1 = binderAddress1;
}
}
BinderView :
public class BinderView extends BaseView {
private String binderName;
private String binderAddress1;
public String getBinderName() {
return binderName;
}
public void setBinderName(String binderName) {
this.binderName = binderName;
}
public String getBinderAddress1() {
return binderAddress1;
}
public void setBinderAddress1(String binderAddress1) {
this.binderAddress1 = binderAddress1;
}
}
In console it prints data / BinderName :
In Loop
Data :: ada
In Loop
Data :: tya
New Update :
Here is BaseView :
#MappedSuperclass
public abstract class BaseView implements IEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="id")
private long id;
public long getId() {
return id;
}
public void setId(long id) {
if (this.id != 0 && this.id != id) {
throw new IllegalStateException(
"The ID must not be changed after it is set.");
}
this.id = id;
}
}
and In IEntity :
public interface IEntity extends Serializable {
long getId();
void setId(long id);
}
WebApiResponseBase :
public class WebApiResponseBase implements IWebApiResponse {
private String _uri;
#Override
public String getUri() {
return _uri == null ? "" : _uri;
}
#Override
public void setUri(String uri) {
_uri = uri;
}
}
Jackson, by default, serializes an object's whole inheritance hierarchy, ie. the parent class fields as well. In the case of
public class BinderResponse extends WebApiResponseBase {
it seems like
Could not write JSON: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.ngl.dto.outgoing.BinderResponse["valid"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.ngl.dto.outgoing.BinderResponse["valid"])
Jackson tries to serialize a field called valid from a getter called isValid (which is a conventional bean property name). The getter method, however, seems to throw a NullPointerException for whatever reason.
If you want Jackson to ignore it, you can annotate the getter with #JsonIgnore or your class with #JsonIgnoreProperties and specify the property name, ie. valid.
In my case when I used #JsonIgnore the exception has been gone but the problem was it couldn't receive that value from API Request anymore and Spring ignored it (obviously because of #JsonIgnore) So I investigated about the issue and figured out that the problem was the getter and setter.
I had the Integer property while my getter was int. So when I changed the getter to Integer my problem solved and error's gone.
private Integer purchaseId;
#JsonIgnore
public int getPurchaseId() {
return purchaseId;
}
public void setPurchaseId(int purchaseId) {
this.purchaseId = purchaseId;
}
Changed to :
private Integer purchaseId;
public Integer getPurchaseId() {
return purchaseId;
}
public void setPurchaseId(Integer purchaseId) {
this.purchaseId = purchaseId;
}
#Column(name="createddate")
private Date createdDate;
#Transient
private String formatedCreatedDate;
public String getFormatedCreatedDate() {
DateFormat dateFormat = new SimpleDateFormat("dd/mm/yyyy");
return dateFormat.format(this.getCreatedDate());
}
It throws the same exception because here may be null by calling getCreatedDate() value come so it can't format null date so keep null check here like:
Solution
public String getFormatedCreatedDate() {
DateFormat dateFormat = new SimpleDateFormat("dd/mm/yyyy");
Date createDdate=this.getCreatedDate();
if(createDdate!=null){
return dateFormat.format(createDdate);
}
return "-";
}

Serializing JSON string to object

I am trying to parse through a JSON string and convert it to the following POJO:
package apicall;
//POJO representation of OAuthAccessToken
public class OAuthAccessToken {
private String tokenType;
private String tokenValue;
public OAuthAccessToken(String tokenType,String tokenValue) {
this.tokenType=tokenType;
this.tokenValue=tokenValue;
}
public String toString() {
return "tokenType="+tokenType+"\ntokenValue="+tokenValue;
}
public String getTokenValue() {
return tokenValue;
}
public String getTokenType() {
return tokenType;
}
}
In order to do this I have written the following code:
Gson gson=new Gson();
String responseJSONString="{\"access_token\" : \"2YotnFZFEjr1zCsicMWpAA\",\"token_type\" : \"bearer\"}";
OAuthAccessToken token=gson.fromJson(responseJSONString, OAuthAccessToken.class);
System.out.println(token);
When I run the code, I get the following output:
tokenType=null
tokenValue=null
Instead of
tokenType=bearer
tokenValue=2YotnFZFEjr1zCsicMWpAA
I don't understand if there's anything I've done wrong. Please help.
You can get the expected result by annotating your fields like:
#SerializedName("token_type")
private final String tokenType;
#SerializedName("access_token")
private final String tokenValue;
How is Gson supposed to know how to populate your object? You don't have a no-arg constructor, and the fields of your object don't match the fields in the JSON object.
Make your object as following:
public class OAuthAccessToken {
private String accessToken;
private String tokenType;
OAuthAccessToken() {
}
...
}
The class should have the exact field name as the json, so if your json have 2 keys: "access_token" and "token_type", the class should have 2 fields:
private String access_token;
private String token_type;
And, of course you need to change the getters/setters accordingly.

Categories