Skip to content

Commit

Permalink
Merge branch '2.19' into 4388-try-another
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder authored Nov 12, 2024
2 parents 215f7cc + 5bdb34d commit ae2cdaf
Show file tree
Hide file tree
Showing 16 changed files with 353 additions and 42 deletions.
3 changes: 3 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,9 @@ Eduard Gomoliako (@Gems)
* Reported #4602: Possible wrong use of _arrayDelegateDeserializer in
BeanDeserializerBase::deserializeFromObjectUsingNonDefault()
(2.18.0)
* Reported #4772: Serialization and deserialization issue of sub-types used with
`JsonTypeInfo.Id.DEDUCTION` where sub-types are Object and Array
(2.19.0)
Mathijs Vogelzang (@mathijs81)
* Reported #4678: Java records don't serialize with `MapperFeature.REQUIRE_SETTERS_FOR_GETTERS`
Expand Down
6 changes: 6 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ Project: jackson-databind
Map object is ignored when Map key type not defined
(reported by @devdanylo)
(fix by Joo-Hyuk K)
#4772: Serialization and deserialization issue of sub-types used with
`JsonTypeInfo.Id.DEDUCTION` where sub-types are Object and Array
(reported by Eduard G)
#4773: `SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS` should not apply to Maps
with uncomparable keys
(requested by @nathanukey)
Expand All @@ -33,6 +36,9 @@ Project: jackson-databind

#4733: Wrong serialization of Type Ids for certain types of Enum values
(reported by @nlisker)
#4783 Possibly wrong behavior of @JsonMerge
(reported by @nlisker)
(fix by Joo-Hyuk K)
#4787: Wrong `String.format()` in `StdDelegatingDeserializer` hides actual error
(reported by @Horus1337)
#4788: `EnumFeature.WRITE_ENUMS_TO_LOWERCASE` overrides `@JsonProperty` values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -820,13 +820,7 @@ public JsonDeserializer<?> createCollectionDeserializer(DeserializationContext c
if (deser == null) {
if (type.isInterface() || type.isAbstract()) {
CollectionType implType = _mapAbstractCollectionType(type, config);
if (implType == null) {
// [databind#292]: Actually, may be fine, but only if polymorphich deser enabled
if (type.getTypeHandler() == null) {
throw new IllegalArgumentException("Cannot find a deserializer for non-concrete Collection type "+type);
}
deser = AbstractDeserializer.constructForNonPOJO(beanDesc);
} else {
if (implType != null) {
type = implType;
// But if so, also need to re-check creators...
beanDesc = config.introspectForCreation(type);
Expand Down Expand Up @@ -968,9 +962,9 @@ public JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
*/
if (deser == null) {
if (type.isInterface() || type.isAbstract()) {
MapType fallback = _mapAbstractMapType(type, config);
if (fallback != null) {
type = (MapType) fallback;
MapType implType = _mapAbstractMapType(type, config);
if (implType != null) {
type = (MapType) implType;
mapClass = type.getRawClass();
// But if so, also need to re-check creators...
beanDesc = config.introspectForCreation(type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@

// [databind#4639] 2.18.1 : regression when using @JsonAnySetter outside of @JsonCreator
public class AnySetterFieldWithCreator4639Test
extends DatabindTestUtil
extends DatabindTestUtil
{

public static class Bean {
int b;
int d;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class SingleImmutableFieldCreatorTest
extends DatabindTestUtil
{
static class ImmutableId {
private final int id;
final int id;

public ImmutableId(int id) { this.id = id; }

Expand All @@ -28,7 +28,7 @@ public int getId() {
}

static class ImmutableIdWithEmptyConstuctor {
private final int id;
final int id;

public ImmutableIdWithEmptyConstuctor() { this(-1); }

Expand All @@ -40,7 +40,7 @@ public int getId() {
}

static class ImmutableIdWithJsonCreatorAnnotation {
private final int id;
final int id;

@JsonCreator
public ImmutableIdWithJsonCreatorAnnotation(int id) { this.id = id; }
Expand All @@ -51,7 +51,8 @@ public int getId() {
}

static class ImmutableIdWithJsonPropertyFieldAnnotation {
@JsonProperty("id") private final int id;
@JsonProperty("id")
final int id;

public ImmutableIdWithJsonPropertyFieldAnnotation(int id) { this.id = id; }

Expand All @@ -61,7 +62,7 @@ public int getId() {
}

static class ImmutableIdWithJsonPropertyConstructorAnnotation {
private final int id;
final int id;

public ImmutableIdWithJsonPropertyConstructorAnnotation(@JsonProperty("id") int id) { this.id = id; }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package com.fasterxml.jackson.databind.deser.merge;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.annotation.JsonMerge;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

// [databind#4783] Test to verify that JsonMerge also works for custom list
@SuppressWarnings("serial")
public class CustomCollectionMerge4783Test
extends DatabindTestUtil
{
static class MyArrayListJDK<T> extends ArrayList<T> { }

static class MergeListJDK {
@JsonMerge
@JsonProperty
public List<String> values = new MyArrayListJDK<>();
{ values.add("a");}
}

interface MyListCustom<T> extends List<T> { }

static class MyArrayListCustom<T> extends ArrayList<T> implements MyListCustom<T> { }

static abstract class MyAbstractStringList extends ArrayList<String> {
MyAbstractStringList() { super(); }
MyAbstractStringList(int i) { super(); }
}

static class MergeCustomStringList {
@JsonMerge
@JsonProperty
public MyListCustom<String> values = new MyArrayListCustom<>();
{ values.add("a"); }
}

static class MergeMyCustomLongList {
@JsonMerge
@JsonProperty
public MyListCustom<Long> values = new MyArrayListCustom<>();
{ values.add(1L); }
}

static class MergeMyCustomPojoList {
@JsonMerge
@JsonProperty
public MyListCustom<CustomPojo> values = new MyArrayListCustom<>();
{
values.add(CustomPojo.create("a", 1));
values.add(CustomPojo.create("b", 2));
}
}

// And then non-merging case too
static class NonMergeCustomStringList {
public MyListCustom<String> values;
}

public static class CustomPojo {
public String name;
public int age;

public static CustomPojo create(String name, int age) {
CustomPojo pojo = new CustomPojo();
pojo.name = name;
pojo.age = age;
return pojo;
}
}

private final ObjectMapper MAPPER = newJsonMapper();

@Test
void testJDKMapperReading() throws Exception {
MergeListJDK result = MAPPER.readValue("{\"values\":[\"x\"]}", MergeListJDK.class);

assertEquals(2, result.values.size());
assertTrue(result.values.contains("x"));
assertTrue(result.values.contains("a"));
}

@Test
void testCustomMapperReading() throws Exception {
MergeCustomStringList result = MAPPER.readValue("{\"values\":[\"x\"]}",
MergeCustomStringList.class);

assertEquals(2, result.values.size());
assertTrue(result.values.contains("x"));
assertTrue(result.values.contains("a"));
}

@Test
void testCustomMapperReadingLongArrayList() throws Exception {
MergeMyCustomLongList result = MAPPER.readValue("{\"values\":[7]}",
MergeMyCustomLongList.class);

assertEquals(2, result.values.size());
assertTrue(result.values.contains(1L));
assertTrue(result.values.contains(7L));
}

@Test
void testCustomMapperReadingPojoArrayList() throws Exception {
MergeMyCustomPojoList result = MAPPER.readValue("{\"values\":[{\"name\":\"c\",\"age\":3}]}",
MergeMyCustomPojoList.class);

assertEquals(3, result.values.size());
}

// // // And then failure cases

// Fail can't construct Collection interface unless there's maaping
@Test
void failNonMergeInterfaceList() throws Exception {
try {
MAPPER.readValue("{\"values\":[\"x\"]}", NonMergeCustomStringList.class);
fail("Should not pass");
} catch (InvalidDefinitionException e) {
verifyException(e, String.format(
"Cannot construct instance of `%s` (no Creators",
MyListCustom.class.getName()));
}
}

// Fail can't construct abstract types
@Test
void failNonMergeAbstractList() throws Exception {
try {
MAPPER.readValue("[]", MyAbstractStringList.class);
fail("Should not pass");
} catch (InvalidDefinitionException e) {
verifyException(e, String.format(
"Cannot construct instance of `%s` (no Creators",
MyAbstractStringList.class.getName()));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.fasterxml.jackson.databind.jsontype;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;

import static org.junit.jupiter.api.Assertions.*;

public class PolymorphicDeductionObjectVsArrayTest extends DatabindTestUtil {
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, defaultImpl = DataArray.class)
@JsonSubTypes({@JsonSubTypes.Type(DataObject.class), @JsonSubTypes.Type(DataArray.class)})
interface Data {
@JsonIgnore
boolean isObject();
}

static class DataItem {
final String id;

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
DataItem(@JsonProperty("id") String id) {
this.id = id;
}

public String getId() {
return id;
}
}

static class DataObject extends DataItem implements Data {

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
DataObject(@JsonProperty("id") String id) {
super(id);
}

@Override
public boolean isObject() {
return true;
}
}

static class DataArray extends ArrayList<DataItem> implements Data {
private static final long serialVersionUID = 1L;

@JsonCreator
DataArray(Collection<DataItem> items) {
super(new ArrayList<>(items));
}

@Override
public boolean isObject() {
return false;
}
}

static class Container {
@JsonProperty("data")
Data data;
}

private final ObjectMapper MAPPER = newJsonMapper();

private static final String containerWithObjectData = a2q("{'data':{'id':'#1'}}");

private static final String containerWithArrayData = a2q("{'data':[{'id':'#1'}]}");

@Test
public void testDeserialization() throws Exception {
Container container = MAPPER.readValue(containerWithObjectData, Container.class);

assertInstanceOf(DataObject.class, container.data);
assertSame(container.data.getClass(), DataObject.class);
assertTrue(container.data.isObject());
assertEquals("#1", ((DataItem) container.data).id);

container = MAPPER.readValue(containerWithArrayData, Container.class);
assertInstanceOf(DataArray.class, container.data);
assertEquals(container.data.getClass(), DataArray.class);
assertFalse(container.data.isObject());

@SuppressWarnings("unchecked")
Iterator<DataItem> arrayDataIterator = ((Iterable<DataItem>) container.data).iterator();

assertTrue(arrayDataIterator.hasNext());
assertEquals("#1", arrayDataIterator.next().id);
}

@Test
public void testSerialization() throws Exception {
Container container = new Container();
container.data = new DataObject("#1");
String json = MAPPER.writeValueAsString(container);
assertEquals(containerWithObjectData, json);

container = new Container();
container.data = new DataArray(Arrays.asList(new DataItem("#1")));
json = MAPPER.writeValueAsString(container);
assertEquals(containerWithArrayData, json);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import com.fasterxml.jackson.databind.type.TypeFactory;

import static org.junit.jupiter.api.Assertions.*;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,11 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonValue;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import com.fasterxml.jackson.databind.type.TypeFactory;

import static org.junit.jupiter.api.Assertions.*;

Expand Down
Loading

0 comments on commit ae2cdaf

Please sign in to comment.