Skip to content
4 changes: 4 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -1738,3 +1738,7 @@ Muhammad Khalikov (mukham12@github)
* Contributed fix for #4209: Make `BeanDeserializerModifier`/`BeanSerializerModifier`
implement `java.io.Serializable`
(2.17.0)

Eduard Dudar (edudar@github)
* Contributed #4299: Some `Collection` and `Map` fallbacks don't work in GraalVM native image
(2.17.0)
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Project: jackson-databind
#4262: Improve handling of `null` insertion failure for `TreeSet`
#4263: Change `ObjectArrayDeserializer` to use "generic" type parameter
(`java.lang.Object`) to remove co-variant return type
#4299: Some `Collection` and `Map` fallbacks don't work in GraalVM native image
(contributed by Eduard D)
#4309: `@JsonSetter(nulls=...)` handling of `Collection` `null` values during
deserialization with `READ_UNKNOWN_ENUM_VALUES_AS_NULL` and `FAIL_ON_INVALID_SUBTYPE` wrong
(reported by @ivan-zaitsev)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import com.fasterxml.jackson.core.JsonLocation;

Expand All @@ -28,14 +29,23 @@ public static ValueInstantiator findStdValueInstantiator(DeserializationConfig c
// [databind#1868]: empty List/Set/Map
// [databind#2416]: optimize commonly needed default creators
if (Collection.class.isAssignableFrom(raw)) {
if (raw == ArrayList.class) {
if (raw == ArrayList.class) { // default impl, pre-constructed instance
return ArrayListInstantiator.INSTANCE;
}
if (Collections.EMPTY_SET.getClass() == raw) {
return new ConstantValueInstantiator(Collections.EMPTY_SET);
if (raw == HashSet.class) { // default impl, pre-constructed instance
return HashSetInstantiator.INSTANCE;
}
if (Collections.EMPTY_LIST.getClass() == raw) {
return new ConstantValueInstantiator(Collections.EMPTY_LIST);
if (raw == LinkedList.class) {
return new LinkedListInstantiator();
}
if (raw == TreeSet.class) {
return new TreeSetInstantiator();
}
if (raw == Collections.emptySet().getClass()) {
return new ConstantValueInstantiator(Collections.emptySet());
}
if (raw == Collections.emptyList().getClass()) {
return new ConstantValueInstantiator(Collections.emptyList());
}
} else if (Map.class.isAssignableFrom(raw)) {
if (raw == LinkedHashMap.class) {
Expand All @@ -44,18 +54,25 @@ public static ValueInstantiator findStdValueInstantiator(DeserializationConfig c
if (raw == HashMap.class) {
return HashMapInstantiator.INSTANCE;
}
if (Collections.EMPTY_MAP.getClass() == raw) {
return new ConstantValueInstantiator(Collections.EMPTY_MAP);
if (raw == ConcurrentHashMap.class) {
return new ConcurrentHashMapInstantiator();
}
if (raw == TreeMap.class) {
return new TreeMapInstantiator();
}
if (raw == Collections.emptyMap().getClass()) {
return new ConstantValueInstantiator(Collections.emptyMap());
}
}
return null;
}

// @since 2.17
private abstract static class JDKValueInstantiator
extends ValueInstantiator.Base
implements java.io.Serializable
{
private static final long serialVersionUID = 2L;
private static final long serialVersionUID = 2L;

public JDKValueInstantiator(Class<?> type) {
super(type);
Expand All @@ -77,7 +94,8 @@ private static class ArrayListInstantiator
{
private static final long serialVersionUID = 2L;

public final static ArrayListInstantiator INSTANCE = new ArrayListInstantiator();
static final ArrayListInstantiator INSTANCE = new ArrayListInstantiator();

public ArrayListInstantiator() {
super(ArrayList.class);
}
Expand All @@ -88,12 +106,78 @@ public Object createUsingDefault(DeserializationContext ctxt) throws IOException
}
}

// @since 2.17 [databind#4299] Instantiators for additional container classes
private static class LinkedListInstantiator
extends JDKValueInstantiator
{
private static final long serialVersionUID = 2L;

public LinkedListInstantiator() {
super(LinkedList.class);
}

@Override
public Object createUsingDefault(DeserializationContext ctxt) throws IOException {
return new LinkedList<>();
}
}

// @since 2.17 [databind#4299] Instantiators for additional container classes
private static class HashSetInstantiator
extends JDKValueInstantiator
{
private static final long serialVersionUID = 2L;

static final HashSetInstantiator INSTANCE = new HashSetInstantiator();

public HashSetInstantiator() {
super(HashSet.class);
}

@Override
public Object createUsingDefault(DeserializationContext ctxt) throws IOException {
return new HashSet<>();
}
}

// @since 2.17 [databind#4299] Instantiators for additional container classes
private static class TreeSetInstantiator
extends JDKValueInstantiator
{
private static final long serialVersionUID = 2L;

public TreeSetInstantiator() {
super(TreeSet.class);
}

@Override
public Object createUsingDefault(DeserializationContext ctxt) throws IOException {
return new TreeSet<>();
}
}

// @since 2.17 [databind#4299] Instantiators for additional container classes
private static class ConcurrentHashMapInstantiator
extends JDKValueInstantiator
{
private static final long serialVersionUID = 2L;

public ConcurrentHashMapInstantiator() {
super(ConcurrentHashMap.class);
}

@Override
public Object createUsingDefault(DeserializationContext ctxt) throws IOException {
return new ConcurrentHashMap<>();
}
}

private static class HashMapInstantiator
extends JDKValueInstantiator
{
private static final long serialVersionUID = 2L;

public final static HashMapInstantiator INSTANCE = new HashMapInstantiator();
static final HashMapInstantiator INSTANCE = new HashMapInstantiator();

public HashMapInstantiator() {
super(HashMap.class);
Expand All @@ -110,7 +194,7 @@ private static class LinkedHashMapInstantiator
{
private static final long serialVersionUID = 2L;

public final static LinkedHashMapInstantiator INSTANCE = new LinkedHashMapInstantiator();
static final LinkedHashMapInstantiator INSTANCE = new LinkedHashMapInstantiator();

public LinkedHashMapInstantiator() {
super(LinkedHashMap.class);
Expand All @@ -122,6 +206,22 @@ public Object createUsingDefault(DeserializationContext ctxt) throws IOException
}
}

// @since 2.17 [databind#4299] Instantiators for additional container classes
private static class TreeMapInstantiator
extends JDKValueInstantiator
{
private static final long serialVersionUID = 2L;

public TreeMapInstantiator() {
super(TreeMap.class);
}

@Override
public Object createUsingDefault(DeserializationContext ctxt) throws IOException {
return new TreeMap<>();
}
}

private static class ConstantValueInstantiator
extends JDKValueInstantiator
{
Expand All @@ -135,7 +235,7 @@ public ConstantValueInstantiator(Object value) {
}

@Override
public Object createUsingDefault(DeserializationContext ctxt) throws IOException {
public final Object createUsingDefault(DeserializationContext ctxt) throws IOException {
return _value;
}
}
Expand Down