Skip to content

Commit

Permalink
Fixed #2759
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Jun 17, 2020
1 parent d5e7bd1 commit 87089ae
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 41 deletions.
12 changes: 12 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -1104,3 +1104,15 @@ Simone D'Avico (simonedavico@github)
Robin Roos (robinroos@github)
* Contributed #2636: ObjectReader readValue lacks Class<T> argument
(2.11.0)

Michael Cramer (BigMichi1@github)
* Reported #2725: JsonCreator on static method in Enum and Enum used as key in map
fails randomly
(2.11.1)

Oleg Chtchoukine (oshatrk@github)
* Reported #2759: Rearranging of props when property-based generator is in use leads
to incorrect output
(2.11.1)


6 changes: 6 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ Project: jackson-databind

#2486: Builder Deserialization with JsonCreator Value vs Array
(reported by Ville K)
#2725: JsonCreator on static method in Enum and Enum used as key in map
fails randomly
(reported by Michael C)
#2755: `StdSubtypeResolver` is not thread safe (possibly due to copy
not being made with `ObjectMapper.copy()`)
(reported by tjwilson90@github)
#2759: Rearranging of props when property-based generator is in use leads
to incorrect output
(reported by Oleg C)

2.11.0 (26-Apr-2020)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,17 @@ protected BeanSerializer(BeanSerializerBase src,
ObjectIdWriter objectIdWriter, Object filterId) {
super(src, objectIdWriter, filterId);
}

protected BeanSerializer(BeanSerializerBase src, Set<String> toIgnore) {
super(src, toIgnore);
}

// @since 2.11.1
protected BeanSerializer(BeanSerializerBase src,
BeanPropertyWriter[] properties, BeanPropertyWriter[] filteredProperties) {
super(src, properties, filteredProperties);
}

/*
/**********************************************************
/* Life-cycle: factory methods, fluent factories
Expand Down Expand Up @@ -114,6 +120,12 @@ protected BeanSerializerBase withIgnorals(Set<String> toIgnore) {
return new BeanSerializer(this, toIgnore);
}

@Override // @since 2.11.1
protected BeanSerializerBase withProperties(BeanPropertyWriter[] properties,
BeanPropertyWriter[] filteredProperties) {
return new BeanSerializer(this, properties, filteredProperties);
}

/**
* Implementation has to check whether as-array serialization
* is possible reliably; if (and only if) so, will construct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.WritableTypeId;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
Expand Down Expand Up @@ -111,12 +112,20 @@ protected BeanAsArraySerializer withIgnorals(Set<String> toIgnore) {
return new BeanAsArraySerializer(this, toIgnore);
}

@Override // @since 2.11.1
protected BeanSerializerBase withProperties(BeanPropertyWriter[] properties,
BeanPropertyWriter[] filteredProperties) {
// 16-Jun-2020, tatu: Added for [databind#2759] but with as-array we
// probably do not want to reorder anything; so actually leave unchanged
return this;
}

@Override
protected BeanSerializerBase asArraySerializer() {
// already is one, so:
return this;
}

/*
/**********************************************************
/* JsonSerializer implementation that differs between impls
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fasterxml.jackson.databind.ser.impl;

import com.fasterxml.jackson.core.JsonGenerator;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
Expand Down Expand Up @@ -54,6 +55,13 @@ protected UnwrappingBeanSerializer(UnwrappingBeanSerializer src, Set<String> toI
_nameTransformer = src._nameTransformer;
}

// @since 2.11.1
protected UnwrappingBeanSerializer(UnwrappingBeanSerializer src,
BeanPropertyWriter[] properties, BeanPropertyWriter[] filteredProperties) {
super(src, properties, filteredProperties);
_nameTransformer = src._nameTransformer;
}

/*
/**********************************************************
/* Life-cycle: factory methods, fluent factories
Expand Down Expand Up @@ -86,6 +94,12 @@ protected BeanSerializerBase withIgnorals(Set<String> toIgnore) {
return new UnwrappingBeanSerializer(this, toIgnore);
}

@Override // @since 2.11.1
protected BeanSerializerBase withProperties(BeanPropertyWriter[] properties,
BeanPropertyWriter[] filteredProperties) {
return new UnwrappingBeanSerializer(this, properties, filteredProperties);
}

/**
* JSON Array output cannot be done if unwrapping operation is
* requested; so implementation will simply return 'this'.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ protected BeanSerializerBase(JavaType type, BeanSerializerBuilder builder,
}
}

public BeanSerializerBase(BeanSerializerBase src,
protected BeanSerializerBase(BeanSerializerBase src,
BeanPropertyWriter[] properties, BeanPropertyWriter[] filteredProperties)
{
super(src._handledType);
Expand Down Expand Up @@ -255,7 +255,16 @@ protected BeanSerializerBase withIgnorals(String[] toIgnore) {
*/
@Override
public abstract BeanSerializerBase withFilterId(Object filterId);


/**
* Mutant factory used for creating a new instance with modified set
* of properties
*
* @since 2.11.1
*/
protected abstract BeanSerializerBase withProperties(BeanPropertyWriter[] properties,
BeanPropertyWriter[] filteredProperties);

/**
* Copy-constructor that is useful for sub-classes that just want to
* copy all super-class properties without modifications.
Expand Down Expand Up @@ -460,6 +469,10 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
}

ObjectIdWriter oiw = _objectIdWriter;

// 16-Jun-2020, tatu: [databind#2759] means we need to handle reordering
// at a later point
int idPropOrigIndex = 0;
Set<String> ignoredProps = null;
Object newFilterId = null;

Expand All @@ -484,15 +497,14 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,

// 2.1: allow modifications by "id ref" annotations as well:
objectIdInfo = intr.findObjectReferenceInfo(accessor, objectIdInfo);
ObjectIdGenerator<?> gen;
Class<?> implClass = objectIdInfo.getGeneratorType();
JavaType type = provider.constructType(implClass);
JavaType idType = provider.getTypeFactory().findTypeParameters(type, ObjectIdGenerator.class)[0];
// Property-based generator is trickier
if (implClass == ObjectIdGenerators.PropertyGenerator.class) { // most special one, needs extra work
String propName = objectIdInfo.getPropertyName().getSimpleName();
BeanPropertyWriter idProp = null;

for (int i = 0, len = _props.length; ; ++i) {
if (i == len) {
provider.reportBadDefinition(_beanType, String.format(
Expand All @@ -502,25 +514,17 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
BeanPropertyWriter prop = _props[i];
if (propName.equals(prop.getName())) {
idProp = prop;
// Let's force it to be the first property to output
// Let's mark id prop to be moved as the first (may still get rearranged)
// (although it may still get rearranged etc)
if (i > 0) { // note: must shuffle both regular properties and filtered
System.arraycopy(_props, 0, _props, 1, i);
_props[0] = idProp;
if (_filteredProps != null) {
BeanPropertyWriter fp = _filteredProps[i];
System.arraycopy(_filteredProps, 0, _filteredProps, 1, i);
_filteredProps[0] = fp;
}
}
idPropOrigIndex = i;
break;
}
}
idType = idProp.getType();
gen = new PropertyBasedObjectIdGenerator(objectIdInfo, idProp);
ObjectIdGenerator<?> gen = new PropertyBasedObjectIdGenerator(objectIdInfo, idProp);
oiw = ObjectIdWriter.construct(idType, (PropertyName) null, gen, objectIdInfo.getAlwaysAsId());
} else { // other types need to be simpler
gen = provider.objectIdGeneratorInstance(accessor, objectIdInfo);
ObjectIdGenerator<?> gen = provider.objectIdGeneratorInstance(accessor, objectIdInfo);
oiw = ObjectIdWriter.construct(idType, objectIdInfo.getPropertyName(), gen,
objectIdInfo.getAlwaysAsId());
}
Expand All @@ -536,6 +540,25 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
}
// either way, need to resolve serializer:
BeanSerializerBase contextual = this;

// 16-Jun-2020, tatu: [databind#2759] must make copies, then reorder
if (idPropOrigIndex > 0) { // note: must shuffle both regular properties and filtered
final BeanPropertyWriter[] newProps = Arrays.copyOf(_props, _props.length);
BeanPropertyWriter bpw = newProps[idPropOrigIndex];
System.arraycopy(newProps, 0, newProps, 1, idPropOrigIndex);
newProps[0] = bpw;
final BeanPropertyWriter[] newFiltered;
if (_filteredProps == null) {
newFiltered = null;
} else {
newFiltered = Arrays.copyOf(_filteredProps, _filteredProps.length);
bpw = newFiltered[idPropOrigIndex];
System.arraycopy(newFiltered, 0, newFiltered, 1, idPropOrigIndex);
newFiltered[0] = bpw;
}
contextual = contextual.withProperties(newProps, newFiltered);
}

if (oiw != null) {
JsonSerializer<?> ser = provider.findValueSerializer(oiw.idType, property);
oiw = oiw.withSerializer(ser);
Expand All @@ -550,6 +573,7 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
if (newFilterId != null) {
contextual = contextual.withFilterId(newFilterId);
}

if (shape == null) {
shape = _serializationShape;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
package com.fasterxml.jackson.failing;
package com.fasterxml.jackson.databind.objectid;

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

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import com.fasterxml.jackson.databind.*;

public class JsonIdentityInfo2759Test extends BaseMapTest
public class ObjectId2759Test extends BaseMapTest
{
static class Hive {
public String name;
public List<Bee> bees = new ArrayList<>();

public Long id;

Hive() { }

public Hive(Long id, String name) {
this.id = id;
this.name = name;
}

public void addBee(Bee bee) {
bees.add(bee);
}
}

static class Bee {
public Long id;

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
/// @JsonIdentityReference(alwaysAsId = true)
// @JsonProperty("hiveId")
@JsonIdentityReference(alwaysAsId = true)
@JsonProperty("hiveId")
Hive hive;

public Bee() { }
Expand All @@ -34,24 +54,6 @@ public void setHive(Hive hive) {
}
}

static class Hive {
public String name;
public List<Bee> bees = new ArrayList<>();

public Long id;

Hive() { }

public Hive(Long id, String name) {
this.id = id;
this.name = name;
}

public void addBee(Bee bee) {
bees.add(bee);
}
}

public void testObjectId2759() throws Exception
{
Hive hive = new Hive(100500L, "main hive");
Expand All @@ -60,7 +62,6 @@ public void testObjectId2759() throws Exception
ObjectMapper mapper = newJsonMapper();
final String json = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(hive);

try {
mapper.readerFor(JsonNode.class)
.with(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)
Expand Down

0 comments on commit 87089ae

Please sign in to comment.