使用 Jackson 序列化 Hibernate Bean
Serializing Hibernate Beans With Jackson
我正在为项目创建一些现有服务的 RESTful 版本。当前应用程序将 Hibernate 3 与 jboss 6 服务器一起使用,因此我添加的任何新服务都必须在该环境中运行。我决定从一个简单的 GET 请求开始。我设法正确设置了所有内容,我的服务方法是 运行。我 运行 遇到的问题是,当 Jackson 尝试序列化响应以将其发送回客户端时,我得到 'lazy load' 异常。
我看到的针对此问题的两种最常见的解决方案在这里都行不通。将获取类型更改为 EAGER 可能会破坏我现有的服务。添加注释以忽略导致异常的字段也不起作用,因为客户端需要这些字段。
通常,我对此类问题的解决方案是 'front-load' 客户在服务调用期间需要的集合。不幸的是,这只能在事务中完成。当 Jackson 准备好序列化我的响应时,服务方法已经返回并且事务已经关闭。
有谁知道解决此问题的方法吗? jackson 是否提供了一些 'hook' 可以让我在交易中进行序列化?
更新
这是我的代码的示例:
服务提供商-
@Path("service")
public interface ClientServiceProvider
{
@GET
@Path("web/brand/{id}")
@Produces(MediaType.APPLICATION_JSON)
public abstract Response getBrandWeb(@PathParam("id") Long brandId);
}
服务bean-
@Stateless(name = "ClientServiceProvider")
@Local(ClientServiceProvider.class)
public class ClientServiceProviderBean implements ClientServiceProvider
{
@Override
public Response getBrandWeb(Long brandId)
{
try
{
Functions.beginTx(tx);
Brand b = entityManager.find(Brand.class, brandId);
if (!b.getSubCollections().isEmpty())
{
b.getSubCollections().size();
}
Response r = null;
if (b != null)
{
r = Response.ok(b).build();
}
else
{
r = Response.serverError().build();
}
Functions.commitTx(tx);
return r;
}
catch (Exception e)
{
return quietRollback(tx, e, Response.class);
}
}
}
最灵活的解决方案是使用在事务上下文中创建的DTOs。
使用 DTO,您可以根据使用结果 JSON 的客户端的确切需求定制要序列化的对象。此外,域模型(Hibernate 实体)与 JSON(反)序列化逻辑分离,允许两者独立发展。
首先,使用DTO
是最好的解决方案。我不喜欢 DTO
,但在这种情况下它会很有帮助。因为,您不仅需要实现 GET
端点,还需要实现 POST/PUT
端点。
此外,如果您将 Swagger 与实体一起使用,您将在 Swagger 文档中拥有所有 Hibernate 支持属性(如双向关联)。
您可以使用 Dozer 或您自己的映射器来减少 DTO
映射错误的数量。在这种情况下,我实现了自己的简单映射器(没有浅拷贝,并为集合和其他复杂情况提供了额外的自定义方法)。
此外,使用 DTO
映射器,您可以自动获取需要序列化的延迟属性 — 映射器将尝试复制这些属性并触发延迟获取。
所以,如果您不想使用 DTO
:
,您可以做什么
- 在打开会话(在事务内)时获取您需要的所有关联。
- 使用 jackson-datatype-hibernate 模块调整 Jackson 以不序列化未获取的关联,如下所述:
Avoid Jackson serialization on non fetched lazy objects
我正在为项目创建一些现有服务的 RESTful 版本。当前应用程序将 Hibernate 3 与 jboss 6 服务器一起使用,因此我添加的任何新服务都必须在该环境中运行。我决定从一个简单的 GET 请求开始。我设法正确设置了所有内容,我的服务方法是 运行。我 运行 遇到的问题是,当 Jackson 尝试序列化响应以将其发送回客户端时,我得到 'lazy load' 异常。
我看到的针对此问题的两种最常见的解决方案在这里都行不通。将获取类型更改为 EAGER 可能会破坏我现有的服务。添加注释以忽略导致异常的字段也不起作用,因为客户端需要这些字段。
通常,我对此类问题的解决方案是 'front-load' 客户在服务调用期间需要的集合。不幸的是,这只能在事务中完成。当 Jackson 准备好序列化我的响应时,服务方法已经返回并且事务已经关闭。
有谁知道解决此问题的方法吗? jackson 是否提供了一些 'hook' 可以让我在交易中进行序列化?
更新 这是我的代码的示例:
服务提供商-
@Path("service")
public interface ClientServiceProvider
{
@GET
@Path("web/brand/{id}")
@Produces(MediaType.APPLICATION_JSON)
public abstract Response getBrandWeb(@PathParam("id") Long brandId);
}
服务bean-
@Stateless(name = "ClientServiceProvider")
@Local(ClientServiceProvider.class)
public class ClientServiceProviderBean implements ClientServiceProvider
{
@Override
public Response getBrandWeb(Long brandId)
{
try
{
Functions.beginTx(tx);
Brand b = entityManager.find(Brand.class, brandId);
if (!b.getSubCollections().isEmpty())
{
b.getSubCollections().size();
}
Response r = null;
if (b != null)
{
r = Response.ok(b).build();
}
else
{
r = Response.serverError().build();
}
Functions.commitTx(tx);
return r;
}
catch (Exception e)
{
return quietRollback(tx, e, Response.class);
}
}
}
最灵活的解决方案是使用在事务上下文中创建的DTOs。
使用 DTO,您可以根据使用结果 JSON 的客户端的确切需求定制要序列化的对象。此外,域模型(Hibernate 实体)与 JSON(反)序列化逻辑分离,允许两者独立发展。
首先,使用DTO
是最好的解决方案。我不喜欢 DTO
,但在这种情况下它会很有帮助。因为,您不仅需要实现 GET
端点,还需要实现 POST/PUT
端点。
此外,如果您将 Swagger 与实体一起使用,您将在 Swagger 文档中拥有所有 Hibernate 支持属性(如双向关联)。
您可以使用 Dozer 或您自己的映射器来减少 DTO
映射错误的数量。在这种情况下,我实现了自己的简单映射器(没有浅拷贝,并为集合和其他复杂情况提供了额外的自定义方法)。
此外,使用 DTO
映射器,您可以自动获取需要序列化的延迟属性 — 映射器将尝试复制这些属性并触发延迟获取。
所以,如果您不想使用 DTO
:
- 在打开会话(在事务内)时获取您需要的所有关联。
- 使用 jackson-datatype-hibernate 模块调整 Jackson 以不序列化未获取的关联,如下所述: Avoid Jackson serialization on non fetched lazy objects