JAX-RS 2.1: адаптер JSON-B применяется в случае неожиданности
Проблема:
Учитывая конечную точку 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
- 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);
}
}
Временное решение:
Сначала я думал, что после определения адаптера они будут применяться повсеместно, аналогично конвертерам JPA с autoApply = true
, Это привело меня в никуда
Сначала я подумал об использовании последней версии Yasson (1.0.2-SNAPSHOT) для решения проблемы. Для этого я должен сказать Паяре загрузить Ясона, который я хочу. Итак glassfish-web.xml
изменяется следующим образом:
<glassfish-web-app error-url="">
...
<!-- <class-loader delegate="true"/> -->
<class-loader delegate="false"/>
...
</glassfish-web-app>
согласно документации Payara.
Но оказывается, что только переключение class-loader
делегирование ложного достаточно.
=> почему?
Вспомогательный вопрос:
Из-за некоторых проблем с горячим развертыванием мне нужно сделать следующее, чтобы проверить мои изменения:
- внести изменения
- построить и развернуть
- перезагрузите сервер после развертывания
Если кто-то случайно узнает, почему горячее / простое развертывание изменяет поведение адаптера JAX-RS, я жду ответа
0 ответов
Просто чтобы вернуться к SO здесь, OP поднял подробную проблему GitHub на Yasson, и основная причина заключается в том, что Yasson кэширует объектную модель (поэтому ему не нужно каждый раз пересматривать объектные модели). Это кэширование вызывает проблему в среде сервера приложений, где Yasson предоставляется контейнером (например, среда выполнения JAX-RS), и когда пользователь обновляет свое приложение, только его классы приложения перезагружаются, но Yasson и его кеши остаются загруженными.
Краткосрочное исправление
Обходной путь на данный момент - перезапустить сервер приложений при внесении изменений в ваши классы данных JSON-B.
Долгосрочный
Я собираюсь выяснить, может ли спецификация Yasson и / или JSON-B определить своего рода ловушку "очистки кеша". Идея заключается в том, что, когда сервер приложений выполняет горячее обновление приложения, он может вызвать этот крюк "очистки кэша", чтобы очистить сохраненную объектную модель от приложения.