Jackson json only convert selected fields and methods - java

With jackson there is a way to ignore some fields using #JsonIgnore. Is there a way to do the opposite, and only show fields with are annotated? I'm working with an external class with a lot of fields and I only want to select a small subset of them. I'm getting tons of recursion problems (using some type of ORM) where object A -> B -> A -> B -> A .... which are not even necessary to export.

You can configure the object mapper to ignore absolutely everything unless specified by JsonProperty,
public class JacksonConfig {
public static ObjectMapper getObjectMapper(){
//The marshaller
ObjectMapper marshaller = new ObjectMapper();
//Make it ignore all fields unless we specify them
marshaller.setVisibility(
new VisibilityChecker.Std(
JsonAutoDetect.Visibility.NONE,
JsonAutoDetect.Visibility.NONE,
JsonAutoDetect.Visibility.NONE,
JsonAutoDetect.Visibility.NONE,
JsonAutoDetect.Visibility.NONE
)
);
//Allow empty objects
marshaller.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );
return marshaller;
}
}
public class MyObject {
private int id;
#JsonProperty
private String name;
private Date date;
//Getters Setters omitted
in this case only name would be serialized.
Sample repo, https://github.com/DarrenForsythe/jackson-ignore-everything

Yes definitely you can; Create a class with only the feilds you need and add the below property in the object mapper and rest is done.
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES to false

You can use #JsonIgnoreProperties(ignoreUnknown=true) on the pojo class so only the fields which are available in the pojo class will be mapped and resf will be left out.
For example
Json data
{
"name":"Abhishek",
"age":30,
"city":"Banglore",
"state":"Karnatak"
}
pojo class
#JsonIgnoreProperties(ignoreUnknown=true)
Class Person{
private int id;
private String name;
private String city;
}
Here state in not present in the Person class so that field won't be mapped

Related

How to declare a variable or Object of any class type in Java

I am quite new to Java and I am trying to deserialize the JSON using Jackson and I facing some minor issue with regards to declaring the Object/Variable type. I will provide all the codes then explain the issue for easy understanding.
I have an enum that will have the required type values:
public enum IdentifierTypeValues {
Type1,
Type2,
Type3,
//Constructor and Getter of enum values
}
Then for each of these type, I have different classes which will have different input and do a completely different type of process:
public class GenerateType1 {
private String name;
private String age;
//Getter and Setter
//Some required process based on these values
}
public class GenerateType2 {
private String address;
private String city;
private String country;
//Getter and Setter
//Some required process based on these values
}
public class GenerateType3 {
private String firstName;
private String lastName;
private String fullName;
//Getter and Setter
//Some required process based on these values
}
Now I have a wrapper class for these type of classes which will take the type based on enum and typeInfo values. I want the typeInfo values to be any of the class based type something like this:
public class TypeSyntax {
private IdentifierTypeValues indeitiferType;
private GenerateType1 / GenerateType2 / GenerateType3 identifierTypeValues;
//Here the identifierTypeValues can have the values for anytype
//How to declare a variable of any of these class type?
}
This is the class that will be used by my JSON for deserializing. I know I can add a wrapper class of those 3 types and provide that wrapper class as a type class for this. Something like this:
public class WrapperClass{
private GenerateType1 type1;
private GenerateType2 type2;
private GenerateType3 type3;
}
public class TypeSyntax{
private IdentifierTypeValues indeitiferType;
private WrapperClass identifierTypeValues;
//But using this approach will change my JSON structure which I do not want to do.
}
My JSON structure is something like this and I would like to keep it in the same way.
{
"indeitiferType":"Type1",
"identifierTypeValues":{
"name":"Batman",
"age":"2008"
}
}
Is there a way I can declare the variable of multiple type class? or any better approach to handle this by keeping the json format same? I tried searching but I am unable to search what exactly so any help would be really appriciated.
Because the type identifier exists on a different level than the other properties a wrapper class TypeSyntax needed. There are several open feature requests to add wrapping functionality to Jackson e.g. https://github.com/FasterXML/jackson-databind/issues/512
Fortunately polymorphism is supported in Jackson with #JsonTypeInfo and #JsonSubTypes annotations.
Wrapper class should look like:
public class TypeSyntax {
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "identifierType")
private GenerateTypeBase identifierTypeValues;
// getters and setters (omitted for brevity)
}
GenerateTypeBase is the common parent class
#JsonSubTypes({
#JsonSubTypes.Type(value = GenerateType1.class, name = "Type1"),
#JsonSubTypes.Type(value = GenerateType2.class, name = "Type2"),
})
public abstract class GenerateTypeBase {
private String name;
private String age;
// getters and setters (omitted for brevity)
}
In this different children classes will instantiated based on the identifierType property.
The children must extend this base class:
public class GenerateType2 extends GenerateTypeBase {
// additional properties
}
In a short test it will be:
#Test
void wrapperTest() throws IOException {
ObjectMapper mapper = new ObjectMapper();
GenerateType2 a = new GenerateType2();
a.setName("Foo");
a.setAge("13");
TypeSyntax w = new TypeSyntax();
w.setIdentifierTypeValues(a);
String json = mapper.writeValueAsString(w);
System.out.println(json);
}
and the output:
{
"identifierTypeValues":
{
"name":"Foo",
"age":"13"
},
"identifierType":"Type2"
}
Deserialization
#Test
void wrapperTest() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String input = "{\"identifierTypeValues\": \"name\":\"Foo\",\"age\":\"13\"},\"identifierType\":\"Type2\"}";
TypeSyntax w = mapper.readValue(new StringReader(input), TypeSyntax.class);
assertAll(
() -> assertEquals(GenerateType2.class, o.getIdentifierTypeValues().getClass()),
() -> assertEquals("13", o.getIdentifierTypeValues().getAge())
);
}
If you want more flexibility you can write custom (de)serializer and / or custom resolver. Using custom TypeIdResolver that will possible to convert identifiers to types programmatically instead of using "key-value pairs" in #JsonSubTypes

Springboot: Can DTO be changed at runtime with null values not being present in the object returned from api?

I have a springboot application which is hitting raw api's of the datasource. Now suppose I have a Customer entity with approx 50 fields and I have a raw api for it in which I pass names of the columns and I get the values for that column. Now I am implementing api in springboot which consumes raw api.
I need to implement different api's in springboot for different combinations of the fields of Customer entity and return only those fields setted in object for which user had queried and remove the null valued fields from the object. One way is to implement different dto's for different combinations of the columns of Customer entity. Is there any other way to implement the same in which I don't need to define different dto's for different combinations of the columns of Customer entity in Spring boot ???
You can configure the ObjectMapper directly, or make use of the #JsonInclude annotation:
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
OR
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Customer {
private Long id;
private String name;
private String email;
private String password;
public Customer() {
}
// getter/setter ..
}
You can see how to do it with this sample code:
Customer customer = new Customer();
customer.setId(1L);
customer.setName("Vikas");
customer.setEmail("info#vikas.com");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
String valueAsString = objectMapper.writeValueAsString(customer);
Since the password is left null, you will have an object that does not exist password.
{
"id": 1,
"name": "Vikas",
"email": "info#vikas.com"
}
with Jackson 2.0 serialization you can specify data inclusion on non nulls at different levels, i.e. on the object mapper (with constructor options), the DTO class or DTO class fields (with annotations).
See Jackson annotations here
This can be done using #JsonInclude inside the DTO class. Please refer following code block for ignoring null values.
#JsonInclude(Include.NON_NULL) // ignoring null values
#Data //lombock
#Builder //builder pattern
public class Customer {
private Long id;
private String name;
private String email;
private String password;
}

Spring bean property set using xml configuration from other bean property

I have two bean classes like below
package com.abc;
public class Employee{
private String id;
private String name;
//setters & getters
}
and
package com.cda;
public class EmployeeDTO{
private String id;
private String name;
//setters & getters
}
I want to set the property fields from Employee to EmployeeDTO using spring xml configuration. Where data is coming from some other sources to the Employee Object.
Can you please help me on this scenario.
Use BeanUtils from apache or spring framework instead. Be careful about the argument positioning in these two ways. They are exactly opposite:
org.apache.commons.beanutils.BeanUtils.copyProperties(Object dest, Object orig)
OR
org.springframework.beans.BeanUtils.copyProperties(Object source, Object target)
this is actually not a task that spring does for you. Spring is more about wiring all depending objects together that work together during runtime. What you need is a mapper like mapstruct or enter link description here.
Lets consider a scenario
Where Employee gets it data from a datasource and now you want to map it to EmployeeDto
In such cases:
You can add a constructor in EmployeeDto which takes Employee as parameter and maps the field
You can use ModelMapper where a simple line like:EmployeeDto employeeDto = modelMapper.map(employee, EmployeeDto.class); will work
Use BeanUtils import org.apache.commons.beanutils.BeanUtils;
EmployeeDto newObject = new EmployeeDto();
BeanUtils.copyProperties(newObject, oldObject); reference
Use Jackson ObjectMapper by the convertValue() method: (not recommended due to performance issues)
ObjectMapper mapper = new ObjectMapper();
Employee employee = ...;
EmployeeDto employeeDto = mapper.convertValue(employee, EmployeeDto.class);

How to ignore json property in encapsulated design

class A{
private B b;
//other properties
//getter setter
}
// unable to add jsonIgnore in this class due to dependency in other module
class B {
int id;
String name;
String defname;
}
I want to ignore defname in class A JSON building by codehaus.jackson API.
I need {a:{id:value,name:value}}.
You can use Mixin for this purpose.
First Create an abstract class with JsonIgnore annotation:
abstract class MixIn{
#JsonIgnore
abstract String getDefname(); }
Then use it as below. (Be sure your getter name of defName field as getDefName() in your B class or change it in Mixin class as yours.)
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn( B.class, MixIn.class );
objectMapper.writeValue( System.out, new A() );
This prints:
{"b":{"id":1,"name":"Sercan"}}

Want to hide some fields of an object that are being mapped to JSON by Jackson

I have a User class that I want to map to JSON using Jackson.
public class User {
private String name;
private int age;
private int securityCode;
// getters and setters
}
I map this to a JSON string using -
User user = getUserFromDatabase();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
I don't want to map the securityCode variable. Is there any way of configuring the mapper so that it ignores this field?
I know I can write custom data mappers or use the Streaming API but I would like to know if it possible to do it through configuration?
You have two options:
Jackson works on setters-getters of fields. So, you can just remove getter of field which you want to omit in JSON. ( If you don't need getter at other place.)
Or, you can use the #JsonIgnore annotation of Jackson on getter method of that field and you see there in no such key-value pair in resulted JSON.
#JsonIgnore
public int getSecurityCode(){
return securityCode;
}
Adding this here because somebody else may search this again in future, like me. This Answer is an extension to the Accepted Answer
You have two options:
1. Jackson works on setters-getters of fields. So, you can just remove getter of field which you want to omit in JSON. ( If you don't need getter at other place.)
2. Or, you can use the `#JsonIgnore` [annotation of Jackson][1] on getter method of that field and you see there in no such key-value pair in resulted JSON.
#JsonIgnore
public int getSecurityCode(){
return securityCode;
}
Actually, newer version of Jackson added READ_ONLY and WRITE_ONLY annotation arguments for JsonProperty. So you could also do something like this.
#JsonProperty(access = Access.WRITE_ONLY)
private String securityCode;
instead of
#JsonIgnore
public int getSecurityCode(){
return securityCode;
}
you also can gather all properties on an annotation class
#JsonIgnoreProperties( { "applications" })
public MyClass ...
String applications;
If you don't want to put annotations on your Pojos you can also use Genson.
Here is how you can exclude a field with it without any annotations (you can also use annotations if you want, but you have the choice).
Genson genson = new Genson.Builder().exclude("securityCode", User.class).create();
// and then
String json = genson.serialize(user);
Field Level:
public class User {
private String name;
private int age;
#JsonIgnore
private int securityCode;
// getters and setters
}
Class Level:
#JsonIgnoreProperties(value = { "securityCode" })
public class User {
private String name;
private int age;
private int securityCode;
}
if you are using GSON you have to mark the field/member declarations as #Expose and use the GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
Don't forget to mark your sub classes with #Expose otherwise the fields won't show.
I suggest you use this.
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private int securityCode;
This allows you to set the value of securityCode(especially if you use lombok #Setter) and also prevent the field from showing up in the GET request.
I had a similar case where I needed some property to be deserialized (JSON to Object) but not serialized (Object to JSON)
First i went for #JsonIgnore - it did prevent serialization of unwanted property, but failed to de-serialize it too. Trying value attribute didn't help either as it requires some condition.
Finally, working #JsonProperty with access attribute worked like a charm.

Categories

Resources