问题:
给定 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 请求
两个实体Company
并Department
通过@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
. 这让我无处可去
起初,我考虑使用 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 文件。
但似乎仅将class-loader
授权切换为 false 就足够了。
=> 为什么?
附属问题:
由于一些热部署问题,我需要执行以下操作来测试我的更改:
- 做出改变
- 构建和部署
- 部署后重启服务器
如果有人知道为什么热部署/简单部署会修改 JAX-RS 适配器行为,我期待答案