Low level JSON manipulation library for Java - java

I am looking for a 3rd party library which can manipulate entities stored as JSONs.
This is intended to be used in the (cucumber) test framework to specifically tailor predefined JSON requests to a specific situation.
For example let`s consider the following JSON
{
"user": {
"name": "Bob",
"age": 27,
"email": "bob#something.com"
}
}
Naturally the JSON above has it`s appropriate POJO which is used by the application/test framework.
In the feature file this should look something like:
Given predefined user Bob with changes:
|node |newValue|
|user.age|-5 |
When I register Bob
Then expect error INVALID_AGE.
In this case before the entity is deserialized its age attribute would be replaced by -5 thus when we receive the POJO it already has -5 in it.
Something like this should be achievable with the ObjectMapper, navigate the JSON node by node and update some values.
This is required to ensure that we do not have to change code in the step definitions in case the API changes (fields get added or removed). Naturally the feature files themselves need to be updated but this can be done by non developers.
Also with this approach its easy to create a generic JSON template and only update specific fields instead of in each scenario to create a complex entity from scratch.
Does such a library or something similar exist?

Related

How to extract any multi-layer nested T object from a JSON WebClient response, given consistent parent fields across all responses?

I'm building a SpringBoot Client (leveraging WebClient for the actual call) that will be retrieving data from a Vendor's REST API (so we have no control over the response structure). Regardless of the endpoint that is called, all responses are wrapped in either
{
"data": {
"attributes": {
// DESIRED FIELDS
}
}
}
or
{
"data": [
{
"attributes": {
// DESIRED FIELDS
}
},
{
"attributes": {
// SAME DESIRED FIELDS WITH DIFFERENT VALUES
}
},
...
]
}
The only way data + attributes would ever be used is to access the data wrapped within them, so I'm looking for an "invisible hand" that I could setup to automagically extract out and return only the inner POJO(s), preferably during the de-serialization process.
There are ~30 POJOs (which can be combined into any hierarchy/relationship structure as required) that have been created to represent the different responses we can get back from the vendor (packaged into an in-house jar for reuse), so writing a custom deserializer/builder/unpacker/etc for each one isn't really an option, and I'm hitting a wall trying to make a generic deserializer or decoder.
As we have no control/influence over the way the Vendor returns the data, leveraging Jackson's Polymorphic deserialization isn't an option here AFAIK, since there's no way to embed identity fields into the serialized data, nor are there any unique, native fields that could serve to reliably identify any given root/parent object in their JSON (the vendor loves to reuse generic fields, like id and name).
Given this, is there an approach that could allow for behind-the-scenes extraction? Even something like intercepting any JSON de-serialization attempt, looking for the data (both array + object permutations) + attribute fields, then manually manipulating the JSON into the desired structure would work, but I can't find any WebClient or Jackson documentation that suggests the existence of a, i guess "detour", de-serializer/decoder that would allow the chain to continue as normal after restructuring.
Worst comes to worst, I can create a generic wrapper class with helper methods to extract the underlying POJOs post-deserialization, and that can be used in combination with WebClient's chained calls, but that doesn't reduce the bloat/boilerplate all that much.

Deserializing selected property names only (Jackson)

Let's say we have following JSON,
{
"id": "imgsId1",
"type": "Fruits",
"name": "Tropical",
"image":
{
"url": "images/img1.jpg",
"width": 300,
"height": 300
},
"thumbnail":
{
"url": "images/thumbnails/img11.jpg",
"width": 50,
"height": 50
}
}
And in Java Class, we have all fields matching with above JSON.
Each time list of fields to be Deserialized depends on customer who sends the information.
For example for customer 1, we want to only read back following values, (and skip other properties even if provided in JSON)
String[] propertiesToFilter1 = {"type","image.url"};
For example for customer 2, we want to read back following values, (and skip other properties even if provided in JSON)
String[] propertiesToFilter2 = {"type","image.url", "image.width"};
When Deserializing JSON using Jackson, is it possible to provide above array which includes which fields need to be Deserialized,
ImageInfo obj1 = (ImageInfo)objectMapper.readValue(jsonStr, ImageInfo.class);
Update:
On researching on net, i saw that one of the options could be via using
FilterProvider filterProvider = new SimpleFilterProvider().addFilter("filterName1",
SimpleBeanPropertyFilter.serializeAllExcept(propertiesToFilter1));
objectMapper.setFilters(filterProvider);
But i think this is good, if we want to keep reusing the same "filterName1" for multiple customers.
In this scenario, it's little bit different because, we customize list of fields each customer can update. So each customer has different list of JSON fields they can update in different classes.
If we start defining different filter names for each customer, it will be a long list, and lookup will have performance impact.
So was looking for solution, where i can check list of fields allowed to be processed at runtime, when constructing back object using objectMapper.readValue() method.
Update 2 (Apr 25 2016):
Going through other Jackson questions, saw a similar question here,
Jackson Dynamic filtering of properties during deserialization
Using the approach listed below by creating custom "static ObjectMapper", the issue with this approach is we running Reflection API multiple times.
First time Jackson parser is populating all fields using
Reflection API when Deserializing JSON to Java Object
Second time, since we can't take all fields that were populated by
Jackson parser, for populate data into another object, we again need to run through Reflection API to populate another object.
This could result in lot of overhead.
Using the approach defined in above link provided, i think using "BeanDeserializerModifier" seems to be best approach. Now the question is, since we are also using Factory based approach to initialize ObjectMapper, we don't want to hard code all arrays for different customers.
Wanted to check if it's possible to provide the String[] array with list of Properties to be considered at runtime to "BeanDeserializerModifier"?
something similar to,
String[] propertiesToFilter2 = {"type","image.url", "image.width"};
BeanDeserializerModifier curBeanDeserializerModifier =
getBeanDeserializerModifierInstance();
curBeanDeserializerModifier.setPropertiesToConsider(propertiesToFilter2);
Thanks
use #JsonIgnoreProperties with configure parameters
http://www.programcreek.com/java-api-examples/index.php?api=com.fasterxml.jackson.annotation.JsonIgnoreProperties
I am not sure if there is a possibility to configure the deserialization dynamically with annotations.
I would suggest to create a class with a static ObjectMapper. In this class you can create different implementations of deserialization. The business logic of your application should then decide which implementation should be used for which customer. Inside your different implementations you are able to configure the ObjectMapper like you do it with annotations.
A second solution can be to deserialize the full json for every customer and let the business logic decide which fields/objects of the Pojo is used. This needs also an implementation in your application.
The benefit of the implementation of the configuration in the business logic is that you will have cleaner code and one place where your configuration is done for every customer.
static ObjectMapper information

Spring/Jackson Mapping Inner JSON Objects

I have a RESTful web service that provides JSON that I am consuming. I am using Spring 3.2 and Spring's MappingJacksonHttpMessageConverter. My JSON looks like this:
{
"Daives": {
"Daive": {},
"Daive": {},
"Daive": {},
"Daive": {}
}
}
Now everything I have read seems to indicate that this JSON should be refactored to an array of JSON Daives. However, this is valid JSON so I want to make sure that I am thinking correctly before going back to the service provider to ask for changes. In the format above, I would have to know ahead of time how many Daives there are going to be such that my DTO accounted for them. The handy dandy Jackson mapper isn't going work with this kind of JSON setup. If the JSON was altered to provide and Array of JSON Daives, I could use a List to dynamically map them using Spring/Jackson.
Am I correct? Thanks :)
According to this thread, the JSON spec itself does not forbid multiple fields with the same name (in your case, multiple fields named "Daive" in the object "Daives").
However, most parsers will either return an error or ignore any value but the last one. As you said, putting these values into an array seems much more sensible; and indeed, you'll be able to map this array to a List with Jackson.

Converter from Json into groovy CODE?

It's a kind of odd question for an odd situation. I have a large JSON structure which I would like to represent in running groovy code. I need groovy objects that mirror the same structure as the JSON objects.
As to be expected a web search mostly returns results with groovy/json runtime conversion stuff, but nothing about things that output groovy code.
You might think this lazy but really it is a massive JSON structure! A converter would save days!
You can use Groovy's own JsonSlurper to parse JSON objects:
import groovy.json.*
def json = '{"name":"john", "surname":"doe", "languages": ["groovy", "python"]}'
def obj = new JsonSlurper().parseText(json)
assert obj.name == "john"
assert obj.surname == "doe"
assert obj.languages.containsAll("python", "groovy")
Of course the class is untyped: it's only known at runtime. If you want it to be typed, you can write a code which writes the code based on an example (since a json schema may be rare).
EDIT: if you want to generate the model classes code, you can try JSONGen, which "parses JSON to create client side source files to model the JSON data structure". I'm not aware of a solution for Groovy, but since java-groovy integrations is seamless, it shall work fine.
If you want a Groovy representation of your JSON, you can get that via the built-in JsonSlurper. This will give you Java Maps and Lists of data you can work with.
You can populate more specific, custom objects you've written to represent your JSON entities using the (3rd party) Jackson's data binding functionality (see this question as well).
Try using a JSON parser like this one. According to its documentation you just need to do
JSON.parse
to deserialize the data

JSON duplicated properties validation via Jackson

I use Jackson and want to check that input JSON string doesn't contain duplicated properties like:
{"a" : 1, "a" : 0}
Following Jackson fragment process input string without any errors and even return value:
JsonNode jsonSelect = mapper.readTree("{ A : 1, A : 0}");
System.out.println(jsonSelect.getFieldValue("A")); // prints 0
Does I have a chance to validate duplicates via Jackson?
P.S. Does JSON format support duplicated properties at all? I didn't find any restrictions about it in specification. Also org.json.JSONObject throws an exception for duplicates that doesn't give me an answer - is {"a" : 1, "a" : 0} well-formed according to standard.
JSON specification indicates duplicates are not consider valid, but parsers are not required to do anything about them. From practical perspective, keeping track of all seen properties adds overhead, which may not make sense at streaming parser level.
As to Jackson, it used to have duplicate detection at data binding level, but I think that is not enabled at this point. It could be added fairly easily when dealing with Maps.
If this is something you would want, filing a feature request or asking on user list might make sense (esp. to see if others would want this feature too, making it more likely to get added soon).
If all you want to do is just validation, you could create a Map subclass, make it throw exception on duplicate. Or, just set a flag in sub-class that you can check if you prefer.
JSON does not support duplicated properties. So if your input is guaranteed to be valid JSON you don't have to check for them.

Categories

Resources