【问题标题】:JAX-RS 2.1: JSON-B adapter applied when unexpectedJAX-RS 2.1:意外时应用 JSON-B 适配器
【发布时间】:2018-01-09 16:18:28
【问题描述】:

问题:

给定 REST 端点:

@Path("/companies")
@Stateless
public class CompanyService{

    @EJB
    private CompanyEjb ejb;

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Company update(Company company){
        return ejb.update(company);
    }

}

提交PUT请求后,JAX-RS预计会返回更新后的公司如

{
    "id": 1,
    "name": "Company",
    "departments": [1,2]
}

但是,仅返回主键 1。第二个请求触发异常:

Warning:   StandardWrapperValve[[RestApplicationClass]: Servlet.service() for servlet RestApplicationClass threw exception
java.lang.NoSuchMethodException: java.lang.Long.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getDeclaredConstructor(Class.java:2178)
    at org.eclipse.yasson.internal.ReflectionUtils.lambda$createNoArgConstructorInstance$1(ReflectionUtils.java:188)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.eclipse.yasson.internal.ReflectionUtils.createNoArgConstructorInstance(ReflectionUtils.java:186)
    at org.eclipse.yasson.internal.serializer.ObjectDeserializer.getInstance(ObjectDeserializer.java:92)
    at org.eclipse.yasson.internal.serializer.AbstractContainerDeserializer.deserialize(AbstractContainerDeserializer.java:62)
    at org.eclipse.yasson.internal.serializer.AdaptedObjectDeserializer.deserialize(AdaptedObjectDeserializer.java:94)
    at org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:57)
    at org.eclipse.yasson.internal.Unmarshaller.deserialize(Unmarshaller.java:50)
    at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:45)
    at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:85)

适配器似乎被应用了,虽然我没有要适应的公司

上下文

配置是:

  • Payara 5.0.0.Alpha3(因此是 Yasson 1.0)
  • Java EE 8(因此是 JAX-RS 2.1、JSON-B 1.0 和 JSON-P 1.1)
  • 应用程序以 EAR 格式打包
  • 使用 Postman 提交的 REST 请求

CompanyDepartment 两个实体通过 @OneToMany 关系链接。这两个实体都有一个主键id 和一个名称name。为避免 JSON 无限循环,@ManyToOne 公司部门有一个适配器:

public class Department{
    // ...
    @ManyToOne // JPA stuff irrelevant here
    @JsonbTypeAdapter(CompanyAdapter.class)
    private Company company;
    // ...
}

使用(简化的)适配器:

public class CompanyAdapter implements JsonbAdapter<Company, Long>{

    @EJB
    private CompanyEjb ejb;

    @Override
    public Long adaptToJson(Company orgnl) throws Exception {
        return orgnl != null ? orgnl.getId() : null;
    }

    @Override
    public E adaptFromJson(Long adptd) throws Exception {
        return ejb.findById(adptd);
    }
}

解决方法:

最初,我认为一旦定义了适配器,它们就会被应用到任何地方,类似于带有autoApply = true 的 JPA 转换器。这让我无处可去

起初,我考虑使用最新版本的 Yasson (1.0.2-SNAPSHOT) 来解决问题。为此,我需要告诉 Payara 加载我想要的 Yasson。所以glassfish-web.xml修改如下:

<glassfish-web-app error-url="">
    ...
    <!-- <class-loader delegate="true"/> -->
    <class-loader delegate="false"/>
    ...
</glassfish-web-app>

根据Payara documentation.

但似乎仅将 class-loader 委托切换为 false 就足够了。

=> 为什么?

附属问题:

由于一些hot-deploy 问题,我需要执行以下操作来测试我的更改:

  1. 进行更改
  2. 构建和部署
  3. 部署后重启服务器

如果有人知道为什么热部署/简单部署会修改 JAX-RS 适配器行为,我期待答案

【问题讨论】:

    标签: jakarta-ee jax-rs payara jsonb-api


    【解决方案1】:

    只是为了在这里发回 SO,OP 在 Yasson 上提出了详细的GitHub issue,根本原因是 Yasson 缓存了对象模型(因此它不必每次都重新扫描对象模型)。在 Yasson 由容器(例如 JAX-RS 运行时)提供的应用服务器环境中,这种缓存会导致问题,并且当用户更新他们的应用程序时,只有他们的应用程序类会被重新加载,但 Yasson 和它的缓存会保持加载。

    短期修复

    目前的解决方法是在更改 JSON-B 数据类时重新启动应用服务器。

    长期

    I'm going to see 如果 Yasson 和/或 JSON-B 规范可以定义某种“清除缓存”挂钩。这里的想法是,当应用服务器热更新应用时,它可以调用此“清除缓存”挂钩以从应用中清除存储的对象模型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-08
      • 2017-10-27
      相关资源
      最近更新 更多