How to change a field name in JSON using Jackson - java

I'm using jackson to convert an object of mine to json.
The object has 2 fields:
#Entity
public class City {
#id
Long id;
String name;
public String getName() { return name; }
public void setName(String name){ this.name = name; }
public Long getId() { return id; }
public void setName(Long id){ this.id = id; }
}
Since I want to use this with the jQuery auto complete feature I want 'id' to appear as 'value' in the json and 'name' to appear as 'label'. The documentation of jackson is not clear on this and I've tried every annotation that even remotely seems like it does what I need but I can't get name to appear as label and id to appear as value in the json.
Does anyone know how to do this or if this is possible?

Have you tried using #JsonProperty?
#Entity
public class City {
#id
Long id;
String name;
#JsonProperty("label")
public String getName() { return name; }
public void setName(String name){ this.name = name; }
#JsonProperty("value")
public Long getId() { return id; }
public void setId(Long id){ this.id = id; }
}

Be aware that there is org.codehaus.jackson.annotate.JsonProperty in Jackson 1.x and com.fasterxml.jackson.annotation.JsonProperty in Jackson 2.x. Check which ObjectMapper you are using (from which version), and make sure you use the proper annotation.

Jackson
If you are using Jackson, then you can use the #JsonProperty annotation to customize the name of a given JSON property.
Therefore, you just have to annotate the entity fields with the #JsonProperty annotation and provide a custom JSON property name, like this:
#Entity
public class City {
#Id
#JsonProperty("value")
private Long id;
#JsonProperty("label")
private String name;
//Getters and setters omitted for brevity
}
JavaEE or JakartaEE JSON-B
JSON-B is the standard binding layer for converting Java objects to and from JSON. If you are using JSON-B, then you can override the JSON property name via the #JsonbProperty annotation:
#Entity
public class City {
#Id
#JsonbProperty("value")
private Long id;
#JsonbProperty("label")
private String name;
//Getters and setters omitted for brevity
}

There is one more option to rename field:
Jackson MixIns.
Useful if you deal with third party classes, which you are not able to annotate, or you just do not want to pollute the class with Jackson specific annotations.
The Jackson documentation for Mixins is outdated, so this example can provide more clarity. In essence: you create mixin class which does the serialization in the way you want. Then register it to the ObjectMapper:
objectMapper.addMixIn(ThirdParty.class, MyMixIn.class);

Related

Is which the best request parameter mapping strategy in Spring Framework?

I am Java web developer, usually develop Spring MVC.
I have been using #RequestMapping or #RequestParam for mapping to hashMap at Controller.
It is a terrible way. I should always cast type when using value.
But nowadays I try to use #ModelAttribute to write clean code at Controller.
However, there are some problem.
case 1) make DTO for each EndPoint.
We can make DTO for each EndPoint, but DTO will have many duplicated property.
#Getter
#Setter
#ToString
class GetUserInfoDTO {
private String id;
private String name;
}
#Getter
#Setter
#ToString
class PostUserInfoDTO {
private String name;
private Integer age;
private String address;
private String gender;
private String email;
private Date joinDate;
}
in controller,
#GetMapping("/user")
public ResultDTO getUserInfo (#ModelAttribute GetUserInfoDTO){
...
return ResultDTO;
}
#PostMapping("/user")
public ResultDTO postUserInfo (#ModelAttribute PostUserInfoDTO){
...
return ResultDTO;
}
In this case, we can apply independent validation strategy for each End-Point.
for example..
#Getter
#Setter
#ToString
class GetUserInfoDTO {
#NotNull
private String id;
private String name;
}
#Getter
#Setter
#ToString
class PostUserInfoDTO {
#NotNull
private String name;
#NotNull
private Integer age;
#NotEmpty
private String address;
private String gender;
private String email;
private Date joinDate;
}
like this.
But so many model classes made, and so many duplicated property exists.
case 2. make common DTO for each Controller.
We can make DTO for each Controller, and reuse them.
#Getter
#Setter
#ToString
class UserInfoDTO {
private String id;
private String name;
private Integer age;
private String address;
private String gender;
private String email;
private Date joinDate;
}
#GetMapping("/user")
public ResultDTO getUserInfo (#ModelAttribute UserInfoDTO){
//I want only id, name
...
return ResultDTO;
}
#PostMapping("/user")
public ResultDTO postUserInfo (#ModelAttribute UserInfoDTO){
...
return ResultDTO;
}
But In this case, we can only pass specific properties.
If someone send other parameter than id and name, we can't notice. ( 400 error not occur )
Code assistance can't recommend us specific properties that use at single end-point.
I don't like these cases.
In first case, I should make so many models and It's management will be so hard.
Second case, unnecessary properties exists and it hard to validate for each end-point.
Which way is the best?
Or Can you recommend another way for mapping request parameter to model object?

What is use of the annotation #JsonIgnore?

I'm joining tables with one to many cardinality, the classes I'm using refer to each other. And I'm using #JsonIgnore annotation with out understanding it deeply.
#JsonIgnore is used to ignore the logical property used in serialization and deserialization. #JsonIgnore can be used at setters, getters or fields.
If you add #JsonIgnore to a field or its getter method, the field is not going to be serialized.
Sample POJO:
class User {
#JsonIgnore
private int id;
private String name;
public int getId() {
return id;
}
#JsonIgnore
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Sample code for serialization:
ObjectMapper mapper = new ObjectMapper();
User user = new User();
user.setId(2);
user.setName("Bob");
System.out.println(mapper.writeValueAsString(user));
Console output:
{"name":"Bob"}
When serializing your object into Json, the fields that are tagged with #JsonIgnore will not be included in the serialized Json object. This attribute is read by the Json serialize using reflection.
The Jackson's #JsonIgnore annotation can be placed on fields, getters/settess and constructor parameters mark a property to be ignored during the serialization to JSON (or deserialization from JSON). Refer to the Jackson annotations reference documentation for more details.

How to create different JSON output for a complex object

I would like to generate different Json output for the same complex Java object depending on the use case.
For example check the following code:
class Employee {
private Long id;
private String name;
private EmployeeDetail detail;
private Department department;
...
}
class Department {
private Long id;
private String name;
private String address;
...
}
class EmployeeDetail {
private Long id;
private int salary;
private Date birthDate;
...
}
If I convert Employee to Json all of the fields from Employee, EmployeeDetail and Department will be present. And it is good for one use case.
However in the second use case I would like to skip Department details except the id field but keep the complete EmployeeDetail.
I know that I can add something similar #JsonView(EmployeeView.Basic.class) to the id field in the Department class and use Json views. However for cleaner code I would like to solve it inside the Employee class something like this:
class Employee {
private Long id;
private String name;
#JsonAllFields
private EmployeeDetail detail;
#JsonIdOnly
private Department department;
...
}
At the moment I use the Jackson library but can switch if required.
i think you can use com.fasterxml.jackson.annotation.
#JsonIgnore is used to ignore the logical property used in serialization and deserialization. #JsonIgnore can be used at setter, getter or field. You can use it in the fields in Department class except on ID. There are so many ways to do it. Either you can allow the only getter in serialization etc.
Example:
#JsonIgnore(false)
private String id;
OR
#JsonIgnoreProperties({ "bookName", "bookCategory" })
public class Book {
#JsonProperty("bookId")
private String id;
#JsonProperty("bookName")
private String name;
#JsonProperty("bookCategory")
private String category;
}
To know more about it, please refer: https://www.concretepage.com/jackson-api/jackson-jsonignore-jsonignoreproperties-and-jsonignoretype
I hope this helps.
Just found a solution using #JsonFilter
Now the Employee class looks like this:
class Employee {
private Long id;
private String name;
private EmployeeDetail detail;
#JsonFilter("departmentFilter")
private Department department;
...
}
And the code to generate the limited json looks like this:
ObjectMapper mapper = new ObjectMapper();
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("departmentFilter", SimpleBeanPropertyFilter.filterOutAllExcept("id"));
mapper.setFilterProvider(filterProvider);
One small cons is that now I also need to define the filter to generate the full, detailed json like this:
filterProvider.addFilter("departmentFilter", SimpleBeanPropertyFilter.serializeAll());

Hibernate: override entity getter to add annotations

I need to override a getter of an entity object, on which the db column is defined, in it's superclass, so I can add additional annotations.
Example:
#MappedSuperclass
public class Person {
String name;
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
#Table(name="employee")
#XmlType(name="employee")
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
public String getName() {
return super.getName();
}
}
Class Person contains common attributes for several entities. Class Employee extends person and defines a database table (table per class strategy). I also want to serialize class Employee to XML, so I need to add additional annotations to its getters, and therefore I'm overriding them.
The problem is that when I try to run this code, I get a Hibernate MappingException saying: Duplicate property mapping of name found in Employee.
Is there a way to tell Hibernate that the name getter in Employee is not duplicate but just overriden (perhaps with some annotation). Or is there another way to do what I need?
Try adding #Transient to the overriding property:
#Entity
#Table(name="employee")
#XmlType(name="employee")
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
#Transient
public String getName() {
return super.getName();
}
}
this is untested code but i hope it will work, use #AttributeOverride annotation like this
#Entity
#Table(name="employee")
#XmlType(name="employee")
#AttributeOverride(name = "name", column = #Column(name = "name"))
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
public String getName() {
return super.getName();
}
}

Map XML with same element and attribute names to Java object

I already searched for this particular issue, the closest thread i found was this one: Java/JAXB: Unmarshall XML elements with same name but different attribute values to different class members But it's still not exactly what i need, so i hope someone can help me with this.
I am doing a SOAP request on a Zimbra Collaboration Suite 7 Server to get a contact. The response is something like this:
<cn fileAsStr="Arthur, Spooner" f="" id="280" rev="1973" d="1338524233000" t="" md="1338524233" ms="1973" l="7"><meta/><a n="homePostalCode">93849</a><a n="lastName">Spooner</a><a n="birthday">1980-05-24</a><a n="homeStreet">Berkleystreet 99</a><a n="firstName">Arthur</a></cn>
I want to map this to a Java object, something like this:
public class Contact {
Integer id;
Integer rev;
String namePrefix;
String firstName;
String middleName;
String lastName;
String jobTitle;
ArrayList<Adress> adresses;
Date birthday;
String department;
Integer mobilePhone;
String email;
String company;
String notes;
...
I usually do this using JAXB, but as all the elements are called a and all the attributes n, I don't know how to map this. I really would appreciate a code snippet or any kind of help. Thanks in advance.
You could try doing something like this:
#XmlAccessorType(XmlAccessType.FIELD)
public class ContactAttribute {
#XmlAttribute(name="n")
private String attribute;
#XmlValue
private String value;
}
#XmlRootElement(name = "cn")
#XmlAccessorType(XmlAccessType.FIELD)
public class Contact {
#XmlAttribute
Integer id;
#XmlAttribute
Integer rev;
//...
#XmlElements(#XmlElement(name = "a"))
List<ContactAttribute> attributes;
//...
}
Use the Castor Mapping
it will help you to Marshall and Unmarshall the data.

Categories