【问题标题】:Serializing Hibernate Beans With Jackson使用 Jackson 序列化 Hibernate Bean
【发布时间】:2017-09-29 01:48:29
【问题描述】:

我正在为一个项目创建一些现有服务的 RESTful 版本。当前的应用程序使用带有 jboss 6 服务器的 Hibernate 3,因此我添加的任何新服务都必须在该环境中工作。我决定从一个简单的 GET 请求开始。我设法正确设置了所有内容,并且正在运行我的服务方法。我遇到的问题是,当 Jackson 尝试序列化响应以将其发送回客户端时,我得到了“延迟加载”异常。

我看到的针对此问题的两个最常见的解决方案在这里不起作用。将获取类型更改为 EAGER 可能会破坏我现有的服务。添加注释以忽略导致异常的字段也不起作用,因为客户端需要这些字段。

通常,我对此类问题的解决方案是在服务调用期间“预先加载”客户端所需的集合。不幸的是,这只能在事务中完成。当 Jackson 准备好序列化我的响应时,服务方法已经返回并且事务已经关闭。

有人知道解决此问题的方法吗?杰克逊是否提供了一些“钩子”,可以让我在事务中进行序列化?

更新 这是我的代码的示例:

服务提供商-

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

【问题讨论】:

  • 可能你不记得了,但是你最终找到了适合这个问题的解决方案吗?
  • 我从来没有这样做过。我最终还是选择了 DTO。
  • 非常感谢您的回复:)

标签: hibernate serialization jackson lazy-loading jboss6.x


【解决方案1】:

首先,使用DTO 是最好的解决方案。我不喜欢DTO,但在这种情况下它会很有帮助。因此,您不仅需要实现GET 端点,还需要实现POST/PUT 端点。

此外,如果您将使用 Swagger,您将在 Swagger 文档中拥有所有 Hibernate 支持属性(如双向关联)。

您可以使用Dozer 或您自己的映射器来减少DTO 映射错误的数量。在这种情况下,我实现了自己的简单映射器(没有浅拷贝,并且为集合和其他复杂情况使用了额外的自定义方法)。

此外,使用 DTO 映射器,您可以自动获取需要序列化的惰性属性 — 映射器将尝试复制这些属性并触发惰性获取。

那么,如果你不想使用DTO,你可以做什么:

  1. 当您有一个打开的会话(在事务中)时,获取您需要的所有关联。
  2. 使用jackson-datatype-hibernate 模块调整Jackson 以不序列化未获取的关联,如下所述: Avoid Jackson serialization on non fetched lazy objects

【讨论】:

  • 1.我已经这样做了。问题是,会话在序列化发生之前关闭。结果,我在序列化过程中遇到了延迟加载异常。 2. jboss 版本的resteasy 已经包含该模块。然而,简单地忽略这些字段不是一种选择,因为它们是客户需要的。
  • @pbuchheit 如果这些字段是必需的,您应该在会话打开时加载它们。
  • 看看我发布的代码示例。在服务 bean 中,我调用 'b.getSubCollections().size();'加载集合。服务调用返回后,作为序列化过程的一部分,Jackson 将再次遍历“Brand”类的字段。然而,此时会话已经关闭,将抛出异常。
【解决方案2】:

最灵活的解决方案是使用在事务上下文中创建的DTOs

使用 DTO,您可以根据使用结果 JSON 的客户端的确切需求来定制要序列化的对象。此外,域模型(Hibernate 实体)与 JSON(反)序列化逻辑解耦,允许两者独立发展。

【讨论】:

  • 我也考虑过使用 DTO。对于一两个类可能还不错,但在整个应用程序中扩展它是一项艰巨的任务。即使我可以花时间创建和测试所有这些 DTO,但将已经相当大的代码库有效地翻倍并尝试使所有这些类保持同步的想法似乎是个坏主意。
猜你喜欢
  • 2016-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-18
  • 1970-01-01
  • 2021-12-13
  • 2014-07-23
  • 2018-04-17
相关资源
最近更新 更多