Jackson JSON converts integers into strings - java

I am using the object mapper to map into an object that has String variables. This works a little too well, because even integers and booleans from the JSON are converted into Strings.
Example:
{"my_variable":123}
class MyClass{
String my_variable;
}
I would like the object mapper to report an error in this kind of situation instead of converting 123 into a string for my_variable. Is this possible?

There is currently no such configuration, but you can override default deserializer with a custom one (see fasterxml wiki) and make that throw an exception?
If you would like a more convenient way you can file a Jira enhancement request; for example, new DeserializationConfig.Feature.COERCE_STRINGS_AS_NUMBERS (default to true) that one could disable to prevent such coercion.

Related

Generate different Java Objects from JSON API Response using Jackson

I'm working on a project at the moment that requires me to take in a various currency pairs and generate a response object from an API call response. I'm using jackson to map the JSON response to java objects then reading data from an ArrayList generated. The problem is the JSON response can have the different currency pairing strings as a key for the list of pairing data. Here's what a typical response looks like:
{"error":[],"result":{"XXBTZUSD":[[1647062100,"39091.2","39184.9","39088.9","39139.0","39150.9","59.22447291",161],}[1647063000,"39138.9","39188.4","39138.9","39151.2","39174.2","2.92905848",126]]}
The problem arises when I try to pull data from a different currency pair as my result object is hard coded to pull the data for the JSON key XXBTZUSD. Here's what my result object looks like:
public class Result{
#JsonProperty("XXBTZUSD")
public ArrayList<ArrayList<Object>> candles;
public int last;
}
I was thinking having the #JsonProperty be variable and pass in the key from the json response to correct pull the currnecy pair I set it to, but JsonProperty needs to be a constant. The only way around this I can see is to have a ton of different classes for each currency pair but that would be inefficient and take around 15 separate classes to do. I'm not too familiar with the jackson library. If anyone has any ideas of how to solve this I would be greatly appreciative, I've been trying to figure out a way around this for awhile now. Thank you!
If keys can be different, one option is to use a Map. Your Result class won't be needed, parse the result property into Map<String, Object>. Then extract like this:
Map<String, Object> result = deserialize();
ArrayList<ArrayList<Object>> arrays = (ArrayList<ArrayList<Object>>) result.get("XXBTZUSD");
Just change property depending on which currency pair you need.
Another option is writing custom deserializer, in which to always put value in your candles field, regardless of how the property is named in json.

Generic approach to deserialize Json to Object

This is a kind of specific question and I couldn't get any information on this topic in the javadoc of Gson.
Currently, I'm trying to parse an Json(1){ "foo":"bar", "bar":"foo" } to an Object Entity. Normally I would map these values to the Entity Object with the fields foo and bar, however I'd like to be more independent from the API.
For (1) I'd have
public class Entity {
String foo;
String bar;
}
But if we test another Endpoint the resulting Json (2) would look like
{ "notFoo":"bar", "notBar":"foo" }
which makes my previous constructed Entity useless, and I'd need to create a new Class with the respective fields for that.
So my actual question is:
Is there a generic (more generic than my example) approach to
push the Json into a GenericEntity -> g.fromJson(response.getBody(),GenericEntity.class); that every field of the json will be successfully mapped, even when using different Endpoints?
Alternatively, are there other dependencies which support that out of the box?
You do not have a deserialisation problem, you have a problem of not knowing how to represent possibly heterogeneous data.
There is no point of saying it should be Object as it should definitely be some type downstream of Object, possibly more than one. Solve this problem first: define all types that you may want to use for all use cases and then you will most likely see how to solve the deserialisation problem.
Surely, for any JSON text defined between {...} you can always go for Map<String, Object> where Object is one of:
further Map<String, Object> where Object follows these rules
List<Object> where Object follows these rules
String
one of atomic types or their boxed values
With the above rules you can represent more or less everything and you can write Gson deserialisers to deliver you those types based on the JSON type of each node (while iterating via the JSON tree). However, it is not really clear what use could you make of such a heterogenous untyped data structure.
You can use the annotation #serializedName as written in Multiple GSON #SerializedName per field?. But the schema must be the same, you only have alternatives to key name.

Jackson: avoid deserialization of some fields but not ignoring them

i need to carry all the json data (to store them, log, return) but i will never access them from code. is there any way to avoid deserializing them but still use them during serialization?
class MyObject {
int importantField; // i want this field to be properly deserialized
String notImportantJsonGarbage; // i don't care what's here. it must be a valid json
}
So now i'd like to be able to deserialize it from
{"importantField":7, "notImportantJsonGarbage":{"key1":3, "key2":[1,2,3]}}
and later serialize it to the same string
UPDATE
i don't want to ignore this property. i need this data. but as a string, not fully deserialized object
i need to be able to do:
json1 -> object -> json2
json1 == json2
Take a look at: JsonProperty.Access
AUTO - Access setting which means that visibility rules are to be used to automatically determine read- and/or write-access of
this property.
READ_ONLY - Access setting that means that the property may only be read for serialization, but not written (set) during
deserialization.
READ_WRITE - Access setting that means that the property will be accessed for both serialization (writing out values as
external representation) and deserialization (reading values from
external representation), regardless of visibility rules.
WRITE_ONLY - Access setting that means that the property may only be written (set) for deserialization, but will not be read
(get) on serialization, that is, the value of the property is not
included in serialization.
So in your case you could use it like this:
#JsonProperty(access = Access.READ_ONLY)
private String notImportantJsonGarbage;
You can use annotation #JsonIgnoreover the property that you wish to ignore
You can use the type JSONObject for the Json field.
private JSONObject notImportantJsonGarbage;
And when you need to read that, you can convert it to a String (or other type). You can use jackson or gson libraries to achieve that.
Note that when you convert the JsonObject back to String, the resulting string might have the quotes escaped.
Using JSONObject also solves your requirement of 'must be a valid json object'.

Using reflection to set property values where types are unknown

I am using reflection to set value object properties at runtime. If everything were a string, I may not be asking this question, but that's not the case. I have a web service that returns json and I want to use the json returned by the service to populate the object. I have an ArrayList of strings called alphabeticalKeys that contains sorted keys in the json string. Here is the code I am using to dynamically populate the object (user):
for(String fieldName : alphabeticalKeys){
Log.d("JSON:" + fieldName, json.getString(fieldName));
Field f = userClass.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(user, jsonObject.get(fieldName));
}
In the json data set, there are strings, doubles and more. This is part of a factory class where the type of object being returned is unknown at compile time. Also, the json fields' data types may vary depending on the type of object needed.
The json output matches the field names in the returned object, so I am looking for a way to handle the different data types returned in the json output. Can somebody offer up a suggestion?
Thx! Vivian
There are libraries available to aid in setting property values using reflection, converting to the appropriate type if necessary. For example, Spring Framework's BeanWrapper and Apache Commons BeanUtils.
There are also json libraries that will handle mapping json to/from java objects. For example, Gson and Jackson. This may make it easier, especially if the json structure closely matches the java object structure.

Jackson: Custom JSON deserializer

I am using Jackson library's ObjectMapper for deserializing JSON into Java objects. I am using Spring 'wiring'. I have created custom deserializers to do the conversion from JSON string to POJO. However, when the input is bad (eg. a number is passed as "124A" - illegal character) a default deserialiser is invoked and bombs with the NumberFormatException. Is there a way to prevent default converters from being called?
Ok, given that input is not valid JSON (numbers can not start with or contain '$'), deserializer will not be called, and any change would have to apply to parser. There are no switches in Jackson to allow such content to be considered numbers.
If you can control input, just change value to a String (add double-quotes around value). Parser then passes it as JSON String, and data binding components get a chance to handle it (JsonDeserializer).

Categories