jackson-databind: Deserialization of a certain kinds of parametrized properties fail to resolve `?` into expected bounds, resulting in `LinkedHashMap`

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

Recently our code editor advices as to change the class definition, the deserialization stopped working correctly.

We have such a class:

public class TestAttribute<T extends TestAttribute<?>> {

	protected List<T> attributes;
}

When we create a parent object with a list of such properties 2-level deep, on 2rd level the deserialization doesn’t work and it deserializes into LinkedHashMap instead of TestAttribute. See the screenshot below.

image

But when I remove the “<?>” from the “extends”, then the IDE complains about it, but the deserialization works just fine

image image

Version Information

2.15.2, JDK17

Reproduction

  1. Brief code sample/snippet: include here in preformatted/code section
public class TestAttribute<T extends TestAttribute<?> {

	protected List<T> attributes;

	public TestAttribute() {
	}
	public TestAttribute(List<T> attributes) {
		this.attributes = attributes;
	}

	public List<T> getAttributes() {
		return attributes;
	}

	public void setAttributes(List<T> attributes) {
		this.attributes = attributes;
	}
}
public class TestObject {

	private List<TestAttribute<?>> attributes = new ArrayList<>();

	public TestObject() {
	}

	public TestObject(List<TestAttribute<?>> attributes) {
		this.attributes = attributes;
	}

	public List<TestAttribute<?>> getAttributes() {
		return attributes;
	}

	public void setAttributes(List<TestAttribute<?>> attributes) {
		this.attributes = attributes;
	}
}
ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
		objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
		objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
		objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

		TestAttribute a = new TestAttribute(null);
		TestAttribute b = new TestAttribute(List.of(a));
		TestAttribute c = new TestAttribute(List.of(b));

		TestObject test = new TestObject(List.of(c));
		String serialized = objectMapper.writeValueAsString(test);
		System.out.println(serialized);

		TestObject deserialized = objectMapper.readValue(serialized, TestObject.class);
		System.out.println(deserialized.getAttributes().get(0).getAttributes().get(0).getClass().getName());
  1. Textual explanation: include here When the code above is executed, the last line fails
java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class com.me.samples.TestAttribute (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.me.samples.TestAttribute is in unnamed module of loader 'app')
	at com.me.samples.PlainTest.main(PlainTest.java:38)

Expected behavior

Deserialization should work just fine and deserialize a list of TestAttribute objects correctly but instead the LinkedHashMap is deserialized instead unless I remove <?> from all my code which keeps the IDE complaining abut the missing raw parameter.

Additional context

No response

About this issue

  • Original URL
  • State: open
  • Created 9 months ago
  • Comments: 22 (20 by maintainers)

Commits related to this issue

Most upvoted comments

@poolsnowhui that looks like a Spring WebMVC problem, not Jackson’s.