How to pass a Map object to a RestController method? - java

I have an API method like below inside my RestController
#PostMapping("/asd")
public ResponseEntity<String> asd(#RequestBody MyParams params) { ... }
MyParams class is like below.
public class MyParams implements Serializable {
public List<Long> ids;
public List<String> ignoredTypes;
public Map<String, List<String>> aMapping;
}
In postman, I pass a JSON string like
{
"ids": [28712, 344248],
"ignoredTypes": [],
"aMapping": "{\"Person\":[\"name\",\"age\"],\"Title\":[\"start\",\"end\"]}",
}
I get an error saying
2021-08-16 18:25:53.953 WARN 4164 --- [io-8080-exec-10]
.w.s.m.s.DefaultHandlerExceptionResolver : Resolved
[org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Cannot construct instance of
java.util.LinkedHashMap (although at least one Creator exists): no
String-argument constructor/factory method to deserialize from String
value ('{"Person":["name","age"],"Title":["start","end"]}'); nested
exception is
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot
construct instance of java.util.LinkedHashMap (although at least one
Creator exists): no String-argument constructor/factory method to
deserialize from String value
('{"Person":["name","age"],"Title":["start","end"]}') at [Source:
(PushbackInputStream); line: 12, column: 20] (through reference chain:
com.xyz.MyParams["aMapping"])]
So basically java.util.Map cannot be parsed from JSON string. How can I do that?

Did you tried like this
{
"prop1": [1],
"prop2": ["string"],
"prop3": {
"additionalProp1": [
"string"
],
"additionalProp2": [
"string"
],
"additionalProp3": [
"string"
]
}
}
Try to pass the JSON object as it is without stringifying

I changed the request body and it worked.
{
"ids": [
28712,
344248
],
"ignoredTypes": [
],
"aMapping": {
"Person": [
"name",
"age"
],
"Title": [
"start",
"end"
]
}
}

Related

GeoJson Jackson - parse JSON to Java object fails

I am working on parsing a GeoJSON file into Java POJO classes.
I have found the GeoJSON Jackson library which seems to be exactly the same as I need.
https://github.com/opendatalab-de/geojson-jackson
I have a JSON like the following:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"lfdNr": 1,
"betriebsNummer": 33,
"nummer": 4,
"bezeichnung": "TERST",
"kng": 61062323,
"nArtCode": "A",
"nArtB": "ACKERLAND",
"flaeche": 4.0748
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
15.8867118536754,
48.4004384452486
],
[
15.884483831836,
48.3981983444393
],
[
15.8847389374202,
48.3991957290405
],
[
15.8853143451339,
48.3991585954555
],
[
15.8851662097189,
48.398462039698
],
....
]
]
}
}
]
}
I wish to use it as a FeatureCollection java object:
objectMapper.readValue(json, FeatureCollection.class);
I get the following:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct
instance of `org.geojson.GeoJsonObject`
(no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types,
have custom deserializer, or contain additional type information
at [Source: (String)"{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"lfdNr":1,"betriebsNummer":10086722,"nummer":4,"bezeichnung":"TERST","fskennung":61062323,"nutzungsArtCode":"A","nutzungsArtBezeichnung":"ACKERLAND","flaeche":4.0748},"geometry":{"type":"Polygon","coordinates":[[[15.8867118536754,48.4004384452486],[15.8829132747878,48.4002081767679],["[truncated 2362 chars]; line: 1, column: 251]
(through reference chain: org.geojson.FeatureCollection["features"]->java.util.ArrayList[0]->org.geojson.Feature["geometry"])
I assume it is because the class Geometry a generic type is:
public abstract class Geometry<T> extends GeoJsonObject
I only operate with Polygons and Points.
Any ides how can I get it working?
Thanks a lot!
You can read this JSON content by
GeoJsonObject object = objectMapper.readValue(json, GeoJsonObject.class);
if (object instanceof FeatureCollection) {
FeatureCollection featureCollection = (FeatureCollection) object;
...
}
Jackson will automatically recognize your JSON example as a FeatureCollection object,
because of the annotations on the GeoJsonObject class:
#JsonTypeInfo(property = "type", use = Id.NAME)
#JsonSubTypes({ #Type(Feature.class), ..., #Type(FeatureCollection.class), ... })
...
public abstract class GeoJsonObject implements Serializable {
...
}

Error When Sending Array of Lists As A Request Body In Spring

I get the following error in the Spring console:
WARN 1208 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.util.ArrayList<java.lang.Float>` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList<java.lang.Float>` out of START_OBJECT token at [Source: (PushbackInputStream); line: 2, column: 5] (through reference chain: java.lang.Object[][0])]
When I pass this response body to my application locally using Postman Echo:
{
"timeslots": [
[
8.4,
9.4,
10.0,
11.4,
12.0,
13.4,
14.4,
15.4,
16.4,
17.4,
18.4,
19.4
],
[
10.4,
11.4,
12.0
]
]
}
]
This is my endpoint:
#PutMapping(path = "/timeslots/id/{id}")
public void updateTimeslotsById(#RequestBody ArrayList<Float>[] timeslots, #PathVariable("id") String id) {
Member member = this.memberService.getMemberById(id).orElseThrow(() ->
new ApiRequestException("Cannot find member with this ID"));
//member.setTimeslots(timeslots);
this.memberService.updateMember(id, member);
}
Receiver in your contoller method does not comply with json schema hence deserialization issue is coming.
Craete below custom class.
MyObject {
List<Float[]> timeslots;
//getter
//setter
}
Change your method signature to
public void updateTimeslotsById(#RequestBody MyObject timeslots, #PathVariable("id") String id) {

Parsing a list of objects got from an API

Hi i am using retrofit to call my API with spring boot.
API Response
[
{
"name": "whishky",
"price": 1000
},
{
"name": "vodka",
"price": 200
}
]
My pojo class looks like
public class MyResponse {
List<MyObject> resp;
}
And MyObject class looks like
public class MyObject implements Serializable {
#JsonProperty("name")
private String name;
#JsonProperty("price")
private Double price;
}
API call
Call<MyResponse> saveRequestCall = MyApi.fetchData(request);
Response<MyResponse> execute = saveRequestCall.execute();
Now the problem is when i call the API i am getting the exception
2020-04-25 18:08:18,895 ERROR c.s.e.b.XYZServiceImpl Error in fetching datawith exception com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `zzz.MyResponse` out of START_ARRAY token
at [Source: (InputStreamReader); line: 1, column: 1]
Any help will be appreciated regarding how i can parse this.
The problem seems to be mapping to MyResponse because it's excepecting something like
{
"resp": [
{
"name": "whishky",
"price": 1000
},
...
]
}
It should be fixed if you use
Call<List<MyObject>> saveRequestCall = MyApi.fetchData(request);
Response<List<MyObject>> execute = saveRequestCall.execute();
The above json represent JSONArray of JSONObject with two properties name and price, so you don't need to wrap List<MyObject> resp in another class, you can directly deserialize json into List<MyObject>
Call<List<MyObject>> saveRequestCall = MyApi.fetchData(request);
Response<List<MyObject>> execute = saveRequestCall.execute();

Deserializing JSON with Jackson for polymorphic classes

I am attempting to deserialize JSON which can be either a GroupRule or AttributeRule:
AbstractRule
GroupRule
AttributeRule
I want my models/entities/POJOs to be generic as I also use the same classes in other projects with Snakeyaml or other serialization providers.
Having said that, I stumbled across this: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization
which in the article, it indicates I could do:
{ // Using fully-qualified path
"#class" : "com.fasterxml.beans.EmployeeImpl", ...
}
However, when I do that, I am getting:
Cannot construct instance of `com.walterjwhite.email.organization.api.configuration.rule.AbstractRule` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (FileInputStream); line: 4, column: 10] (through reference chain: com.walterjwhite.email.organization.api.configuration.rule.EmailMatcherRule["rule"])
com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
My configuration is this:
{
"name": "default",
"ordering": "1",
"rule": {
"#class": "com.walterjwhite.email.organization.api.configuration.rule.GroupRule",
"criteriaType": "Should",
"rules": [
{"#class": "com.walterjwhite.email.organization.api.configuration.rule.AttributeRule",
"emailMessageField": "Subject",
"values": ["default"]
}
]
},
"matchType": "ContainsIgnoreCase",
"actionClassNames": [
"com.walterjwhite.email.organization.plugins.count.CountAction",
"com.walterjwhite.email.organization.plugins.index.IndexAction",
"com.walterjwhite.email.organization.plugins.reply.MoveAction"
]
}
On the Java side of things, I am doing this generally:
mapper.readValue(inputStream, entityType);
Now, the entityType in this case is EmailMatcherRule which inside it has a rule field which can either be attribute or group. Inputstream is just the fileInputStream I am passing in ...
I am using Jackson 2.10.1. I also converted the above JSON from YAML which was working fine via Snakeyaml. Note that it automatically embeds the classes into the YAML, so this was a non-issue with it.
Is my JSON correct - according to the documentation, I should be able to add the #class attribute to specify the class I want to use, right?
I tried below and it worked without any configuration. Not sure if thats what you want to achieve:
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String groupRuleStr = "{\"parentId\":\"parent\",\"groupId\":\"group\"}";
String attributeRuleStr = "{\"parentId\":\"parent\",\"attributeId\":\"attribute\"}";
GroupRule groupRule = mapper.readValue(groupRuleStr, GroupRule.class);
AttributeRule attributeRule = mapper.readValue(attributeRuleStr, AttributeRule.class);
System.out.println(groupRule.groupId);
System.out.println(attributeRule.attributeId);
}
static abstract class AbstractRule {
public String parentId = "parent";
}
static class GroupRule extends AbstractRule {
public String groupId = "group";
}
static class AttributeRule extends AbstractRule {
public String attributeId = "attribute";
}
I had to do this:
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator());
Now, my JSON looks like this (NOTE: this is a different test entity, but you get the idea):
{
"name": "default",
"ordering": "1",
"rule": [
"com.walterjwhite.email.organization.api.configuration.rule.GroupRule",
{
"criteriaType": "Should",
"rules": ["java.util.HashSet",[[
"com.walterjwhite.email.organization.api.configuration.rule.AttributeRule",
{
"emailMessageField": ["com.walterjwhite.email.organization.api.configuration.rule.EmailMessageField", "Subject"],
"values": ["java.util.HashSet", [
"default"
]],
"matchType": ["com.walterjwhite.email.organization.api.configuration.rule.MatchType","ContainsIgnoreCase"]
}]]
]
}
],
"actionClassNames": ["java.util.ArrayList",[
"com.walterjwhite.email.organization.plugins.count.CountAction",
"com.walterjwhite.email.organization.plugins.index.IndexAction",
"com.walterjwhite.email.organization.plugins.reply.MoveAction"
]
]
}
So, the reference documentation I saw with #class seems inaccurate. I am not really happy about adding all this extra information especially when some of it isn't needed - java.util.ArrayList.

Not able to post JSON array to my rest controller

I've a JSON Array that needs to be consumed at the rest controller. It always says JSON parser error
{
"message": "JSON parse error: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token\n at [Source: (PushbackInputStream); line: 1, column: 1]",
"errorUid": "c794a587-2f27-4402-b43b-5ec46a5bccfc"
}
Here is my request object
{
"results":[{
"keyname":"bb-response",
"bbResponse":{
"count": 8,
"transactionId": "hu7h78707ssf8",
"responseMessage": [{
"type": "NTY",
"status": "F"
},
{
"type": "HYG",
"status": "F"
}]}
}]}
Here is my code of the controller
#PostMapping(value = "/post-keys")
#ResponseStatus(HttpStatus.OK)
public String postKeys(#RequestBody List<RequestWrapper> requestWrapperList) {
log.info("Starting to send messages ");
return "success";
}
My RequestWrapper Class
public class RequestWrapper implements Serializable {
String keyname;
BBResponse bbResponse;
}
My BBResponse class is
public class BBResponse implements Serializable {
private int count;
private List<Response> responseMessage;
private String transactionId;
}
Can any one let me know where am I doing wrong? Any ideas would be greatly appreciated
Solved. The issue was with the JSON request. The correct request looks like this
[{
"keyname":"bb-response",
"bbResponse":{
"count": 8,
"transactionId": "hu7h78707ssf8",
"responseMessage": [{
"type": "NTY",
"status": "F"
},
{
"type": "HYG",
"status": "F"
}]}
}]

Categories

Resources