Suppose I have below Cassandra entities.
#Entity
class Person {
private String name;
// getter and setter
}
#Entity
class Job {
private String title;
// getter and setter
}
class PersonWrapper extends Person {
private Job job;
// getter and setter
}
And API is giving:
{
"name": "rick",
"job": {
"title": "programmer"
},
"person": {
"name": "rick",
"job": {
"title": "programmer"
}
}
}
My temporary solution is to use JsonIgnoreProperties on wrapper class. Is there any solution to eliminate the duplicate object?
Jackson maps the fields of a JSON to the equal fields in a Java object by matching the names of the JSON fields and fields from your class without "get" and "set" (you have to have getters and setters in your serialization classes).
In your example you need to create class like that:
#Getter
#Setter
class CommonClass {
String name;
Job job;
Person person;
}
#Getter
#Setter
class Job {
String title;
}
#Getter
#Setter
class Person {
String name;
Job job;
}
Related
I have a spring project wherein I have an abstract class Person as following
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({#Type(value=Employee.class, name="employee"), #Type(value = Driver.class, name = "driver")})
public abstract class Person {
}
I have 2 implementations of this Person class, Employee and Driver as following
#JsonTypeName("employee")
public class Employee extends Person {
private int field1;
private int field2;
//some getters and setters
}
#JsonTypeName("driver")
public class Driver extends Person {
private int field3;
private int field4;
private int field5;
//some getters and setters
}
The Person object is contained in Company class as follows
public class Company {
private String name;
private int id;
private Person person;// this is the object
private int people;
}
Now, I receive the request in a json format and one of the fields is this person object as follows:
{
"name": "some name",
"id": 123,
"person":{
"type": "employee"
"field1":"some field1 value",
"field2":"some field2 value"
},
"people": 100
}
The thing is, the person can be either of driver or employee type. The field "type"(not present as a variable) is passed in json and the corresponding object is instantiated. However I am unable to get the hold of the instantiated object as the instantiation happens on runtime and I am not able to tell in the code which class was instantiated. And hence can't call the getters of the appropriate object(employee or driver).
Is there a way I can get the hold of the instantiated object so that I can do whatever I want with the fields of the object(field1 and field2 in case of employee and field3, field4 and field5 in case of driver), say company.getPerson().getField1();
Thanks in advance
If getField1() is a method of Employee and not of any Person, then no you can't do getPerson().getField1().
And that's logic. If you're invoking getField1() on a Person, then it means that you know that this Person is an Employee and not a Driver.
So, you should simply separate the code handling a Employee from the one handling a Driver:
Person person = company.getPerson();
if (person instanceof Employee) {
Employee employee = (Employee) person;
employee.getField1();
//...
} else if (person instanceof Driver) {
Driver driver = (Driver) person;
driver.getField3();
//...
}
Can I use these annotation for my class to my expected json?
public class Staff {
private String name;
private Integer age;
#JsonUnwrapped
private Staff manager;
.... getter and setter ....
}
{
"name": "Fanny",
"age": 24,
"manager": "Timmy"
}
I know I can use JsonIgnoreProperties but I need to unwrap name only. Any solution? Thanks
You can have a getter for the name that returns a String and annotate it with #JsonPropery,
Can I use these annotation for my class to my expected json?
public class Staff {
private String name;
private Integer age;
#JsonIgnore
private Staff manager;
#JsonProperty("managerName")
public String getManagerName() {
return this.manager.getName();
}
.... getter and setter ....
}
Say I have 2 classes, one includes the other
class TestClass {
private int id;
private String name;
private AnotherClass another
}
class AnotherClass {
private String details
}
I would like json output for TestClass to only include AnotherClass's field directly and not show the field another:
{
"id": 1,
"name": "test",
"details": "test details"
}
I found the solution.Use #JsonUnwrapped on field another.
Thanks
If using Jackson, you can use the JsonUnwrapped annotation:
class TestClass {
private int id;
private String name;
#JsonUnwrapped
private AnotherClass another
}
class AnotherClass {
private String details
}
I working with JAX-RS and I want to get a JSON Object from my resource.
For example, I have the next code:
Book class:
#XmlRootElement
public class Book {
private int id;
private String name;
}
And person class:
#XmlRootElement
private class Person {
private int id;
#XmlElement(name="full_name")
private String fullName;
#XmlElement(name="book_id")
private Book book;
}
I want get this:
{
"id": 1,
"full_name": "Gustavo Pacheco",
"book_id": 8
}
And don't get this:
{
"id": 1,
"full_name": "Gustavo Pacheco",
"book": {
"id": 8,
"name": "Cien AƱos De Soledad"
}
}
How can I get only id attribute from book class for get a more simple JSON?
The best thing for these cases is to have the classes corresponding to the DTOs and entities corresponding to the database model independently.
For example:
package com.github.ryctabo.example.entity;
/* Entity class */
#Entity
public class Person implements Serializable {}
package com.github.ryctabo.example.dto;
/* Data Transfer Object class */
#XmlRootElement
public class PersonData {}
This ensures the integrity of the database model, and independently you have how you are going to display the data in a different class.
I'm trying to implement json serialization of the single entity to different views according to used interface.
For example we have:
public interface BookBrief {
long getId();
String getTitle();
}
public interface BookPreview {
long getId();
String getAnnotation();
}
public class Book implements BookBrief, BookPreview {
// class fields here
public long getId() {...}
public String getTitle() {...}
public String getText() {...}
public String getAnnotation() {...}
// setters here
}
// service which results is serialized to json in Spring MVC controllers
public interface BookService {
List<? extends BookBrief> getBooks();
BookPreview getBookPreview(long id);
Book getBook(long id);
}
BookService implementation always returns Book class (with unused fields set to null).
To serialize interfaces I tried to use annotation #JsonSerialize(as = Interface.class) for each,
but for all interfaces jackson always use only the first one listed in 'implements' expression.
Is there a way to configure jackson like I need? Or may be there is a better solution?
Seems like you have 2 options:
Write a custom Jackson Serializer
Use Jackson views, which looks like a more viable choice (full documentation could be found here).
With Views it could be implemented in 3 easy steps:
Define your view markers:
BookViews.java:
public class BookViews {
public static class BookBrief { }
public static class BookPreview { }
}
Annotate which Book fields you want to be exposed in each view:
Book.java:
public class Book {
#JsonView({BookViews.BookBrief.class, BookViews.BookPreview.class})
private long id;
#JsonView(BookViews.BookBrief.class)
private String title;
#JsonView(BookViews.BookPreview.class)
private String annotation;
// Constructors and getters/setters
}
Annotate REST method with JSonValue and specify which view you want to use:
BookService.java:
#Path("books")
public class BookService {
private static final List<Book> library = Arrays.asList(
new Book(1, "War and Peace", "Novel"),
new Book(2, "A Game of Thrones", "Fantasy")
);
#GET
#Path("all")
#JsonView(BookViews.BookBrief.class)
#Produces(MediaType.APPLICATION_JSON)
public Response getBooks() {
return Response.status(Response.Status.OK).entity(library).build();
}
#GET
#Path("previews")
#JsonView(BookViews.BookPreview.class)
#Produces(MediaType.APPLICATION_JSON)
public Response getBookPreviews() {
return Response.status(Response.Status.OK).entity(library).build();
}
}
Result:
GET http://localhost:8080/root/rest/books/all:
[
{
"id": 1,
"title": "War and Peace"
},
{
"id": 2,
"title": "A Game of Thrones"
}
]
GET http://localhost:8080/root/rest/books/previews:
[
{
"annotation": "Novel",
"id": 1
},
{
"annotation": "Fantasy",
"id": 2
}
]