Unmarshal nested JSON object to generic Java object - java

I'm using Jersey (2.5.1) for a RESTish API with JAXB to marshal JSON to/from POJOs. The client will be doing a POST with the following request:
{
"type":"myevent",
"data":{
"id":"123",
"count":2
}
}
I have an 'Event' class which holds a type string and a data payload.
#XmlRootElement
public class Event {
#XmlElement public String type;
#XmlElement public JSONObject data;
...
}
The 'data' payload is a JSON object, however I don't know what type, or what the 'schema' of the object is. All I know is it's JSON. Above I have the type as a JSONObject, but that's just an example, maybe this needs to be Object? Map? Something else?
I want to be able to get the 'data' payload and persist this as JSON somewhere else.
I thought about using a String for the data payload, but then any API client would need to encode this and I would need to decode it before passing it on.
Any suggestions?

I usually work with strings on the backend side and then
JSONObject json = new JSONObject(s);
would create a json obj from that s (you don't need to decode).
On the client side I believe you just need to escape the " with something like a replaceAll function applied on that string

Related

How to get the set inside nested JsonNode using Jackson

I have a below JSON structure. which I need to parse using the Jackson library. I am building a web-service, which accept below JSON in a POST method's BODY.
{
"organization": {
"products": [
"foo",
"bar",
"baz"
]
},
"mission" : "to be the best in domain"
}
Till, now I was having simple JSON body, which wasn't having nested and JSON element, like in this case organization is another JSON node which contains a Set of products.
This JSON keys are not mandatory, And I am accepting/storing organization JSON in JsonNode. And doing below checks.
If organization is null.
If organization is not null and it has products key.
But after that I don't know how to fetch the set of boards from this JsonNode and store it in Java's HashSet.
My expected O/P should be to have a set of boards extracted from my organization JsonNode.
P.S. :- I think I have to use the ObjectMapper but couldn't find a direct way of getting the Set. Looks like I need to use some JsonParser with which I am not very familier.
You can create DTOs(Data Transfer Objects) for your purpose. The nested objects could have the structure as below:
class Organization {
List<String> Products;
.....
}
class WebOrganizationRequest {
Organization organization;
String mission;
}
By creating objects in this way you are mapping your JSON objects to classes and Jackson will typecast the JSON as an instance of WebOrganizationRequest when you pass it in the controller with WebOrganizationRequest as the request body type.

Keep on JSON deserialized when some property is different

I am having troubles when JSON is being deserialized using Jackson.
The problem is when the JSON is deserialized and whatever JSON property is changed by DEV, I still need to get it deserialized into an object.
Here is the part of variables in the object
#JsonProperty("accountingFiscalYear")
public String accountingFiscalYear;
#JsonProperty("amount")
public Float amount;
#JsonProperty("debitFlag")
public Boolean debitFlag;
and here is the JSON part
"accountingFiscalYear": "2017",
"amount": 1632.0000,
"debitFlag": true,
When it runs it is deserialized without any problems. But if there is any change in the JSON response it fails during the deserialization like:
For example if I change the debitFlag data type from Boolean to Integer
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of int out of VALUE_TRUE token
I know it is right, but I would like to continue with deserialization and simply ignore types that could not be deserialized and keep them null.
Thanks for hints.

Convert from JSON with Jackson Annotations

I am attempting to convert JSON into a Java object with the Play framework. I do not have easy control over the input JSON, which contains dashes in the names.
{ "field-name": "value" }
As a result, I cannot create a Java object with a default mapping to the JSON. I have a class which looks like this:
import com.fasterxml.jackson.annotation.JsonProperty;
public class Data {
#JsonProperty("field-name")
public String fieldName;
}
I know that Play 2.4 uses Jackson, and
I have a unit test which is able to populate the object from the JSON using a default Jackson ObjectMapper.
The JSON is the body of a POST request, and I attempt to use it like this:
Form<Data> form = Form.form(Data.class).bindFromRequest();
If I print form, I can that the data field is populated with the expected values. However, when I do form.get(), the returned value has a null field. (In the actual code, there are more fields, which are Strings or longs. All of them are null or 0.)
Am I attempting to customize the JSON deserialization in the wrong way? Or am I doing something else wrong?
As you've expected you've used the wrong way to deserialize. The Forms class is for PlayForms only and not for Json request. Have a look at the BodyParser and JsonActions documentation:
#BodyParser.Of(BodyParser.Json.class)
public Result index() {
RequestBody body = request().body();
Data data = Json.fromJson(body.asJson(), Data.class);
return ok("Got java object: " + data.toString());
}

Is there any way to create JSON object with keys as upper case?

Project: Android app using REST web service
Using:
Client - Volley
Server API - Jersey
Converter: Gson
This is my first time asking a question here, and i will provide my way of "evading" this code convention. Since i am working on a project where POJO fields are already defined as upper-case (sadly, i cant change that), i had to find a way to fix JSON string and convert it to an instance of uppercase POJO.
So basicaly its: client POJO <--> json object converted to/from gson <--> server POJO
So, lets say that i have a field in Users.class
String USERNAME;
When Jersey sends an instance of via #Produces, it follows the convention of creating JSON and sends an object
{"username": "random_name"}
When it gets converted from JSON via gson.fromJSON, an instance of a client's POJO will get null value for that field (obviously because field is in lower-case in JSONObject).
This is how i managed it by using a method that parses JSONObject and puts each key as upper-case:
public static String fixJSONObject(JSONObject obj) {
String jsonString = obj.toString();
for(int i = 0; i<obj.names().length(); i++){
try{
obj.names().getString(i).toUpperCase());
jsonString=jsonString.replace(obj.names().getString(i),
obj.names().getString(i).toUpperCase());
} catch(JSONException e) {
e.printStackTrace();
}
}
return jsonString;
}
And luckily since gson.fromJSON() requires String (not a JSONObject) as a parameter besides Class, i managed to solve the problem this way.
So, my question would be: Is there any elegant way of making JSON ignore that code convention and create a JSON object with an exact field? In this case:
{"USERNAME": "random_name"}
Jersey uses JAXB internally to marshall beans to xml/json. So you can always use #XmlElement annotation and use name attribute to set the attribute name to be used for marshalling
#XmlElement(name="USERNAME")
String USERNAME;
Just use annotation com.google.gson.annotations.SerializedName
Add in class Users.java:
#SerializedName("username")
String USERNAME;

JsonMappingException no single-String constructor/factory method Jackson

I am trying to parse JSON data being sent from UI in my Controller using Spring build Jackson support and this is my code
final Map<String, CartDataHelper> entriesToUpdateMap = new ObjectMapper().readValue(entriesToUpdate, new TypeReference<Map<String, CartDataHelper>>()
my JSON string is
{"0":"{\"categoryCode\":\"shoes\",\"productCode\":\"300050253\",\"initialQty\":\"3\",\"leftoverQty\":\"0\",\"newQty\":\"3\"}",
"1":"{\"categoryCode\":\"shoes\",\"productCode\":\"300050254\",\"initialQty\":\"3\",\"leftoverQty\":\"0\",\"newQty\":\"3\"}"}
i checked the JSON format using some online services and it seems valid, while tryin gto parse JSON data i am getting following exception
org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type [simple type, class controllers.util.CartDataHelper] from JSON String; no single-String constructor/factory method
my CartDataHelper class contains simple properties for for productCode, categoryCode etc with a no argument constructor
As comments mentioned, your JSON contains Map<String,String> and NOT Map<String,CartDataHelper>: values are JSON Strings, not JSON Objects.
Ideally you would not try writing out objects as JSON Strings; and if so, things would work.
It seems that on the client side the json is sent as a string instead as an object. That way on the server side you are receiveing a string and not a CartDataHelper as you pretend.
Try sending JSON.parse(stringCartDataHelper). It worked for me with the same issue.

Categories

Resources