Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get just an entity id instead of the entire entity in JSON response

I saw several similar questions but non with an answer that worked for me. I am working on converting an existing project over to use Hibernate. I am using Mysql for the database. I have a class like this:

@Entity
@Table(name = "user")
public class User {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "user_id")
   private Long userId;

   @ManyToOne
   @JoinColumn(name = "group_id_user")
   private Group group;

   @Column(name = "name")
   private String name;

   ...
   // getters and setters....   
}

and a class like this:

@Entity
@Table(name = "group")
public class Group {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "group_id")
   private Long groupId;

   @Column(name="group_name")
   private String groupName;

   ...
   // getters and setters....   
}

When I fetch a User item from the database I convert it to JSON and end up with a result in this format:

{
    "user": {
        "userId": 1,
        "group": {
            "groupId": 3,
            "groupName": "Group Three",

        },
        "name": "John Doe",
     }
}

In my case, the Group object is actually quite a bit bigger than in this example and also contains references to another table as well (i.e. Group has a SomeOtherClass object). I want to end up with something that looks like the following:

{
    "user": {
        "userId": 1,
        "groupId": 3,
        "name": "John Doe",
     }
}

Is there a way to just get the groupId in my JSON response instead of the entire Group object?

I have tried adding FetchType.Lazy to my User class

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id_user")
private Group group;

but when I try to convert the User object to Json I get the following error:

error: Errorjava.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?

I found this answer which gets rid of the error, but then the JSON object is exactly the same as it was before I added the FetchType.LAZY. It looks like somehow converting to JSON adds in the values that the FetchType.LAZY was ignoring.

I am using converting to JSON as follows:

GsonBuilder b = new GsonBuilder();
Gson gson = b.create();
//b.registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY);  

com.google.gson.JsonArray jsonArray = gson.toJsonTree(out).getAsJsonArray();
like image 488
Gerald Murphy Avatar asked Sep 07 '17 17:09

Gerald Murphy


2 Answers

Correct me if I wrong, as I'm new to hibernate. Based on my experience so far, Yes it is possible to send only object ID instead of sending the whole object details in response. By using @JsonIdentityReference and @JsonIdentityInfo find documentation here

Below is the sample code worked for me:

Group Class

@Entity
@Table(name = "group")
public class Group {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "group_id")
   private Long groupId;

   @Column(name="group_name")
   private String groupName;

   ...
   // getters and setters....   
}

User Class

@Entity
@Table(name = "user")
public class User {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "user_id")
   private Long userId;

   @ManyToOne
   @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "group_id")
   @JsonIdentityReference(alwaysAsId = true)
   @JoinColumn(name = "group_id_user")
   private Group group; 
   ...
   // getters and setters....   
}

Result is

{ "userId": 1, "group": 1, "name": "Sample User" }

I used below code to convert JSON

ObjectMapper mapper = new ObjectMapper();
try {
      json = mapper.writeValue(user);
} catch (JsonProcessingException e) {
      e.printStackTrace();
}

I found the solution for my issue here

like image 171
sukesh shetty Avatar answered Nov 15 '22 06:11

sukesh shetty


Option 1: (from @JBNizet's comment)

Create classes (DTOs) which represent the output of your API, transform your entities to instances of these DTO classes, and use Gson to serialize the DTOs to JSON. Good REST frameworks do the last part automatically for you.

For this example you could create a UserItem class that looked like this:

public class UserItem {

    private Long userId;
    private Long groupId;
    private String name;
   ...
   // getters and setters....   
}

Then you would need a method that converts the User entity to a UserItem:

public UserItem UserToUserItem(User user) {
    UserItem userItem = new UserItem();
    userItem.setUserId(user.getUserId());
    userItem.setGroupId(user.getGroup().getGroupId());
    userItem.setName(user.getName());

    return userItem;
}

The use the userItem in your response.


Option 2:

UPDATE: Updated option 2 to something that works

If you don't want to write DTOs for each entity class because (like this example) the only field that needs changed is the Group object to the groupId you can create an ExclusionStrategy and use the @Expose annotation as follows:

First create a class that implements ExclusionStrategy

public class SerializeExclusionStrat implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes fieldAttributes) {
        final Expose expose = fieldAttributes.getAnnotation(Expose.class);
        return expose != null && !expose.serialize();
    }

    @Override
    public boolean shouldSkipClass(Class<?> aClass) {
        return false;
    }
}


@Entity
@Table(name = "user")
public class User {

Then add the @Expose annotation to User class. Adding the additional field groupId will allow the groupId to be returned in your queries and in your json responses. Just make sure to mark groupId with updatable=false and insertable=false.

@Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "user_id")
   private Long userId;

   @ManyToOne
   @JoinColumn(name = "group_id_user")
   @Expose(serialize = false)
   private Group group;

   @Column(name = "group_id_user", updatable = false, insertable = false)
   private Long groupId;     

   @Column(name = "name")
   private String name;

   ...
   // getters and setters....   
}

Then set the Exclusion strategy when creating the Gson:

GsonBuilder b = new GsonBuilder();
b.serializeNulls();
b.setExclusionStrategies(new SerializeExclusionStrat());
Gson gson = b.create();
like image 1
Gerald Murphy Avatar answered Nov 15 '22 05:11

Gerald Murphy