How to get a specific attribute an object in JSON? - java

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.

Related

Json output to exclude field name, but include its class fields

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
}

Why Jackson serializing super class as separate object?

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;
}

How to handle parent child relation for Rest service

In my Spring boot service, I have a controller as below
#PostMapping
public ApiResponse generateUKLabel(#RequestBody LabelRequestData data){
//do operation
}
Here, LabelRequestData has List of base class.
In, request I am passing child class data with base class data.
But, Child class data seems to be ignored.
Is there any way I can access the child class data.
I want to make the LabelRequestData with Base class generic so that it can accept multiple child class data.
Is there any way to solve it?
I tried casting. but throws can't cast exception
I also tried generics. but then I need to create two controller method to handle those request. I want only one controller method to handle the request
#Data
public class LabelRequestData extends BaseRequestData {
#Valid
private List<BaseClass> labelData; // this base class has multiple child classes that i need
#Valid
private PreferenceData preferenceData;
}
When Deserialising the Jackson will not know which child class that has to be used, so it only takes the value of the BaseClass and ignores the ChildClass
You could use #JsonTypeInfo in the BaseClass , this helps the Jackson to identify the proper ChildClass (You have to add type in the json)
I am not sure what BaseClass holds so I am just assuming random attributes below.
BaseClass.java
#Data
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = ChildOne.class, name = "childOne"),
#JsonSubTypes.Type(value = ChildTwo.class, name = "childTwo")})
public class BaseClass {
private Integer id;
}
ChildOne .java
#Data
public class ChildOne extends BaseClass {
private String name;
}
ChildTwo.java
#Data
public class ChildTwo extends BaseClass {
private String address;
}
If you request the Json,
{
"labelData": [
{
"id": 0, // -|
"type": "childOne", // |-> This will go to ChildOne.class
"name": "Foo" // _|
}, {
"id": 0, // -|
"type": "childTwo", // |-> This will go to ChildTwo.class
"address": "Somewhere in Earth"// _|
}
]
// Rest of Json
}

Jackson and multiple interface inheritance

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
}
]

Convert object that contains another object to json

I need to pass data from HTML to Service using JSON (in JS/JQUERY)
In the service I have a service call that reciving an object that contains another object and 2 more fields.
Role object:
import java.io.Serializable;
public class Role implements Serializable {
private long id;
private String name;
}
User object:
import java.io.Serializable;
public class User implements Serializable {
private String userName;
private String password;
private ArrayList<Role> roles;
}
Till now I managed to pass data to JSON like that to other service: (data that contains only 2 parameters: id and userName )
xmlHttp.open("POST", "http://www.foo.com/serviceFunction2", true);
xmlHttp.send('{"Id": "123", "userName": "test"}');
So, my question is how can I fill the User object that contains the Role object using JS/JQUERY? like I managed to send it with this line:
xmlHttp.send('{"Id": "123", "userName": "test"}');
Thanks
There are several ways to "nest" objects in JS, but for your purpose probably the simplest is to nest your object and/or array literals. If "roles" is supposed to be an array, then something like this:
'{"userName":"test", "password":"secret", "roles":["role1","role2","role3"]}'
If each role in the array is itself an object with properties:
{
"userName":"test",
"password":"secret",
"roles": [
{ "roleName":"role1", "prop2":"someValue", "prop3":"whatever" },
{ "roleName":"role2", "prop2":"someValue", "prop3":"whatever" },
{ "roleName":"role3", "prop2":"someValue", "prop3":"whatever" }
]
}
(Line breaks added for readability, but you'd remove them if creating a string.)
I don't know what your goal is but if you are using the HTML page as a GUI and Java for the processing you might as well use jsf or similar. There are multiple frameworks like primefaces, myfaces or icefaces that handle a lot of stuff for you.
Have a look at the Primefaces showcase if you're interested.
As MattBall suggested you can also use something like jaxb, this takes a lot of load off your hands.
You can use a lot of powerful and easy stuff.
You can map objects to JSON/XML using annotations:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Role
{
#XmlAttribute
private long id;
#XmlAttribute
private String name;
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class User
{
#XmlAttribute
private String userName;
#XmlAttribute
private String password;
#XmlElement
private ArrayList<Role> roles;
}
You can then use this in a web service:
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("user/{username}")
public User getUser( #PathParam("username") String userName)
{
User user;
// Get your user
return user;
}

Categories