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 делегирование ложного достаточно.

=> почему?

Вспомогательный вопрос:

Из-за некоторых проблем с горячим развертыванием мне нужно сделать следующее, чтобы проверить мои изменения:

  1. внести изменения
  2. построить и развернуть
  3. перезагрузите сервер после развертывания

Если кто-то случайно узнает, почему горячее / простое развертывание изменяет поведение адаптера JAX-RS, я жду ответа

0 ответов

Просто чтобы вернуться к SO здесь, OP поднял подробную проблему GitHub на Yasson, и основная причина заключается в том, что Yasson кэширует объектную модель (поэтому ему не нужно каждый раз пересматривать объектные модели). Это кэширование вызывает проблему в среде сервера приложений, где Yasson предоставляется контейнером (например, среда выполнения JAX-RS), и когда пользователь обновляет свое приложение, только его классы приложения перезагружаются, но Yasson и его кеши остаются загруженными.

Краткосрочное исправление

Обходной путь на данный момент - перезапустить сервер приложений при внесении изменений в ваши классы данных JSON-B.

Долгосрочный

Я собираюсь выяснить, может ли спецификация Yasson и / или JSON-B определить своего рода ловушку "очистки кеша". Идея заключается в том, что, когда сервер приложений выполняет горячее обновление приложения, он может вызвать этот крюк "очистки кэша", чтобы очистить сохраненную объектную модель от приложения.

Другие вопросы по тегам