How to deserialize the following json using Jackson - java

I have the following json:
{
"id":"myid",
"fields":{
"body":"text body"
}
}
which I want to deserialize into the following Java class:
class TestItem {
private String id;
private String body;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
using the Jackson Json deserializer. This doesn't work because the body field is nested inside a fields inner class.
I can't change the json structure, so is there any way (perhaps using annotations) I can remap of the body field up from TestItem.fields.body to TestItem.body?
Edit:
I should have said this is part of a larger class hierarchy and the aim of the excercise is to reduce the depth of it. In other words, I know that I COULD declare an inner class and then access that, but that is not what I'm trying to achieve.

There are couple of feature requests that (if implemented) would allow limited one-level wrapping/unwrapping. But currently there is no declarative way to do this. And to some degree it is edge case, since this goes into data transformation as opposed to data binding (unfortunately I can't think of good object transformation libs, so there may be bit of gap there).
What is usually done, then, is to do two-phase binding: first into intermediate types (often java.util.Map, or jackson JsonNode (Tree model)); modify those, and then convert from this type to actual result. For example something like this:
JsonNode root = mapper.readTree(jsonSource);
// modify it appropriately (add, remove, move nodes)
MyBean bean = mapper.convertValue(root, MyBean.class);

Related

Use DTO to map JSON to final object, or just parse JSON?

I have some json object that looks like this:
{
"make":"Volvo",
"model":"240",
"metadata":{
"color":"white",
"year":"1986",
"previousOwner":"Joe",
"condition":"good"
}
}
And I want to turn this JSON into List<Car>, which is comprised of the following objects:
public class Car {
private String make;
private String model;
private CarMetadata carMetadata;
}
public class CarMetadata {
private Body body;
private History history;
}
public class Body {
private String color;
private String condition;
}
public class History {
private String previousOwner;
private String year;
}
So essentially the point is that the object I want to turn it into (Car) is very nested, whereas my JSON is not very nested. In reality the "Car" object is actually much more nested than this example I'm showing.
I was thinking of two options:
Create a CarDTO object to represent my input JSON, do objectMapper.readValue(json, CarDTO.class), then map CarDTO to Car to create my List<Car>.
Just parse the JSON and create the final List<Car> object in the first place.
I don't want to create an unnecessary DTO, but I also don't want to mess with parsing this JSON.
Is there a best practice in this scenario, and would this even be a valid use of a DTO?
Use a DTO.
Although you can deserialize from json directly to your domain class, their structure differs so you would have to create a custom deserializer... DO NOT TRY THIS AT HOME. I've been there and it's completely not worth the hassle.
Use the DTO to parse the json into a POJO, then map the DTO to the domain object.
This will decouple the transport from your domain object, allowing both to change freely with only the mapping code being affected. It's also way easier to write, understand, test and debug.

Jackson: How do I post-process JsonNode during serialization?

I am attempting to implement the HL7 FHIR spec's assertion that JSON representing a FHIR model will not have empty objects nor empty arrays. For the sake of not making the lives of my consumers any harder, I'm not strictly enforcing this during deserialization, but I want to ensure the serialized JSON produced by my library conforms as specified. I am using Java and Jackson ObjectMapper to serialize Objects into JSON. My understanding from writing a custom serializer is that the Object is at one point represented as JsonNode, regardless of what you are converting to.
What I would like to do is intercept the JsonNode as it exits the serializer, make some adjustments to it (find and remove empty arrays and objects), and then let it continue on its way. I need to do this in an environment where I can't tweak the ObjectMapper, because I don't have access to it. And further, the complex hierarchy of models in this library use Jackson's default serialization with annotations etc. heavily, and I cannot eliminate this.
If I go the route of defining a custom serializer for the base type, let's say "Resource", then I have a problem, because I still need the original serializer's output in order to generate my modified output. And further, that needs to accommodate any custom serializers that may already exist on various types within the model.
I got pretty far with the above option using https://www.baeldung.com/jackson-call-default-serializer-from-custom-serializer and the last option, implementing BeanSerializerModifier, but I ran into the issue where I can't control the ObjectMapper that my library consumers use.
Example POJOs (Using Lombok for accessors):
#Data
#JsonInclude(JsonInclude.Include.NON_EMPTY)
#JsonIgnoreProperties(ignoreUnknown = true)
abstract class Resource {
private FhirString id;
private List<Extension> extension;
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
public abstract ResourceType getResourceType();
}
#Data
#Builder
class SomethingElse extends Resource {
FhirUri someProperty;
CodeableConcept someCode;
List<Reference> someReferences;
#Override
public ResourceType getResourceType() {
return ResourceType.SOMETHING_ELSE;
}
}
And an example instance of the SomethingElse class:
SomethingElse somethingElse = SomethingElse.builder()
.someProperty(FhirUri.from("some-simple-uri"))
.someCode(new CodeableConcept())
.someReference(List.of(new Reference()))
.build();
somethingElse.setId(FhirString.randomUuid());
somethingElse.setExtension(new ArrayList<>());
When I tell any mapper (or, for example, use a Spring service) to map the SomethingElse class into JsonNode, I can, for example, end up with empty objects and arrays, like this:
ObjectMapper mapper = getUntouchableMapper();
JsonNode somethingElseNode = mapper.valueToTree(somethingElse);
System.out.println(somethingElseNode.toString());
Becomes:
{
"resourceType": "SomethingElse",
"id": "00000000-0002-0004-0000-000000000000",
"someProperty": "some-simple-uri",
"someCode": {},
"someReferences": [{}],
"extension": []
}
According to FHIR, this should actually look like:
{
"resourceType": "SomethingElse",
"id": "00000000-0002-0004-0000-000000000000",
"someProperty": "some-simple-uri"
}
To summarize
How do I preserve the serialization mechanisms already in place, regardless of the ObjectMapper used, and somehow remove empty lists and objects from outgoing JSON produced by the Jackson serialization process?
Edit:
I also tried #JsonInclude(JsonInclude.Include.NON_EMPTY), which did omit empty list implementations. However, the vast majority of data in this library is represented by POJOs that serialize to maps and primitives, and this annotation only works if they are represented directly by maps and primitives in the model.
The solution is to use a custom #JsonInclude, which is new in Jackson 2.9. Thank you #dai for pointing me back towards this functionality.
On the base Resource class, this looks like:
#JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = FhirJsonValueFilter.class)
class Resource implements FhirTypeInterface {
...
#Override
public boolean isEmpty() {
//Details omitted for simplicity
}
}
For visibility, the interface used above:
interface FhirTypeInterface {
boolean isEmpty();
}
And my custom definition for FhirJsonValueFilter implements all of the functionality of JsonInclude.Include.NON_EMPTY but also adds functionality for checking against a method implemented by FHIR types (implementation of this is not relevant to the answer).
public class FhirJsonValueFilter {
#Override
public boolean equals(Object value) {
return !getWillInclude(value);
}
/**
* Returns true for an object that matched filter criteria (will be
* included) and false for those to omit from the response.
*/
public boolean getWillInclude(Object value) {
//Omit explicit null values
if (null == value) {
return false;
}
//Omit empty collections
if (Collection.class.isAssignableFrom(value.getClass())) {
return !((Collection) value).isEmpty();
}
//Omit empty maps
if (Map.class.isAssignableFrom(value.getClass())) {
return !((Map) value).isEmpty();
}
//Omit empty char sequences (Strings, etc.)
if (CharSequence.class.isAssignableFrom(value.getClass())) {
return ((CharSequence) value).length() > 0;
}
//Omit empty FHIR data represented by an object
if (FhirTypeInterface.class.isAssignableFrom(value.getClass())) {
return !((FhirTypeInterface) value).isEmpty();
}
//If we missed something, default to include it
return true;
}
}
Note that the custom omission filter uses Java's Object.equals functionality, where true means to omit the property, and I've used a second method to reduce confusion in this answer.

Handle Json non existent keys spring boot

I am creating a requestModel and let say a person doesn't send me some keys.
If that key is not present I want to put null if i get the value of the key.
I don't want to investigate if a key is present or not .
public class CustomerModel {
private Optional<String> s3Bucket;
private Optional<String> docType;
public String getS3Bucket() {
if(s3Bucket.isPresent()) {
return s3Bucket.get();
} else {
return null;
}
}
public void setS3Bucket(Optional<String> s3Bucket) {
this.s3Bucket = s3Bucket;
}
public Optional<String> getDocType() {
return docType;
}
public void setDocType(Optional<String> docType) {
this.docType = docType;
}
}
Do we have any library or something where.
1. If i get the key and it is not present in the coming request json, i will get the null out of it and if the key is present and has value . It will be stored as value.
2. When writing the getter for s3bucket (getS3Bucket), i dont want to write it for everykey value. Is there a automatic way to do this.
I looked at lot of posts but the scenario is not there.
P.S - I am new to java
I believe Jackson is exactly what you need. And if you are using Spring - it already uses Jackson under the hood I guess.
Here you can find some examples and documentation of how JSON mapping on to model class is done.
If you need to customize some behavior, you can use annotations like #JsonProperty (there are many).
If properties in your model class have the same names as properties in JSON, most probably you won't need to provide any further configs.
Here is a simple example:
public class User {
#JsonProperty("userName")
private String name;
private int age;
// getters and setters
}
And if you have JSON like this:
{
"userName" : "Foo Bar",
"age" : 18
}
Jackson will do all the magic for you unless you need something very specific.
If something is not in JSON you get (let's say you received JSON without age) - corresponding property in model class will be null if it is object type and default value (0, false, etc.) for primitives (in our case age would be 0).

Serialization pojo into different json structure

I need to serialize a pojo into different json structure depending on whom I am sending request. Also I should be able to configure in some config that how field of pojo are mapped to json properties for a given request.
Can this be achived using jackson?
Is there some library or api to do this?
Edit:
For example:
public class Universal {
private int id;
private Date date;
private String name;
private Inner inner;
private Map<String,Object> others;
private List<Inner> inners;
}
public class Inner {
private String value;
}
now above are two object i need to create dynamic json, one example for some of transformation is below
{
"id":"",//value will be id of Universal
"detials":{
"name":"",//value will be name of Universal
},
"data":[], // array of value(field of Inner) from inners
"ext":{
"prop1":""// value of this field will be some (key1) value from others
}
}
You can use Google Gson and rely on its type adaptors.
http://www.javacreed.com/gson-typeadapter-example/ is a good article from web

Jackson vs Gson for simple deserialisation

For parsing JSON like this twitter API users/show response I've been using Jackson and Gson Java libraries as candidates to do this work. I'm only interested in a small subset of properties of the JSON so Gson was nice because of its very concise syntax but I'm losing an internal battle to continue to use Gson as Jackson is already used elsewhere in our application and it has documented better performance (which I concede are both good reasons to lose Gson).
For a POJO like
public class TwitterUser {
private String id_str;
private String screen_name;
public String getId_str() {
return id_str;
}
public void setId_str(String id_str) {
this.id_str = id_str;
}
public String getScreen_name() {
return screen_name;
}
public void setScreen_name(String screen_name) {
this.screen_name = screen_name;
}
}
The only code for Gson needed to build this is one line,
TwitterUser user = new Gson().fromJson(jsonStr, TwitterUser.class);
That's pretty nice to me; scales well and is opt-in for the properties you want. Jackson on the other hand is a little more laborious for building a POJO from selected fields.
Map<String,Object> userData = new ObjectMapper().readValue(jsonStr, Map.class);
//then build TwitterUser manually
or
TwitterUser user = new ObjectMapper().readValue(jsonStr, TwitterUser.class);
//each unused property must be marked as ignorable. Yikes! For 30 odd ignored fields thats too much configuration.
So after that long winded explanation, is there a way I can use Jackson with less code than is demonstrated above?
With Jackson 1.4+ you can use the class-level #JsonIgnoreProperties annotation to silently ignore unknown fields, with ignoreUnknown set to true.
#JsonIgnoreProperties(ignoreUnknown = true)
public class TwitterUser {
// snip...
}
http://wiki.fasterxml.com/JacksonAnnotations
http://wiki.fasterxml.com/JacksonHowToIgnoreUnknown

Categories

Resources