Jackson JSON deserialization for Amazon Lex AWS Lambda hook - java

I have a problem with deserialization implemented in AWS Lex Lambda hook. I have an AWS Lambda function to validate the user input, but I keep getting JSONMapping errors.
The Lex json is like this:
{
"currentIntent": {
"name": "intent-name",
"slots": {
"slot-name": "value",
"slot-name": "value",
"slot-name": "value"
},
"confirmationStatus": "None, Confirmed, or Denied (intent confirmation, if configured)",
},
"bot": {
"name": "bot-name",
"alias": "bot-alias",
"version": "bot-version"
},
"userId": "User ID specified in the POST request to Amazon Lex.",
"inputTranscript": "Text used to process the request",
"invocationSource": "FulfillmentCodeHook or DialogCodeHook",
"outputDialogMode": "Text or Voice, based on ContentType request header in runtime API request",
"messageVersion": "1.0",
"sessionAttributes": {
"key1": "value1",
"key2": "value2"
}
}
And my Java bean for deserializing this JSON is:
public class RequestInput {
public class CurrentIntent {
#JsonProperty("name")
String name;
#JsonProperty("slots")
Map<String, String> slots;
#JsonProperty("confirmationStatus")
String confirmationStatus;
public CurrentIntent(#JsonProperty("name") String name, #JsonProperty("slots") Map<String, String> slots, #JsonProperty("confirmationStatus") String confirmationStatus) {
this.name = name;
this.slots = slots;
this.confirmationStatus = confirmationStatus;
}
}
#JsonProperty("currentIntent")
CurrentIntent currentIntent;
#JsonProperty("bot")
Map<String, String> bot;
#JsonProperty("userId")
String userId;
#JsonProperty("inputTranscript")
String inputTranscript;
#JsonProperty("invocationSource")
String invocationSource;
#JsonProperty("outputDialogMode")
String outputDialogMode;
#JsonProperty("messageVersion")
String messageVersion;
#JsonProperty("sessionAttributes")
Map<String, String> sessionAttributes;
#JsonCreator
public RequestInput(#JsonProperty("currentIntent") CurrentIntent currentIntent, #JsonProperty("bot") Map<String, String> bot,
#JsonProperty("userId") String userId, #JsonProperty("inputTranscript") String inputTranscript,
#JsonProperty("invocationSource") String invocationSource, #JsonProperty("outputDialogMode") String outputDialogMode,
#JsonProperty("messageVersion") String messageVersion, #JsonProperty("sessionAttributes") Map<String, String> sessionAttributes) {
this.currentIntent = currentIntent;
this.bot = bot;
this.userId = userId;
this.inputTranscript = inputTranscript;
this.invocationSource = invocationSource;
this.outputDialogMode = outputDialogMode;
this.messageVersion = messageVersion;
this.sessionAttributes = sessionAttributes;
}
#Override
public String toString() {
return "Intent " + currentIntent.toString() + "; Bot " + bot.toString() + "; InputTranscript " + inputTranscript;
}
}
In the handler class I just try to invoke RequestInput.toString() method, but I keep getting this error:
An error occurred during JSON parsing: java.lang.RuntimeException
java.lang.RuntimeException: An error occurred during JSON parsing
Caused by: java.io.UncheckedIOException: com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.comelit.lex.LexIntercomCallValidate$RequestInput]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: lambdainternal.util.NativeMemoryAsInputStream#55d56113; line: 1, column: 2]
Caused by: com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.comelit.lex.LexIntercomCallValidate$RequestInput]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: lambdainternal.util.NativeMemoryAsInputStream#55d56113; line: 1, column: 2]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1106)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:296)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:133)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1511)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1102)

Add a default constructor to class RequestInput. This error generally indicates the inability to instantiate the class to be mapped with the received JSON:
public RequestInput() {}

Related

How do I resolve com.fasterxml.jackson.databind.exc.MismatchedInputException?

I'm getting the below error while trying to post a request through Swagger. This works fine when I do it through Postman.
I'm using springBootVersion = '2.1.0.RELEASE', swaggerVersion = '2.9.2'.
This is my Json mapping class.
DataExport.java
#XmlRootElement(name = "DataExport")
public class DataExport
{
#JsonProperty("engineName")
private String engineName;
#JsonProperty("searchQuery")
private String searchQuery;
public DataExport()
{
super();
}
public DataExport(String aEngineName, String aSearchQuery)
{
super();
this.engineName = aEngineName;
this.searchQuery = aSearchQuery;
}
RestController.java
#RequestMapping(value = "/export", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
#ApiOperation(authorizations = {
#Authorization(value = "oauth") }, value = "Initiates the job for export", response = String.class)
#ApiResponses({ #ApiResponse(code = 200, message = "Request accepted."),
#ApiResponse(code = 500, message = "The export could not be started due to an internal server error.") })
public String getJobId(#RequestBody DataExport aDataExport, HttpServletResponse aResponse,
#Value("${com.xyz.dataexportmodule.defaultfilelocation}") final String aLocation)
throws Exception
{
LOG.info("Initializing export for Engine {} and Query {}", aDataExport.getEngineName(),
aDataExport.getSearchQuery());
String exportLocation = aLocation
....
I want to pass this JSON
{
"engineName":"ABC",
"searchQuery":"*"
}
But I'm getting this error:
2019-04-01 13:42:05,022 [https-jsse-nio-8443-exec-19] WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct an instance of `com.xyz.dataexportmodule.persistence.entity.DataExport` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('string');
nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct an instance of `com.xyz.dataexportmodule.persistence.entity.DataExport` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('string')
at [Source: (PushbackInputStream); line: 1, column: 1]]
I'm unable to figure out what is the issue, somebody please help.
P.s: My Swagger Screenshot
enter image description here
Solution: After making these changes in DataExport class and removing Location variable in REST controller method, this issue got resolved.
#JsonIgnoreProperties(ignoreUnknown = true)
#ApiModel(value = "Data Export", description = "A JSON object corresponding to Data Export entity.")
public class DataExport
{
private String mEngineName;
private String mSearchQuery;
/**
* Default CTor.
*/
public DataExport()
{
}
#JsonCreator
public DataExport(#JsonProperty("engineName") String aEngineName,
#JsonProperty("searchQuery") String aSearchQuery)
{
mEngineName = aEngineName;
mSearchQuery = aSearchQuery;
}
Your screenshot show that you have two body, which can't be done.
I don't know what you're trying to do, but just for test remove the field aLocation, and it will be OK.

Deserialization exception while POSTing nested json to Spring controller

I'm using Spring, following is my controller code:
#RequestMapping(value = "/campaigns/addTask", method = RequestMethod.POST)
public Campaign addTaskToCampaign(#RequestParam(value = "campaignName")String campaignName,#Valid #RequestBody Task task) {
Campaign campaign = campaignInterface.findByName(campaignName);
if (campaign!=null){
List<String> task_ids;
if (campaign.getTask_ids()==null){
task_ids = new ArrayList<>();
}else{
task_ids= campaign.getTask_ids();
}
Task newTask = taskInterface.save(task);
task_ids.add(newTask.getId());
campaign.setTask_ids(task_ids);
return campaignInterface.save(campaign);
}
return null;
}
Where my task model is:
#Document(collection = "tasks")
public class Task {
#Id
private String id;
private String name;
private int points;
private List<Question>questions;
private List<String>answers;
...
}
And the nested question model is:
public class Question {
private Boolean isText = false;
private String questionText;
}
But, the same model when POSTing as nested json throws an HTTP 400 exception saying json unreadable exception, and it tried to parse the String questionText field as a boolean value.
Here is what im POSTing:
{
"name" : "Test Task 3",
"questions": [{ "questionText":"What is the name you college festival?","isText":true}]
}
And the exception that comes is this:
{
"timestamp": 1497508476467,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.http.converter.HttpMessageNotReadableException",
"message": "JSON parse error: Can not deserialize value of type boolean from String \"What is the name you college festival?\": only \"true\" or \"false\" recognized; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type boolean from String \"What is the name you college festival?\": only \"true\" or \"false\" recognized\n at [Source: java.io.PushbackInputStream#6a371c03; line: 3, column: 32] (through reference chain: com.frapp.CBM.prod.model.Task[\"questions\"]->java.util.ArrayList[0]->com.frapp.CBM.prod.model.Question[\"questionText\"])",
"path": "/campaigns/addTask"
}
Any help is appreciated. ive been trying for hours. Thank you, in advance.
The first comment I would make to any of my developers is: please can you rename your boolean. This is because the getter will look like: isIsText().
As a general rule it is good practice to avoid starting a field name with "get", "set", or "is".
This is because these are the prefixes of java-beans properties.
#RequestMapping(value = "/campaigns/addTask", method = RequestMethod.POST)
public Campaign addTaskToCampaign(#RequestParam Map<String,Object> campaignName,#Valid #RequestBody Task task){
/*
if there is exception then just remove Task put it into json to catch into map.
access just as map by campaignName.get("key_name");
*/
Campaign campaign = campaignInterface.findByName(campaignName);
if (campaign!=null){
List<String> task_ids;
if (campaign.getTask_ids()==null){
task_ids = new ArrayList<>();
}else{
task_ids= campaign.getTask_ids();
}
Task newTask = taskInterface.save(task);
task_ids.add(newTask.getId());
campaign.setTask_ids(task_ids);
return campaignInterface.save(campaign);
}
return null;
}

How to map Json String to POJO?

I am getting below json response from third party web services.
{
"Values":[
{
"Date":"2013-08-01",
"Value":1451674.0
},
{
"Date":"2013-09-01",
"Value":1535645.0
},
{
"Date":"2013-10-01",
"Value":1628753.0
},
{
"Date":"2013-11-01",
"Value":1279856.0
},
{
"Date":"2013-12-01",
"Value":1471991.0
},
{
"Date":"2014-01-01",
"Value":1571008.0
},
{
"Date":"2014-02-01",
"Value":1863232.0
},
{
"Date":"2014-03-01",
"Value":2126469.0
},
{
"Date":"2014-04-01",
"Value":2146069.0
},
{
"Date":"2014-05-01",
"Value":2735564.0
},
{
"Date":"2014-06-01",
"Value":1977808.0
},
{
"Date":"2014-07-01",
"Value":1932503.0
}
]
}
Now what should be the pojo properties and how to map it with pojo?
class Value{
#JsonProperty("Values")
List<DateValuePair> values;
//setter getter
}
class DateValuePair{
#JsonProperty("Date")
String date;
#JsonProperty("Value")
String value;
//setter getter
}
//mapping
Value visits = new Value();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet("http://api.8df1fc");
HttpResponse response = client.execute(request);
BufferedReader rd = new BufferedReader (new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
mapper.readValue(line, Value.class);
}
got below exception:
{"Values":[{"Date":"2013-08-01","Value":1451674.0},{"Date":"2013-09-01","Value":1535645.0},{"Date":"2013-10-01","Value":1628753.0},{"Date":"2013-11-01","Value":1279856.0},{"Date":"2013-12-01","Value":1471991.0},{"Date":"2014-01-01","Value":1571008.0},{"Date":"2014-02-01","Value":1863232.0},{"Date":"2014-03-01","Value":2126469.0},{"Date":"2014-04-01","Value":2146069.0},{"Date":"2014-05-01","Value":2735564.0},{"Date":"2014-06-01","Value":1977808.0},{"Date":"2014-07-01","Value":1932503.0}]}
Exception in thread "main" org.codehaus.jackson.map.JsonMappingException: Root name 'Values' does not match expected ('Value') for type [simple type, class com.domain.Value]
at [Source: java.io.StringReader#e9a398d; line: 1, column: 2]
Thanks!
you can have Pojo which looks something like this
class Value{
#JsonProperty("Values")
List<DateValuePair> values;
}
class DateValuePair{
#JsonProperty("Date")
String date;
#JsonProperty("Value")
String value;
}
and getters/setteres as well
we have jackson libraries which will help you to de-serialize the json string to above POJO object
Just a pointer you need to take it forward
Hope this helps!
Root name 'Values' does not match expected ('Value') for type [simple type, class
com.domain.Value] at [Source: java.io.StringReader#e9a398d; line: 1, column: 2]
Try with setting UNWRAP_ROOT_VALUE to false
//mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, false);

Json Exception wrong type

I use Gson in my project. But it returns me error
String sig = PortalConfig.getSignature(method, callId, params);
String url = PortalConfig.getUrl(method, callId, sig, params);
String plainResponse = BaseClientCommunicator.executeGetMethod(url);
GsonBuilder builder = new GsonBuilder();
Gson gsonObject = builder.create();
response = gsonObject.fromJson(plainResponse, GetMenuResponse.class);
return response;
example I get a Server-response like this
{
"group":
[
{
"id": "206896",
"name": "Ryż",
"info": "xyz"
},
{
"id": "206897",
"name": "Buraki",
"info": {}
}
]
}
and i have error Expected a string but was BEGIN_OBJECT
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 16151
how should I handle this exception??
public class GetMenuResponse
{
#SerializedName("group")
private group[] group;
//method get and set
//to string method
}
public class group
{
#SerializedName("id")
private String id;
#SerializedName("name")
private String name;
#SerializedName("info")
private String info;
//method get and set
//to string method
}
I do not have access to the database, because I use the API
Problem is at line "info": {} in your json string.
Your class have private String info; String type and in your JSON string it is JSONObject.
It will try to convert JSONObject into String, which give error Expected a string but was BEGIN_OBJECT.GSON API cant able to cast JSONObject into JAVA String.
Value of info in first element of your array group is correct that is "info": "xyz" but same variable value in second element is different.
check value of info if it is String than you need to check your JSON response coming from server, if not than you need to change it's type into class variable.

Deserializing JSON map with "key" & "value" properties does not work with Jackson

Questions
To begin with, does the serialized JSON serialization below make sense?
If so, why am I not getting the Map back?
What can I do about it on the deserializing side?
JSON serialization of Map<String, String> property (excerpt):
{
"attributes": {
"entry": [
{
"key": "operating system",
"value": "GNU/Linux"
},
{
"key": "allergies",
"value": "weed"
}
]
}
}
POJO for deserialization:
class Contact implements Comparable<Contact>, Serializable {
#JsonProperty("attributes")
private Map<String, String> attributes;
...
}
Causes this exception:
Thread-4889 An exception occurred during request network execution :Could not read JSON: Can not deserialize instance of java.lang.String out of START_ARRAY token
at [Source: libcore.net.http.FixedLengthInputStream#43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_ARRAY token
at [Source: libcore.net.http.FixedLengthInputStream#43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"])
org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not deserialize instance of java.lang.String out of START_ARRAY token
at [Source: libcore.net.http.FixedLengthInputStream#43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_ARRAY token
at [Source: libcore.net.http.FixedLengthInputStream#43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"])
at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readInternal(MappingJackson2HttpMessageConverter.java:126)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:147)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:76)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:484)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:237)
at com.example.providers.Query$1.loadDataFromNetwork(Query.java:99)
at com.octo.android.robospice.request.CachedSpiceRequest.loadDataFromNetwork(CachedSpiceRequest.java:45)
at com.octo.android.robospice.request.RequestRunner.processRequest(RequestRunner.java:130)
at com.octo.android.robospice.request.RequestRunner$1.run(RequestRunner.java:197)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:841)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_ARRAY token
at [Source: libcore.net.http.FixedLengthInputStream#43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"])
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:691)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:46)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringMap(MapDeserializer.java:430)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:312)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:525)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:106)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:242)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:227)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.des
The attributes Object when inspected in debugger after deserialization:
Further inspection after changing to:
#JsonProperty("attributes")
private Map<String, List<Map<String, String>>> attributes;
Dependencies:
com.fasterxml.jackson.core:jackson-core:2.3.0
com.fasterxml.jackson.core:jackson-databind:2.3.0
com.fasterxml.jackson.core:jackson-annotations:2.3.0
If we will convert Map to json:
Map<String, String> map = new HashMap<String, String>();
map.put("operating system", "GNU/Linux");
map.put("allergies", "weed");
The output will be:
{"operating system":"GNU/Linux","allergies":"weed"}
As we can see there is no key/value.
Solution
WrapperObject
#JsonIgnoreProperties(ignoreUnknown = true)
public class WrapperObject { // we can give any name to class, its only external {}
private Attributes attributes;
public WrapperObject() {}
public Attributes getAttributes() {
return attributes;
}
}
Attributes
#JsonIgnoreProperties(ignoreUnknown = true)
public class Attributes {
public Attributes() {}
private ArrayList<Entry> entry;
public ArrayList<Entry> getEntry() {
return entry;
}
}
Entry
#JsonIgnoreProperties(ignoreUnknown = true)
public class Entry {
private String key;
private String value;
public Entry() {}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
}
Launcher
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
String str = "{" +
" \"attributes\": {" +
" \"entry\": [" +
" {" +
" \"key\": \"operating system\"," +
" \"value\": \"GNU/Linux\"" +
" }," +
" {" +
" \"key\": \"allergies\"," +
" \"value\": \"weed\"" +
" }" +
" ]" +
" }" +
"}";
ObjectMapper mapper = new ObjectMapper();
WrapperObject mj = mapper.readValue(str, WrapperObject.class);
if(mj == null){
System.err.println("null");
}
// dummy check
System.out.println(mj.getAttributes().getEntry().get(0).getKey());
}
Output:
operating system

Categories