question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Jackson does not support deserializing new Java 9 unmodifiable collections

See original GitHub issue

Describe the bug Java 9 introduced new unmodifiable collection APIs. For instance, List.of.

Today, Jackson has a special deserializer for Collections.unmodifiableList but not for these new classes: https://github.com/FasterXML/jackson-databind/blob/a64e1bfd7ced17c2e19e73da1a00f3e679011fec/src/main/java/com/fasterxml/jackson/databind/deser/impl/JavaUtilCollectionsDeserializers.java#L81

Version information 2.11.2

To Reproduce

@Test
public void testUnmodifiableList() throws JsonMappingException, JsonProcessingException {
	final ObjectMapper mapper = new ObjectMapper();
	mapper.activateDefaultTypingAsProperty(
		new NoCheckSubTypeValidator(),
		ObjectMapper.DefaultTyping.NON_FINAL,
		"@class"
	);

	final List<String> list = Collections.unmodifiableList(Collections.singletonList("a"));
	final String actualJson = mapper.writeValueAsString(list);
	System.out.println(actualJson);
	final List output = mapper.readValue(actualJson, List.class);
	System.out.println(output);
}

@Test
public void testJava9UmodifiableList() throws JsonMappingException, JsonProcessingException {
	final ObjectMapper mapper = new ObjectMapper();
	mapper.activateDefaultTypingAsProperty(
		new NoCheckSubTypeValidator(),
		ObjectMapper.DefaultTyping.NON_FINAL,
		"@class"
	);

	final List<String> list = List.of("a");
	final String actualJson = mapper.writeValueAsString(list);
	System.out.println(actualJson);
	final List output = mapper.readValue(actualJson, List.class);
	System.out.println(output);
}

@Test
public void testJava9ListWrapped() throws JsonMappingException, JsonProcessingException {
	final ObjectMapper mapper = new ObjectMapper();
	mapper.activateDefaultTypingAsProperty(
		new NoCheckSubTypeValidator(),
		ObjectMapper.DefaultTyping.NON_FINAL,
		"@class"
	);

	final List<String> list = Collections.unmodifiableList(List.of("a"));
	final String actualJson = mapper.writeValueAsString(list);
	System.out.println(actualJson);
	final List output = mapper.readValue(actualJson, List.class);
	System.out.println(output);
}

testJava9UmodifiableList fails. The other 2 pass.

Expected behavior I would think the new classes are added as additional aliases as candidates for special deserialization.

Unfortunately, I think this is tricky for two reasons:

  1. These are Java 9 classes and Jackson supports a lower minimum Java version. I’m not sure if there’s a way to add them without breaking backwards compatibility or introducing a new Java 9 add-on library, like there exists for Java 8.
  2. There are multiple classes. For List.of, there seem to be 3 different ones depending on the number of arguments:

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:2
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
cowtowncodercommented, Nov 10, 2020

Ok, had a chance to look a bit into this. I agree with notes on 2 main challenges, but there is also third immediate problem wrt tests: type for List is actually final which is what sort of breaks the test since:

  1. During serialization, actual type – which is final – will result in no type information being added, BUT
  2. During deserialization, requested type – List – is NON-FINAL and as such no type information is excepted

so test would fail even if special handling was added.

For now I think I can at least add failing test(s), under src/test-jdk14/ to allow reproducing the issue, in case someone has time to look deeper into possible solutions.

0reactions
Sam-Kruglovcommented, Dec 7, 2021

Hi, 2.13.0 doesn’t seem to work with Set.of() and I don’t see any tests for it, there’re only for List.of() and Map.of().

Read more comments on GitHub >

github_iconTop Results From Across the Web

jackson serializing Collections.unmodifiable* - Stack Overflow
UnmodifiableCollection you won't be able to deserialize it. You probably don't need to to use unmodifiable collection to be serialized. What is ...
Read more >
Security update for jackson-databind, jackson-dataformats ...
... Jackson does not support deserializing new Java 9 unmodifiable collections + Allocate TokenBuffer instance via context objects (to allow ...
Read more >
Frequently Asked Questions - XStream
registerConverter(new JavaFieldConverter(javaClassConverter, mapper){});. My implicit collection is suddenly null after deserialization instead of empty! By ...
Read more >
JsonDeserializer (jackson-databind 2.12.1 API) - javadoc.io
Abstract class that defines API used by ObjectMapper (and other chained JsonDeserializer s too) to deserialize Objects of arbitrary types from JSON, ...
Read more >
Jackson: java.util.LinkedHashMap cannot be cast to X
Second, when Jackson attempts to deserialize an object in JSON but no target type information is given, it'll use the default type: ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found