【问题标题】:Resolve JPA association while deserializing JAX-RS JSON Object在反序列化 JAX-RS JSON 对象时解析 JPA 关联
【发布时间】:2014-10-24 13:15:12
【问题描述】:

我在将 JAX-RS(在 JBoss Wildfly 容器中)与 JSON 有效负载和 JPA 关联结合起来时遇到了一些问题。以下场景:

有两个 JPA 实体

@Entity
class Organization {
  @Id
  private long id;

  private String name;
}

@Entity
class Empolyee {
  @Id
  private long id;

  @Id
  private String name;

  @ManyToOne(fetch = FetchType.EAGER)
  @JsonProperty("organization_id")
  @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
  @JsonIdentityReference(alwaysAsId = true)
  private Organization organization;
}

接下来我有一个 JAX-RS 服务来创建一个具有以下签名的新员工:

@POST
@Consumes({ "application/json" })
public Response create(final Employee employee) {
}

客户端发送的新员工的 JSON 格式如下:

{
  "name" : "Sam Sample",
  "organization_id" : 2
}

我的问题是这个 JSON(显然)不能反序列化为“Employee”的实例,因为“organization_id”到相应 JPA 实体的映射失败。

如何配置 JAX-RS(或 Jackson JSON 映射器)以将“orgainization_id”解释为 JPA 实体的 id?

【问题讨论】:

  • 你能解决这个问题吗?
  • 我们通过引入 DTO 对象来解决这个问题,在将 JSON 有效负载合并到我们的工作单元之前先将其转换为这些对象。不是很聪明,但它确实有效......
  • @woelfle 您究竟是如何注册对象映射器以便可以注入 EntityManager 的?我希望编写一个类似的自定义反序列化器来反序列化作为请求的 POST 主体传入的确切类。我需要能够使用 Jersey 的 HK2 注入 EntityManager,因为这就是我设置它的方式。我只需要以某种方式由 Jersey 管理 ObjectMapper。
  • @vikarjramun 正如我在上一条评论中提到的,我们根本没有在反序列化器中注入 EntityManager。我们正在做的是将 JSON 有效负载反序列化为专用的 DTO 对象。在示例案例中,这意味着有一个具有以下结构的 DTO: class EmployeeDTO { private String name, long organizationId } 现在我们将 JSON 有效负载反序列化为该 DTO 的实例。 IE。 JAX-RS 端点的签名现在使用 EmployeeDTO。此 DTO 正在 JAX-RS 端点中转换为 Employee 对象。

标签: java json jpa jackson jax-rs


【解决方案1】:

使用 Jackson,您可以定义一个自定义反序列化器(参见 thisthis),它根据 organization_id 的值获取 Organization 实体。

编辑: 查看此示例,了解如何使用 Jackson 和自定义反序列化程序以编程方式(而不是通过注释)配置 JAX-RS:

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {

    private ObjectMapper objectMapper;

    public JacksonContextResolver() throws Exception {
        this.objectMapper = new ObjectMapper().configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        SimpleModule myModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
        myModule.addDeserializer(MyType.class, new MyTypeDeserializer());
        objectMapper.registerModule(myModule);

    }

     public ObjectMapper getContext(Class<?> objectType) {
         return objectMapper;
    }
}

【讨论】:

  • 感谢您的提示。我已经尝试过编写自己的 Jackson Deserializer,但我还没有找到任何关于如何将当前 EntityManager 实例注入 Deserializer 的文档
  • 您如何注册自定义反序列化程序?如果您使用依赖注入,我认为您应该能够使用 @PersistenceContext 注释注入 EntityManager。
  • 我已经使用@JsonDeserialize 注解注册了反序列化器。还有其他注册方式吗?
  • 再次感谢您的帮助。我尝试使用上下文解析器注册反序列化器。似乎该反序列化器仅在反序列化“组织”对象时使用(当调用 JAX-RS 服务创建组织时),但在创建员工时反序列化对组织的引用时不使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-27
  • 2015-05-25
  • 2017-06-04
  • 1970-01-01
  • 2015-02-16
相关资源
最近更新 更多