FasterXML / FasterXML/jackson-databind
Inner classes that get their generic information from an outer class lose type information
- Lenguaje dominante
- Java
- Estrellas
- 3.7k
- Forks
- 1.5k
- Merge medio
- 3 d 6 h
- PR fusionados (30 d)
- 28
Descripción
**Describe the bug**
If a non-static inner class uses generics from the outer class, that generic information is lost when serializing.
**Version information**
2.12.5
**To Reproduce**
```java
import static org.assertj.core.api.Assertions.assertThat;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
public final class JacksonPoC {
@JsonTypeInfo(use = Id.NAME)
@JsonSubTypes({@JsonSubTypes.Type(value = ConcreteValue.class, name = "concrete-value")})
private interface AbstractValue {}
private static class ConcreteValue implements AbstractValue {}
public interface Wrapper {
T getValue();
}
private static final class Outer {
private final class Inner implements Wrapper {
private final T value;
Inner(T value) {
this.value = value;
}
@Override
public T getValue() {
return value;
}
}
Inner create(T value) {
return new Inner(value);
}
}
private static final class Direct implements Wrapper {
private final T value;
Direct(T value) {
this.value = value;
}
@Override
public T getValue() {
return value;
}
}
private static final class Container {
private final Wrapper wrapper;
Container(Wrapper wrapper) {
this.wrapper = wrapper;
}
public Wrapper getWrapper() {
return wrapper;
}
}
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void direct() throws Exception {
// This test passes because the generic information is present on the class directly
Container object = new Container(new Direct<>(new ConcreteValue()));
assertThat(mapper.writeValueAsString(object))
.isEqualTo("{\"wrapper\":{\"value\":{\"@type\":\"concrete-value\"}}}");
}
@Test
void indirect() throws Exception {
// This test fails (the @type part is omitted) because the `AbstractValue` information is lost
Container object = new Container(new Outer().create(new ConcreteValue()));
assertThat(mapper.writeValueAsString(object))
.isEqualTo("{\"wrapper\":{\"value\":{\"@type\":\"concrete-value\"}}}");
}
}
```
**Additional context**
The example above does feel quite contrived, but I encountered this in practice with Guava's Multimaps.asMap on a SetMultimap, because the resulting class `AbstractMapBasedMultimap.WrappedSet` inherits the generic information from the parent.
When debugging this, I got as far as the short-circuit in https://github.com/FasterXML/jackson-databind/blob/77e8b62fed4748d19fbd350c9fd80a7bdca75c91/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java#L487, but I'm not sure whether simply removing that is sufficient to resolve this.
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Evaluación
Este issue todavía no se ha evaluado.