eclipse-ee4j / eclipse-ee4j/yasson
@JsonbTypeAdapter is not applied for unmarshalling when @JsonbCreator is used
- Dominant language
- Java
- Stars
- 218
- Forks
- 109
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 9
Description
Suppose we have a following enum type
```java
public static enum EnumType {
ONE("one"),
TWO("two");
private EnumType(String value) {
this.value = value;
}
private final String value;
public String getValue() {
return value;
}
public static EnumType of(String value) {
for (EnumType t : EnumType.values()) {
if (t.value.equals(value)) {
return t;
}
}
return null;
}
}
```
Then, let's define a custom JsonbAdapter for a list of EnumTypes:
```java
public class EnumTypeListAdapter implements JsonbAdapter, JsonArray> {
@Override
public JsonArray adaptToJson(List obj) {
System.out.println("I am marshalling the list of EnumTypes to JsonArray");
return Json.createArrayBuilder(obj.stream()
.map(EnumType::getValue)
.collect(Collectors.toList()))
.build();
}
@Override
public List adaptFromJson(JsonArray obj) {
System.out.println("I am unmarshalling the list of EnumTypes from JsonArray");
List enums = new ArrayList<>();
for (JsonString s : obj.getValuesAs(JsonString.class)) {
enums.add(EnumType.of(s.getString()));
}
return enums;
}
}
```
Then for the type defined as:
```java
public class CollectionAdapterType {
@JsonbTypeAdapter(EnumTypeListAdapter.class)
private List enums;
public CollectionAdapterType() {
}
public CollectionAdapterType(List enums) {
this.enums = enums;
}
public List getEnums() {
return enums;
}
public void setEnums(List enums) {
this.enums = enums;
}
}
```
the following test passes:
```java
public class CollectionAdapterTypeTest {
@Test
public void test() {
CollectionAdapterType coll = new CollectionAdapterType(asList(EnumType.ONE, EnumType.TWO));
Jsonb jsonb = JsonbBuilder.create();
String result = jsonb.toJson(coll);
assertEquals("{\"enums\":[\"one\",\"two\"]}", result);
CollectionAdapterType unmarshalled = jsonb.fromJson(result, CollectionAdapterType.class);
assertEquals(coll.getEnums(), unmarshalled.getEnums());
// passes as the custom type adapter has been called for both marshalling and unmarshalling
}
}
```
However, when we define the type with @JsonbCreator, such as:
```java
public class CollectionAdapterCreatorType {
@JsonbTypeAdapter(EnumTypeListAdapter.class)
private List enums;
private CollectionAdapterCreatorType(List enums) {
this.enums = enums;
}
@JsonbCreator
public static CollectionAdapterCreatorType create(@JsonbProperty("enums") List enums) {
return new CollectionAdapterCreatorType(enums);
}
public List getEnums() {
return enums;
}
public void setEnums(List enums) {
this.enums = enums;
}
}
```
then the following test fails:
```java
public class CollectionAdapterCreatorTypeTest {
@Test
public void test() {
CollectionAdapterCreatorType coll = CollectionAdapterCreatorType.create(asList(EnumType.ONE, EnumType.TWO));
Jsonb jsonb = JsonbBuilder.create();
String result = jsonb.toJson(coll);
assertEquals("{\"enums\":[\"one\",\"two\"]}", result);
CollectionAdapterCreatorType unmarshalled = jsonb.fromJson(result, CollectionAdapterCreatorType.class);
assertEquals(coll.getEnums(), unmarshalled.getEnums());
// custom adapter was called only for marshalling
}
}
```
The reason is that the EnumTypeListAdapter was used only when marshalling (and the CollectionAdapterCreatorType type is marshalled correctly), however, it was not picked up when unmarshalling, causing the failure.
Note: I have used Yasson 1.0.3.
Contributor guide
Research direction
Start by reproducing the failure in CollectionAdapterCreatorTypeTest using JsonbBuilder.fromJson and compare it with CollectionAdapterTypeTest. Trace how @JsonbCreator and @JsonbTypeAdapter are processed during unmarshalling; done means EnumTypeListAdapter is called and the creator-based type round-trips with the expected enum list.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100