如何在 JSON 响应中仅获取实体 ID 而不是整个实体

Ger*_*phy 5 java json annotations hibernate

我看到了几个类似的问题,但没有一个对我有用的答案。我正在努力将现有项目转换为使用 Hibernate。我使用 Mysql 作为数据库。我有一堂这样的课:

@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....   
}
Run Code Online (Sandbox Code Playgroud)

和这样的类:

@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....   
}
Run Code Online (Sandbox Code Playgroud)

User当我从数据库中获取项目时,我将其转换为 JSON 并最终得到以下格式的结果:

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

        },
        "name": "John Doe",
     }
}
Run Code Online (Sandbox Code Playgroud)

就我而言,该Group对象实际上比本示例中的要大得多,并且还包含对另一个表的引用(即Group有一个SomeOtherClass对象)。我想最终得到如下所示的结果:

{
    "user": {
        "userId": 1,
        "groupId": 3,
        "name": "John Doe",
     }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法只获取 JSON 响应中的 groupId 而不是整个Group对象?

我尝试将 FetchType.Lazy 添加到我的 User 类中

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id_user")
private Group group;
Run Code Online (Sandbox Code Playgroud)

但是当我尝试将User对象转换为 Json 时,出现以下错误:

error: Errorjava.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?
Run Code Online (Sandbox Code Playgroud)

我发现这个答案消除了错误,但是 JSON 对象与我添加FetchType.LAZY. 看起来像是以某种方式转换为 JSON 添加了被FetchType.LAZY忽略的值。

我正在使用转换为 JSON,如下所示:

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

com.google.gson.JsonArray jsonArray = gson.toJsonTree(out).getAsJsonArray();
Run Code Online (Sandbox Code Playgroud)

小智 5

如果我错了,请纠正我,因为我是冬眠新手。根据我迄今为止的经验,是的,可以仅发送对象 ID,而不是发送整个对象详细信息作为响应。通过使用@JsonIdentityReference并在此处@JsonIdentityInfo查找文档

下面是对我有用的示例代码:

团体课

@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....   
}
Run Code Online (Sandbox Code Playgroud)

用户等级

@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....   
}
Run Code Online (Sandbox Code Playgroud)

结果是

{ "userId": 1, "group": 1, "name": "示例用户" }

我使用下面的代码来转换 JSON

ObjectMapper mapper = new ObjectMapper();
try {
      json = mapper.writeValue(user);
} catch (JsonProcessingException e) {
      e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

我在这里找到了我的问题的解决方案


Ger*_*phy 1

选项1:(来自@JBNizet的评论)

创建代表 API 输出的类 (DTO),将实体转换为这些 DTO 类的实例,并使用 Gson 将 DTO 序列化为 JSON。好的 REST 框架会自动为您完成最后一部分。

对于此示例,您可以创建一个如下所示的 UserItem 类:

public class UserItem {

    private Long userId;
    private Long groupId;
    private String name;
   ...
   // getters and setters....   
}
Run Code Online (Sandbox Code Playgroud)

然后您需要一个将 User 实体转换为 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;
}
Run Code Online (Sandbox Code Playgroud)

在您的响应中使用 userItem。


选项2:

更新:将选项 2 更新为有效的选项

如果您不想为每个实体类编写 DTO,因为(如本示例)唯一需要更改的字段是 groupId 的 Group 对象,您可以创建一个ExclusionStrategy并使用@Expose注释,如下所示:

首先创建一个类来实现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 {
Run Code Online (Sandbox Code Playgroud)

然后将@Expose注释添加到 User 类中。添加附加字段groupId将允许在查询和 json 响应中返回 groupId。只需确保用updatable=false和标记 groupId 即可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....   
}
Run Code Online (Sandbox Code Playgroud)

然后在创建Gson时设置Exclusion策略:

GsonBuilder b = new GsonBuilder();
b.serializeNulls();
b.setExclusionStrategies(new SerializeExclusionStrat());
Gson gson = b.create();
Run Code Online (Sandbox Code Playgroud)