Jackson ObjectMapper to process JSON and non-JSON inputs - java

TL;DR
How can Jackson's ObjectMapper be made to work for deserializing an object when sometimes the input is serialized JSON and sometimes it is a non-JSON string?
Details
I'm a Java/Jackson noob and have been banging my head against this all day.
I'm working in the context of a system that user ObjectMapper to deserialize inputs. I'm familiar with the Jackson annotations to make that work. And there's no problem when the input is serialized JSON.
The problem is I'm being provided a variety of inputs, some of which are not serialized JSON. I've seen answers related to polymorphic deserialization in which the serialized JSON may come in one of a variety of forms. That doesn't address the issue of how to handle input that is not serialized JSON at all.
I've tried using #JsonDeserialize to specify custom deserializers that extend StdDeserializer and JsonDeserializer. The problem in both cases is the JsonParser passed into the deserialize or deserializeWithType methods processes the input string before reaching my code, and so in the case of a non-JSON input the result is a JsonParseException.
So, is there a way to handle this? I'm working in the context of a larger system that expects ObjectMapper to do the work and, if possible, I'd like not to change that aspect of the system.

Related

Is JSON parsing or String parsing more expensive in Java?

I'm trying to dynamically parse a lot of data in Java. In other words I have tons of different types of data so I am putting them in a String or a JSON String (via GSON) instead of doing:
switch(data){
case instanceof Class1:
Class1 data = gson.fromJson(jsonString);
//Do Stuff for class 1 layout
case instanceof Class2:
Class2 data = gson.fromJson(jsonString);
etc.
So instead of doing this for 80 or so classes (which more may be added/removed/changed at any given time) I am planning to put the data in either a String or Json String and parse out the values (depth first).
I am on a low end PC (single core Atom processor) and am trying to reduce the amount of taxing I put on the CPU, so determining which would be faster... regex string manipulation with splits or using a recursive JSON parser.
Let us discuss both the cases you have mentioned here:
CASE 1:
Creating instances for each and every json input using gson (mapped to a Class)
and
CASE 2: Create a Document (or similar type object) itself and try accessing data from there.
For Case 2, you don't need to write a parser yourself: there are parsers already available.
I'll just write down a jackson example here (There must be similar stuff available with gson as well):
String myJson = "{ \"type\" : \"foo\", \"class\" : 3 }";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode node = objectMapper.readValue(myJson, JsonNode.class);
JsonNode type = node.get("type");
System.out.println(type.asText());
As per my experience, the performance difference hasn't been much in both these cases as the libraries handle the parsing quite efficiently but if you have a lot of different types of JSON, then it doesn't make any sense to create POJOs out of each and every JSON (So much mapping !!).
I have personally not worked with gson because of performance reasons like this but you can create what's called an ObjectMapper using jackson and use it quite efficiently. I assume there should be similar thing in gson as well.
The only downside would be that every field will now be accessible through a string input which might make your code a bit unreadable.
EDIT:
If you really wish to iterate through all the fields of the json, you'll have to do DFS ultimately, but parsing can still be avoided by using the fields method of the JsonNode.
root.fields() will return with an iterator with the entries in it which can be then gracefully used as described in answer here.
Remember, similar stuff with different names will be available in gson too. :)

Gson: fields that sometimes are strings and others arrays

I'm parsing json with Gson but I'm struggling with the data I'm getting. This is part of an API out of my control (openFDA) so changing that might not be an option.
Here's the json I'm strugling with: https://api.fda.gov/device/event.json?search=device.generic_name:generator&limit=10
There are some fields that are not consistent, for example remedial_action. Sometimes it comes out like this:
"remedial_action": [
"Recall"
]
and in other results like this:
"remedial_action": ""
So it's either an array or a plain string. Is there a way to handle this? If not possible in Gson, any other json parsing library that can help?
I created my pojos here in case someone needs the code. There are a few files created from that and didn't want to spam them here. I can add them if needed.
Update: The bug has been confirmed and it's scheduled for a fix.
It is possible through GSON, by using a TypeAdapter.
Here are the initial steps I would use to do that:
Create a POJO that contains the array and the String. Let's call it RemedialAction.
In your original POJO, create an attribute of the new class.
Create a class that extends TypeAdapter<RemedialAction>.
Override the read() and write() methods and create the logic in them.
That should be a little hard to parse, though. Read this tutorial for more information.
Note: you can customize getRemedialAction() to give you only the valid return -- array or String.

Steps to convert a Java object to JSON

During a recent job interview, i was asked the steps taken to convert Java object to JSON using Jackson.
Although, I havent done it before, I have seen examples where Jackson was used and by using object mapper the java object is converted to JSON.
However, the interviewer asked "how and where is the JSON schema set up"
I thought this was done automatically. Does one have to specify how the JSON has to be returned?
I have seen examples where the toString is overriden - is that where the schema is specified.
Thanks
I think the interviewer doesn't mean to ask you how to use Jackson, but how JSON is constructed from a Java Object.
Here's what I thought:
Jackson will detect every field's name as keys;
Iterate the keys to get their values and put it into the JSON.
If a field has child object, it will do step 1 and 2 recursively.
Note: The Java class should implementation the serialization interface.

How to include String, Integer type information when serializing to JSON using Jackson

I have enabled defaultTyping on my object mapper as follows:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
After serialization my JSON string doesn't include type information for java.lang.* types (such as java.lang.String). I'm guessing this is by design.
The problem I run into, is that during deserialization, there are two methods that match: one that accepts an Enum and another that accepts a String. Of course, Jackson cannot decide which method to use. I was hoping that if the type information were included in the serialization step, this should be a non-issue.
I have already gone down the path of #JsonIgnore and Mixins, unfortunately this is not viable.
Any idea how I can get Jackson to deserialize successfully?

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