i have a json string like this
{
"code": "200",
"data": "",
"datadetail": null,
"message": "Khách hàng không tồn tại",
"description": "KH_NOTFOUND:"
}
because the value of data property is "" so that the object mapper can't not map that field in to Java POJO, is that anyway to modify the value of data property to specific string like below
{
"code": "200",
"data": "no data",
"datadetail": null,
"message": "Khách hàng không tồn tại",
"description": "KH_NOTFOUND:"
}
here is the error
detail
Can not instantiate value of type [collection type; class java.util.ArrayList, contains [simple type, class vnptpay.collection.adapter.partner.water.laichau.Datum]] from String value (''); no single-String constructor/factory method
here is my target java object class to map
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"code",
"data",
"datadetail",
"message",
"description"
})
#JsonIgnoreProperties(ignoreUnknown = true)
public class GetBillResponse implements Serializable{
#JsonProperty("code")
private String code;
#JsonProperty("data")
private ArrayList<Datum> data = null;
#JsonProperty("datadetail")
private Object datadetail;
#JsonProperty("message")
private String message;
#JsonProperty("description")
private String description;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
here is my mapping code
ObjectMapper mapper = new ObjectMapper();
GetBillResponse obj = null;
obj = mapper.readValue(output.toString(), GetBillResponse.class);
Assuming output.toString() is your JSON string you could add .replace("\"\"", \"{none}\"). Java should be able to interpret this as an ArrayList with one element (maybe my syntax is wrong, but there is definitely a way to initialise an ArraList from a String).
Edit: Now that I think about it, you probably need JSON-syntax, not Java-syntax, so .replace("\"\"", \"[]\") or something like that.
As said in the comments, you're mapping from a wrong type.
In your JSON "data": "" refers to a String field name data. When the java code is mapping it, as the default value passed is a string, it tries to look for an ArrayList constructors that takes a String as you defined it as list in your Java code:
#JsonProperty("data")
private ArrayList<Datum> data = null;
So you have 2 options now:
you send a valid JSON array that will be mapped to the list like "data": []. (assuming you have a constructor like Datum(String value))
You change the data mapping in your java code to a String and map it to an ArrayList later (if for instances your splitting the String on commas or so)
Also for the record I wouldn't advise you yo map data to an ArrayList but rather map it to a List as it is common best practice to refer to interfaces and not implementations !
Related
I'm working on a Spring-boot project where I receive different format of Json String. My goal is to convert these Json string into an Unified Java class.
I can receive many variations of this Json:
{ "id" : "someId", "type" : "temperature", "value" : 21.0 }
For example, one variation might look like :
{ "id" : "someId", "data" : { "type": "temp", "val" : 21.0 }, "location": "here" }
So these 2 Json must be mapped into the same Java class.
I already have 2 solutions in mind :
First solution
1) Create a Specific Java Class for each Json that I may receive
2) Create a function that takes this specific object and return the Unified Java Class
Second solution
1) Create a JsonNode with the Json String
2) For each key try to match it with a field of the Unified Java Class.
But we have to take into consideration every key possible of a node like "value" or "val".
What is the best approach to solve this problem ?
I'm looking for a solution that could be easy to maintain.
Edit : I'm already using Jackson, but my problem is to map this Json object into an universal Java Class independently of the Json
Edit 2 : The Unified Java Class is a class model that already exist and it's used to store information in our database. So to push information inside our database, I have to convert each json I receive into this unified format
I can see following solutions. E.g. you use Jackson for parse JSON you could declare you custom ObjectMapper:
ObjectMapper mapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
This mapper contains additional options to ignore unknow properties.
Do you Map<String, Object> as destination class. This is magic key and it works always. Contra: you do not have json validation and have to add many constant keys to read this.
Example:
public static <T> Map<String, T> readMap(String json) throws NGPException {
if (json == null) {
return null;
}
ObjectReader reader = JSON_MAPPER.readerFor(Map.class);
MappingIterator<Map<String, T>> it = reader.readValues(json);
if (it.hasNextValue()) {
Map<String, T> res = it.next();
return res.isEmpty() ? Collections.emptyMap() : res;
}
return Collections.emptyMap();
}
Client:
Map<String, Object> map = readMap("json string");
String id = (String)map.getOrDefault("id", null);
Second way is to build one general class that contain all posiible variables. Additionnaly you have to set option to Jackson ignore unknown fields. In this case, existed fields will be used by Jackson.
Example:
public static <T> T read(String json, Class<T> clazz) throws NGPException {
return mapper.readerFor(clazz).readValue(json);
}
class Response {
private String id;
private String type;
private Double value;
private String location;
private Data data;
public class Data {
private String type;
private String temp;
private Double value;
}
}
Client:
Response response = read("json string", Response.class);
I usually use GSon from Google. It is really usefull. Check gson.fromJson(yourJsonString) in your case.
You can easy use
Gson gson = new Gson();
Data data = gson.fromJson(jsonString, Data.class);
I am looking for a generic way to deserialise with Jackson a JSON such as:
{
"hello": "baby",
"eyes": "[blue,green]"
}
To a POJO such as
public class Whatever {
#Setter private String hello;
#Setter private List<Color> eyes;
}
With Color being an enum.
When I try naively like below:
ObjectMapper mapper = new ObjectMapper();
mapper.convertValue(properties, objectClass);
I get the error
Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
Obviously this is because Jackson can only deserialise arrays from JSON arrays, not their string representation.
I tried to activate ACCEPT_SINGLE_VALUE_AS_ARRAY but it would consider the value of the property "eyes" to be an array with a single String element "[blue,green]" (which fails to convert to the enumeration Color)
Any hint would be very much appreciated.
The problem isn't that ACCEPT_SINGLE_VALUE_AS_ARRAY is causing the "eyes" property to be interpreted as an array with a single element, that option allows Jackson to coerce types so that
{
"hello": "baby",
"eyes": "[blue,green]"
}
would be interpreted the same as
[{
"hello": "baby",
"eyes": "[blue,green]"
}]
This way single elements can be used with Java's Collections more information can be found at
http://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/DeserializationFeature.html#ACCEPT_SINGLE_VALUE_AS_ARRAY
As far as your problem goes, the best option would be to have the JSON submitted with color as a JSON array like:
{
"hello": "baby",
"eyes": [
"blue",
"green",
]
}
Otherwise you may need to have your Whatever class have the #JsonSetter annotation on a setEyes method with String parameter where you parse the String to manually create the list of Color yourself.
#JsonSetter
public void setEyes(final String eyes) {
// Parse string and set field here
}
I'm working on a RESTful app in which the response is passed as JSON string from Extjs to the java , so I am using the jackson to deserialize into the java POJO.
Below is my request:
{
"filter": "[{"type":"string","value":"sdadsadsa","field":"groupName"}]",
"limit": 10
}
The FilterParams class looks like this:
class FilterParams {
#JsonProperty( value = "type" )
private String type;
/** The value. */
#JsonProperty( value = "value" )
private String value;
/** The group name. */
#JsonProperty( value = "field" )
private String field;
}
For conversion to pojo am using below code
mapper.readValue(json, FilterParams.Class);
But still am getting the "Can not deserialize instance of FilterParams" . How to convert it into the pojo.
Any help would be greatly appreciated. Thanks.
Your JSON is invalid. Value of filter shouldn't start with " if it's a JSON array, or should have escaped inner " if it's a String.
Your FilterParams class does not reflect the data in your JSON at all: it should have a limit int property and an array or a Collection of Filters
Then you should have a Filter class with type, value and field properties
Your JSON contains 2 elements : filter & limits so that Jackson is not able to match this JSON String into a FilterParams object.
To ignore the JSON part that deal with limit, do the following :
JsonNode tree = mapper.readTree(<JSON_STRING>);
FilterParams fp = mapper.treeToValue(tree.get("filter"), FilterParams.class);
Given the following JSON object
{
"id": 5,
"data: { ... }
}
Is it possible to map this to the following POJO?
class MyEntity {
int id;
Map<String, Object> data;
}
Because I would like to leave the data object open ended. Is this even possible or what is a better approach to go about this? I am doing this on Android.
I don't have any idea about Android application but you can achieve it using Gson library easily.
The JSON that is used in your post is not valid. It might be a typo. Please validate it here on JSONLint - The JSON Validator
Simply use Gson#fromJson(String, Class) method to convert a JSON string into the object of passed class type.
Remember the name of instance member must be exactly same (case-sensitive) as defined in JSON string as well. Read more about JSON Field Naming
Use GsonBuilder#setPrettyPrinting() that configures Gson to output Json that fits in a page for pretty printing.
Sample code:
String json = "{\"id\": 5,\"data\": {}}";
MyEntity myEntity = new Gson().fromJson(json, MyEntity.class);
String prettyJsonString = new GsonBuilder().setPrettyPrinting().create().toJson(myEntity);
System.out.println(prettyJsonString);
output:
{
"id": 5,
"data": {}
}
I'm trying to parse some JSON containing a nested array. I'd like the array to map to a list of child objects within the parent I'm mapping. Here is the (slightly abbreviated) JSON and Java classes
JSON:
{
"id": "12121212121",
"title": "Test Object",
"media$content": [
{
"plfile$audioChannels": 1,
"plfile$audioSampleRate": 18000,
},
{
"plfile$audioChannels": 2,
"plfile$audioSampleRate": 48000,
},
{
"plfile$audioChannels": 2,
"plfile$audioSampleRate": 48000,
}
]
}
Java classes
class MediaObject {
#JsonProperty("id")
private String id;
#JsonProperty("title")
private String title;
#JsonProperty("media$Content")
private List<MediaContent> mediaContent;
... getters/setters ...
}
class MediaContent {
#JsonProperty("plfile$audioChannels")
private int audioChannels;
#JsonProperty("plfile$audioSampleRate")
private int audioSampleRate;
... getters/setters ...
}
I'd like to be able to deserialize using annotations along with the standard mapper code, i.e.
mapper.readValue(jsonString, MediaObject.class)
Everything works fine with the "id" and "title" fields, but my list of MediaContent objects always comes up null. This seems like something Jackson should be able to handle without much trouble, can anyone see what I'm doing wrong here?
The name of the json field is wrong - the attribute is not media$Content, rather media$[c]ontent. Otherwise I do not see why it will not work.