Json not converting to object in spring integration - java

I'm having
.transform(Transformers.fromJson(SNSMessage.class))
not return a value transformed from my JSON. The JSON input is
{
"Type": "Notification",
"MessageId": "b5c64f3f-59e3-5fce-9ad6-1e98973c9537",
"TopicArn": "arn:aws:sns:us-east-1:194477963434:local-hera-update",
"Subject": "com.accuity.hera.model.HeraNotification",
"Message": "{\"id\":\"65e60559-cab5-4027-88a2-46185fbd50b9\",\"resourceType\":\"listItem\",\"action\":\"I\",\"timeOfAction\":\"2017-05-30T19:48:46Z\",\"source\":\"gwl\"}",
"Timestamp": "2017-05-30T19:48:47.593Z",
"SignatureVersion": "1",
"Signature": "Xz0qg0byLMA1fwIRbi7aWcEzhtcLBOmzyUluL1W5URu4WaiEO3G\/+hPSpsFXGxcSYNYRgpKhL9QAP2qLkuMlSEMqiEOHaSr88UaB8QRV2lUEjdBAWpuFYVBPdb+jpo6n3m89vVHoYfFWk8yBkc0zuoRl4OYcUXfTZiWWQkkrT8r9OzWU8LxQwgf0jgr1xEoqbl7uMHIp7nHp3cKstQ0mbK6yxMQ8faxfDm+IwH3k8BBH2\/CXmRg9WME6JK77jvagMUHNhUahWKIjm4iz+TCQCdnmHQR21hmgxlkhdrSxZ1FBbk6BjxfX7gorEwwfY1gYNoZCXxsN63+4vSiFMlOAAQ==",
"SigningCertURL": "https:\/\/sns.us-east-1.amazonaws.com\/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem",
"UnsubscribeURL": "https:\/\/sns.us-east-1.amazonaws.com\/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:194477963434:local-hera-update:7de3da56-9e6c-43ca-9abc-d46fff379380"
}
and the class definition is:
public class SNSMessage {
private String Type;
private String MessageId;
private String TopicArn;
private String Subject;
private String Message;
private String Timestamp;
private String SignatureVersion;
private String Signature;
private String SigningCertURL;
private String UnsubscribeURL;
}
any ideas why the SNSMessage is coming back with all its fields set to null?

The problem you have is that your json attributes are using a different capitalization than your pojo properties.
It means you have Type as json attribute and type detected for your getter.
You need to use #JsonProperty annotation like this:
#JsonProperty("Type")
private String type;
...
// getters / setters for type
Btw, if you don't want to follow the java naming standard and have Type as well as the pojo property, then just add the #JsonProperty to the property with no args

Related

change field name to lowercase while deserializing POJO to JSON using GSON?

I have a POJO class like this. I am deserializing my JSON to below POJO first..
public class Segment implements Serializable {
#SerializedName("Segment_ID")
#Expose
private String segmentID;
#SerializedName("Status")
#Expose
private String status;
#SerializedName("DateTime")
#Expose
private String dateTime;
private final static long serialVersionUID = -1607283459113364249L;
...
...
...
// constructors
// setters
// getters
// toString method
}
Now I am serializing my POJO to a JSON like this using Gson and it works fine:
Gson gson = new GsonBuilder().create();
String json = gson.toJson(user.getSegments());
System.out.println(json);
I get my json printed like this which is good:
[{"Segment_ID":"543211","Status":"1","DateTime":"TueDec2618:47:09UTC2017"},{"Segment_ID":"9998877","Status":"1","DateTime":"TueDec2618:47:09UTC2017"},{"Segment_ID":"121332121","Status":"1","DateTime":"TueDec2618:47:09UTC2017"}]
Now is there any way I can convert "Segment_ID" to all lowercase while deserializing? I mean "Segment_ID" should be "segment_id" and "Status" should be "status". Is this possible to do using gson? So it should print like this instead.
[{"segment_id":"543211","status":"1","datetime":"TueDec2618:47:09UTC2017"},{"segment_id":"9998877","status":"1","datetime":"TueDec2618:47:09UTC2017"},{"segment_id":"121332121","status":"1","datetime":"TueDec2618:47:09UTC2017"}]
if I change the "SerializedName" then while deserializing my JSON to POJO, it doesn't work so not sure if there is any other way.
You need to provide alternative names for deserialisation process and primary (value property) for serialisation.
class Segment {
#SerializedName(value = "segment_id", alternate = {"Segment_ID"})
#Expose
private String segmentID;
#SerializedName(value = "status", alternate = {"Status"})
#Expose
private String status;
#SerializedName(value = "datetime", alternate = {"DateTime"})
#Expose
private String dateTime;
}
Now, you can deserialise fields: Segment_ID, DateTime, Status and still be able to serialise as desired.

Java object not populated from json request for inner class

Have searched in different sites but couldn't find correct answer, hence posting this request though it could possible duplicates.sorry for that.
I am sending the below json request to my back-end service and converting to java object for processing. I can see the request body passed to my service but when i convert from json to java object , values are not populating
{
"data":{
"username":"martin",
"customerId":1234567890,
"firstName":"john",
"lastName":"smith",
"password":"p#ssrr0rd##12",
"email":"john.smith#gmail.com",
"contactNumber":"0342323443",
"department":"sports",
"location":"texas",
"status":"unlocked",
"OrderConfigs":[
{
"vpnId":"N4234554R",
"serviceId":"connectNow",
"serviceType":"WRLIP",
"ipAddress":"10.101.10.3",
"fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
"timeout":1800,
"mapId":"test_map"
}
]
}
}
My Parser class have something like,
JSONObject requestJSON = new JSONObject(requestBody).getJSONObject("data");
ObjectMapper mapper = new ObjectMapper();
final String jsonData = requestJSON.toString();
OrderDTO mappedObject= mapper.readValue(jsonData , OrderDTO .class);
// I can see value coming from front-end but not populating in the mappedObject
My OrderDTO.java
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true,value = {"hibernateLazyInitializer", "handler", "created"})
public class OrderDTO {
private String username;
private long customerId;
private String source;
private String firstName;
private String lastName;
private String email;
private String contactNumber;
private String password;
private String department;
private String location;
private String status;
private List<OrderConfig> OrderConfigs;
#JsonInclude(value = Include.NON_NULL)
public class OrderConfig {
private String vpnId;
private String serviceId;
private String serviceType;
private String ipAddress;
private String mapId;
private String[] fRoutes;
private Map<String, Object> attributes;
private SubConfig subConfig;
private String routeFlag;
getter/setters
.....
}
all setter/getter
}
Not sure what I'm missing here. Is this right way to do?
If your are trying to use inner class, correct way to use is to declare it static for Jackson to work with inner classes.
For reference check this
code changes made are
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
static class OrderConfig {
Make sure that your json tag names match with variable names of java object
Ex : "fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
private String[] fRoutes;
OrderConfigs fields will not be initialized, just modify your bean as
#JsonProperty("OrderConfigs")
private List<OrderConfig> orderConfigs;
// setter and getter as setOrderConfigs / getOrderConfigs
See my answer here. (same issue)

Retrofit/Android - dynamic response support

I'm having trouble with mapping resulting json data to pojo class with Retrofit. I need to determine Firebase topics by token. This can be eaisly done with Google's json api, as described here: https://developers.google.com/instance-id/reference/server#get_information_about_app_instances
In my case, server response is simlar to this:
{
"applicationVersion": "36",
"connectDate": "2018-02-04",
"attestStatus": "ROOTED",
"application": "<my application id>",
"scope": "*",
"authorizedEntity": "205414012839",
"rel": {
"topics": {
"topic1": {
"addDate": "2018-02-04"
},
"topic2": {
"addDate": "2018-01-31"
}
}
},
"connectionType": "WIFI",
"appSigner": "<hash>",
"platform": "ANDROID"
}
The problem is basically rel and topics structure, because topics is dynamic and field list can by anything and it's unknown. So I can't generate simple POJO to get it mapped by Retrfofit automatically.
Can I force Retrofit to treat topics as single String field, I will able to parse it later to retrieve topics list? Or is there any other soulution?
Any ideas?
If you use gson, you can define rel as a JsonElement. If you use moshi, you can define it as a Map.
for gson:
public class Response{
private String applicationVersion;
private String connectDate;
private String attestStatus;
private String application;
private String scope;
private String authorizedEntity;
private String connectionType;
private String appSigner;
private String platform;
private JsonElement rel;
}
for moshi:
public class Response{
private String applicationVersion;
private String connectDate;
private String attestStatus;
private String application;
private String scope;
private String authorizedEntity;
private String connectionType;
private String appSigner;
private String platform;
private Map<String, Map<String, Map<String, String>>> rel;
}

How to parse a JSON with a property which could be a String or an Object using GSON?

I have a class that should be deserialized accordingly the header request.
If header is on V1 version, ww should output the information field of Product class, like a String. Otherwise it output an Info object.
Is there another solution to do this, instead duplicate the class?
public class Product{
private String name;
private Integer id;
private Info information;
}
public class Info{
private String generalInfo;
private String fullDescription;
private String code;
}
public class Product{
private String name;
private Integer id;
private String information;
}
Above the JSON when use INFO object and when information is a string.
{
"name": "Paul",
"id": "123123,
"information": {
"generalInfo":"Business Product",
"fullDescription":"23",
"code":"9487987289929222-3"
}
}
{
"name": "Paul",
"id": "123123,
"information": "Business Product - 23 - 9487987289929222-3 "
}

How to bind map of custom objects using #RequestBody from JSON

I need to send map of custom objects Map<String, Set<Result>> from frontend to backend.
So I think it should be possible to build JSON, send it to Controller via Ajax and receive it in Controller via #RequestBody annotation which should bind json to object. right?
Controller:
#RequestMapping(value = "/downloadReport", method = RequestMethod.POST)
public ResponseEntity<byte[]> getReport(#RequestBody Map<String, Set<Result>> resultMap)
{
Context context = new Context();
context.setVariable("resultMap", resultMap);
return createPDF("pdf-report", context);
}
JSON:
{
"result": [
{
"id": 1,
"item": {
"id": 3850,
"name": "iti"
},
"severity": "low",
"code": "A-M-01",
"row": 1,
"column": 1,
"description": "Miscellaneous warning"
}
]
}
Model:
public class Result {
private Integer id;
private Item item;
private String severity;
private String code;
private Integer row;
private Integer column;
private String description;
//getter & setters
//hashCode & equals
}
public class Item {
private Integer id;
private String name;
//getter & setters
}
After send such a JSON like above by ajax I am getting error message from browser:
The request sent by the client was syntactically incorrect
If I change JSON to send empty set like below then it works but of course my map has empty set:
{"result": []}
So, Why I am not able to receive filled map with set of objects? Why binding/unmarshalling do not work as expected and what I should do to make it works?
Note:
I am using Jackson library and marshalling for other case for #ResponseBody works fine. Problem is with unmarshalling and binding object via #RequestBody.
In order for jackson to properly deserialize your custom classes you need to provide #JsonCreator annotated constructor that follows one of the rules defined in the java doc. So for your Item class it could look like this:
#JsonCreator
public Item(#JsonProperty("id") Integer id,
#JsonProperty("name") String name) {
this.id = id;
this.name = name;
}
you have to deal with map differently,
first create wrapper class
public MyWrapperClass implements Serializable {
private static final long serialVersionUID = 1L;
Map<String, List<String>> fil = new HashMap<String, List<String>>();
// getters and setters
}
then you should take request in controller,
#PostMapping
public Map<String,List<String>> get(#RequestBody Filter filter){
System.out.println(filter);
}
Json Request should be like
{
"fil":{
"key":[
"value1",
"value2"
],
"key":[
"vakue1"
]
}
}

Categories