Jackson: how to read a String as List? - java

Our current class looks like
public class Attributes {
private String mapping;
.....
and
{
"mapping": "displayName",
.....
This has worked well and shipped to customers.
The way we convert JSON to Attribute class is
JSON.readValue(jsonFile, Attribute.class);
Recently the requirement says, that mapping would be List<String> instead of String
At first, the quick change that I thought of was to change mapping to List<String>, but this would break existing clients.
I tried that by writing test that does
assertEquals("displayName", configuration.getMapping().get(0));
and it failed as
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
Question
How can I tell Jackson to read a String as `List? It would be List of 1 item but would be backward compatible.
Thanks

The answer is Can not deserialize instance of java.util.ArrayList out of VALUE_STRING
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

Related

How to fix invaliddefinitionexception when using ObjectMapper on Pojo that has org.json.JSONObject

I'm not sure if this type of problem was already asked. I couldn't find, so asking
I have a POJO
Class A {
int id;
Object data;
//getter and setters
}
I set org.json.JSONObject type json into data
Option 1:
When I set data to object directly, I get an error from ObjectMapper when doing
objectMapper.writeValueAsString(anInstanceOfA);
Error: InvalidDefinitionException: No serializer found for org.json.JSONObject
{ I assume the problem is between fasterxml and org.json }
Option 2:
If I use toString on JSONObject before setting to an instance of A, I see escape character in the output. The output is unacceptable. Can't sacrifice JSON formatting and structure
Is there a way to leave already JSON structured element as-is, with less conversions?

Deserializing JSON containing invalid class identifiers

In Java, using Jackson, I want to deserialize JSON that looks something like this:
{
"123_ABC": {
"XYZ": 768,
"123_DATA": {
"123_DEF": "",
"123_ACT": "ZAC",
"123_PAG": {
"123_PAG_A": 1,
"123_PAG_B": 1
}
}
}
}
You all know that identifiers starting with a number are invalid in Java (and every programming language I ever heard of.)
I already know how to use #JsonProperty to translate field names, but handling class names is outside my knowledge.
If I define classes corresponding to the structure of the JSON, but with valid class names, is there a way to use Jackson annotations to map the invalid class id in the JSON to my valid class names?
I think #JsonProperty should be good to deserialize this.
Let's create a wrapper class that will have 123_ABC as a property of class ValidClass.
class Wrapper {
#JsonProperty("123_ABC")
private ValidClass validName;
}
Now, when you serialize, it will create JSON like this (or can be deserialized using that)
{ "123_ABC":{ //PROPERTIES OF ValidClass HERE } }
Similarly, you can have different properties in further inner classes.
In case if you to support 123_ABC only for deserialization and serialize with correct field names, you can do like this
#JsonAlias("123_ABC")
private ValidClass validName;
it will serialize to following.
{"validName": {//properties}}
but deserialization can be done using both
{"validName": {//properties}}
{"123_ABC": {//properties}}
In case, if keys keep changing, I would suggest to deserialize them in Map.

Jackson deserialize JSON with extra properties using #JsonRootName

I want to deserialize an object which is annotated with #JsonRootName. However the JSON in which the object is transported contains another extra property. As a result Jackson is complaining with:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (FIELD_NAME), expected END_OBJECT: Current token not END_OBJECT (to match wrapper object with root name 'account'), but FIELD_NAME at [Source: (ByteArrayInputStream); line: 1, column: 26].
Apparently deserialization of #JsonRootName annotated objects works ONLY if that object is the sole property in JSON file - since it's not expecting the "lastTransactionID" to be there.
Here's my Account class:
#JsonRootName("account")
public class Account {
private String id;
}
This is the JSON I need to deserialise:
{
"account": {
"id": "1234"
},
"lastTransactionID": "1"
}
Since I'm using spring I have this setup also spring.jackson.deserialization.unwrap_root_value=true.
Is there any way to solve this without:
having to write a custom deserializer?
OR
intercepting the response and stripping it of the extra property before deserialization takes place?
It looks like simplest way to solve this issue is create wrapper for Account class and deserialise json as usual with disabled DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES feature.
public static class Wrapper {
public Account account;
}
In this case other fields will be ignored.
It's not a nice solution, I know, but it solve a problem.
We can use ObjectMapper to Map json to java Objects.
public Account jsonToObject(Map<String, Object> map){
ObjectMapper objectMapper = new ObjectMapper();
Account account = objectMapper.convertvalue(map.get("account"),Account.class);
return account;
}
You can use JsonIgnoreProperties(ignoreUnknown=true) annotation on your Account class. Please refer below link for more details.
https://www.thetechnojournals.com/2019/10/entity-object-conversion-to-dto-object.html

How do I get a list of JSON objects out of an array among other objects using Spring RestTemplate?

I'm trying to consume this data
https://api.nasa.gov/neo/rest/v1/neo/browse?api_key=DEMO_KEY
following the tutorial from
http://spring.io/guides/gs/consuming-rest/
I successfully retrieve the "links" and "page" portions of the data, but the array of near_earth_objects is null.
I tried what was suggested in this post:
Get list of JSON objects with Spring RestTemplate
But my situation is a little more complicated because it's more than just one array filled with objects as seen in
http://bitpay.com/api/rates
Top answer gives error:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not
deserialize instance of java.lang.Object[] out of START_OBJECT token
Here is what my POJO looks like:
#JsonIgnoreProperties(ignoreUnknown = true)
public class NearEarthObjectBrowse {
#Id
private Links links;
private Page page;
private NearEarthObject[] near_earth_objects;
I also tried using a wrapper class for the NearEarthObject array and still was unable to marshal successfully.
Is there a better way to go about doing this in general?
Edit: I believe the structure of NearEarthObject matches the data. Here is my github
Try to use A list instead of an array for near_earth_objects
#JsonProperty("near_earth_objects")
private List<NearEarthObject> near_earth_objects;

convert json to object using jackson

I have to convert a json into an object using jackson. The class is like:
class Country {
int a;
int b;
}
And the json i am getting:
{"country":{"a":1,"b":1}}
But when i am trying to deserialize this its giving me following error
org.codehaus.jackson.map.JsonMappingException: Unrecognized field "country"
If i remove "country", i am able to get the object.
Is there any way i can tell jackson to just ignore "country" from the json string?
Thanks in advance.
This is the correct behavior of Jackson, the actual json representation of Country object should be without the top level country. If your json absolutely has the top level country attribute, a cleaner approach would be to use a wrapper Country class like this:
class WrapperCountry {
Country country;
}
this way the json representation should correctly deserialize to the WrapperCountry object and you can retrieve country from that.

Categories

Resources