eclipse-ee4j / eclipse-ee4j/yasson

JSON-B adapters + JAX-RS 2.1 + hot-deploying = not working

Open
#76 14 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Java
Stars
218
Forks
109
Avg merge
1d 5h
Merged PRs (30d)
9

Description

## Short version

### Cannot use hot-deploy with adapters

When using `JsonbTypeAdapter`, hot deploying makes the adapters unusable. Configuration is:

- Payara 5.0.0.Alpha3 Full
- Java EE 8: same behaviour whether using `javaee-web-api` (standalone war module) or `javaee-api` (ear application made of 1 x Ejb + N x web)
- aiming for JAX-RS 2.1
- using JSON-P 1.1 and JSON-B 1.0
- Yasson dependency is not explicitly used, it seems that the implementation of Payara takes precedence
- JPA not used
- `JsonbTypeAdapter` have injected `@EJB`
- Netbeans 8.2

When loading the fake database, a `@Singleton`, I successfully test if the `JsonbTypeAdapter` are working

### Workaround

> Simply reboot the application server. There is no need to manually re-deploy first, the last hot-deploy will be taken into account.

---

## Context:

I'm comparing `JSON-B 1.0` vs `JSON-P 1.1`. I faked entities so that JPA is not involved yet. Full source code is [here](https://github.com/Xsylum/java-ee/tree/master/jax-rs).

There is no testing page. REST testing is done with [Google's Postman](https://www.getpostman.com/)

My simple entities look like:

**Company** ([full code link](https://github.com/Xsylum/java-ee/blob/master/jax-rs/src/main/java/com/playground/jax/rs/organisation/Company.java))
```java
@JsonbPropertyOrder(PropertyOrderStrategy.ANY)
public class Company{
private Long id;
private String name;

@JsonbTypeAdapter(DepartmentListAdapter.class)
private List departments; // fake a @OneToMany relationship
//...
}
```

**Department** ([full code link](https://github.com/Xsylum/java-ee/blob/master/jax-rs/src/main/java/com/playground/jax/rs/organisation/Department.java))
```java
@JsonbPropertyOrder(PropertyOrderStrategy.ANY)
public class Department{
private Long id;
private String name;

@JsonbTypeAdapter(CompanyAdapter.class)
private Company company; // fake a @ManyToOne relationship
// ...
}
```

## JSON-B & Adapter

To avoid circular serialization (Company -> Department -> Company) I have the following adapters:

1. [`DepartmentListAdapter implements JsonbAdapter, JsonArray>`](https://github.com/Xsylum/java-ee/blob/master/jax-rs/src/main/java/com/playground/jax/rs/organisation/DepartmentListAdapter.java)
2. [`CompanyAdapter implements JsonbAdapter`](https://github.com/Xsylum/java-ee/blob/master/jax-rs/src/main/java/com/playground/jax/rs/organisation/CompanyAdapter.java)

Adapter works fine with a basic:

```java
Jsonb jsonB = JsonbBuilder.create();
jsonB.toJson(departmentsList);
```

## Errors

As said earlier, in both situation, a server reboot fixes the issue.

### Without using EJB

If I comment out the `@EJB` injection (`adaptFromJson(...)` always return `null`), a `ClassCastException` is triggered after the first hot-deploy:

- when requesting companies list:
> `java.lang.ClassCastException: com.playground.jax.rs.organisation.Department cannot be cast to com.playground.jax.rs.organisation.Department`

- similarly, when requesting departments list:
> `java.lang.ClassCastException: com.playground.jax.rs.organisation.Company cannot be cast to com.playground.jax.rs.organisation.Company`

Stacktrace is:

```
at org.eclipse.yasson.internal.serializer.AdaptedObjectSerializer.serialize(AdaptedObjectSerializer.java:103)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serializerCaptor(AbstractContainerSerializer.java:91)
at org.eclipse.yasson.internal.serializer.ObjectSerializer.marshallProperty(ObjectSerializer.java:85)
at org.eclipse.yasson.internal.serializer.ObjectSerializer.serializeInternal(ObjectSerializer.java:59)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:60)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serializerCaptor(AbstractContainerSerializer.java:91)
at org.eclipse.yasson.internal.serializer.CollectionSerializer.serializeInternal(CollectionSerializer.java:79)
at org.eclipse.yasson.internal.serializer.CollectionSerializer.serializeInternal(CollectionSerializer.java:35)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:60)
at org.eclipse.yasson.internal.Marshaller.serializeRoot(Marshaller.java:118)
at org.eclipse.yasson.internal.Marshaller.marshall(Marshaller.java:76)
at org.eclipse.yasson.internal.JsonBinding.toJson(JsonBinding.java:98)
at org.glassfish.jersey.jsonb.internal.JsonBindingProvider.writeTo(JsonBindingProvider.java:118)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:266)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:251)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163)
at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:109)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163)
at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:85)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163)
at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1135)
```

### With EJB

Similarly, if I leave the `@EJB` injection, the error becomes

```
java.lang.IllegalArgumentException: Can not set com.playground.jax.rs.dummydata.FakeDatabase field com.playground.jax.rs.organisation.CompanyAdapter.db to com.playground.jax.rs.organisation.CompanyAdapter
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:764)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:688)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.inject(InjectionManagerImpl.java:507)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:170)
at org.glassfish.weld.services.InjectionServicesImpl.aroundInject(InjectionServicesImpl.java:166)
at org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:46)
at org.jboss.weld.injection.producer.ResourceInjector.inject(ResourceInjector.java:71)
at org.jboss.weld.injection.producer.BasicInjectionTarget.inject(BasicInjectionTarget.java:117)
at org.eclipse.yasson.internal.components.BeanManagerInstanceCreator.lambda$getOrCreateComponent$0(BeanManagerInstanceCreator.java:63)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
at org.eclipse.yasson.internal.components.BeanManagerInstanceCreator.getOrCreateComponent(BeanManagerInstanceCreator.java:58)
at org.eclipse.yasson.internal.ComponentMatcher.introspectAdapterBinding(ComponentMatcher.java:239)
at org.eclipse.yasson.internal.AnnotationIntrospector.getAdapterBindingFromAnnotation(AnnotationIntrospector.java:208)
at org.eclipse.yasson.internal.AnnotationIntrospector.getAdapterBinding(AnnotationIntrospector.java:203)
at org.eclipse.yasson.internal.model.PropertyModel.getUserAdapterBinding(PropertyModel.java:120)
at org.eclipse.yasson.internal.model.PropertyModel.introspectCustomization(PropertyModel.java:174)
at org.eclipse.yasson.internal.model.PropertyModel.(PropertyModel.java:87)
at org.eclipse.yasson.internal.model.customization.ordering.PropertyOrdering.orderProperties(PropertyOrdering.java:70)
at org.eclipse.yasson.internal.ClassParser.parseProperties(ClassParser.java:60)
at org.eclipse.yasson.internal.MappingContext$ParseClassModelFunction.apply(MappingContext.java:56)
at org.eclipse.yasson.internal.MappingContext$ParseClassModelFunction.apply(MappingContext.java:37)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
at org.eclipse.yasson.internal.MappingContext.getOrCreateClassModel(MappingContext.java:100)
at org.eclipse.yasson.internal.serializer.AbstractSerializerBuilder.getClassModel(AbstractSerializerBuilder.java:100)
at org.eclipse.yasson.internal.serializer.DeserializerBuilder.build(DeserializerBuilder.java:145)
at org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:56)
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)
at org.glassfish.jersey.jsonb.internal.JsonBindingProvider.readFrom(JsonBindingProvider.java:99)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:257)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:236)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:156)
at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:73)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:156)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1091)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
at org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:271)
at org.glassfish.jersey.server.internal.inject.EntityParamValueParamProvider$EntityValueSupplier.apply(EntityParamValueParamProvider.java:97)
at org.glassfish.jersey.server.internal.inject.EntityParamValueParamProvider$EntityValueSupplier.apply(EntityParamValueParamProvider.java:80)
at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.apply(ParamValueFactoryWithSource.java:74)
at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:92)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:133)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:200)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:103)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:493)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:415)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:104)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:277)
```

---

I tried to do some debug with basic `System.out.println` in a cloned `org.eclipse.yasson` but Netbeans does not like Java SE 9 so it didn't give me relevant hints

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.