FasterXML / FasterXML/jackson-databind

Inner classes that get their generic information from an outer class lose type information

Abierto
#3,288 0 comentarios 0 reacciones 0 asignados Ver en GitHub
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.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.