Skip to content

Commit

Permalink
StdDelegatingSerializer does not consider a Converter that may return…
Browse files Browse the repository at this point in the history
… null for a non-null input (#4576)
  • Loading branch information
plevart authored and cowtowncoder committed Jun 13, 2024
1 parent a01d01f commit 577fe9c
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 9 deletions.
5 changes: 5 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -1774,3 +1774,8 @@ Oddbjørn Kvalsund (oddbjornkvalsund@github)
* Reported, contributed fix for #4430: Use `ReentrantLock` instead of `synchronized`
in `DeserializerCache` to avoid deadlock on pinning
(2.17.1)

Peter Levart (plevart@github)
* Reported, contributed fix for #4575: StdDelegatingSerializer does not consider
a Converter that may return null for a non-null input
(2.17.2)
3 changes: 3 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ Project: jackson-databind

#4561: Issues using jackson-databind 2.17.1 with Reactor
(reported by @wdallastella)
#4575: StdDelegatingSerializer does not consider a Converter that may
return null for a non-null input
(reported, fix contributed by Peter L)

2.17.1 (04-May-2024)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ public void serializeWithType(Object value, JsonGenerator gen, SerializerProvide
// 03-Oct-2012, tatu: This is actually unlikely to work ok... but for now,
// let's give it a chance?
Object delegateValue = convertValue(value);
// consider null (to be consistent with serialize method above)
if (delegateValue == null) {
provider.defaultSerializeNull(gen);
return;
}
JsonSerializer<Object> ser = _delegateSerializer;
if (ser == null) {
ser = _findSerializer(value, provider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@

import org.w3c.dom.Element;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.*;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.CharacterEscapes;
Expand All @@ -23,6 +21,8 @@
import com.fasterxml.jackson.databind.ser.std.CollectionSerializer;
import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer;
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.Converter;
import com.fasterxml.jackson.databind.util.StdConverter;

/**
Expand Down Expand Up @@ -187,6 +187,55 @@ public String getId() {
}
}

// [databind#4575]
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type")
@JsonSubTypes(
{
@JsonSubTypes.Type(Sub4575.class)
}
)
@JsonTypeName("Super")
static class Super4575 {
public static final Super4575 NULL = new Super4575();
}

@JsonTypeName("Sub")
static class Sub4575 extends Super4575 { }

static class NullSerializer4575 extends StdDelegatingSerializer {
public NullSerializer4575(Converter<Object, ?> converter, JavaType delegateType, JsonSerializer<?> delegateSerializer) {
super(converter, delegateType, delegateSerializer);
}

public NullSerializer4575(TypeFactory typeFactory, JsonSerializer<?> delegateSerializer) {
this(
new Converter<Object, Object>() {
@Override
public Object convert(Object value) {
return value == Super4575.NULL ? null : value;
}

@Override
public JavaType getInputType(TypeFactory typeFactory) {
return typeFactory.constructType(delegateSerializer.handledType());
}

@Override
public JavaType getOutputType(TypeFactory typeFactory) {
return typeFactory.constructType(delegateSerializer.handledType());
}
},
typeFactory.constructType(delegateSerializer.handledType() == null ? Object.class : delegateSerializer.handledType()),
delegateSerializer
);
}

@Override
protected StdDelegatingSerializer withDelegate(Converter<Object, ?> converter, JavaType delegateType, JsonSerializer<?> delegateSerializer) {
return new NullSerializer4575(converter, delegateType, delegateSerializer);
}
}

/*
/**********************************************************
/* Unit tests
Expand All @@ -208,7 +257,6 @@ public void testCustomization() throws Exception
@SuppressWarnings({ "unchecked", "rawtypes" })
public void testCustomLists() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("test", Version.unknownVersion());
JsonSerializer<?> ser = new CollectionSerializer(null, false, null, null);
final JsonSerializer<Object> collectionSerializer = (JsonSerializer<Object>) ser;
Expand All @@ -225,14 +273,15 @@ public void serialize(Collection value, JsonGenerator gen, SerializerProvider pr
}
}
});
mapper.registerModule(module);
ObjectMapper mapper = jsonMapperBuilder()
.addModule(module)
.build();
assertEquals("null", mapper.writeValueAsString(new ArrayList<Object>()));
}

// [databind#87]: delegating serializer
public void testDelegating() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("test", Version.unknownVersion());
module.addSerializer(new StdDelegatingSerializer(Immutable.class,
new StdConverter<Immutable, Map<String,Integer>>() {
Expand All @@ -245,7 +294,9 @@ public Map<String, Integer> convert(Immutable value)
return map;
}
}));
mapper.registerModule(module);
ObjectMapper mapper = jsonMapperBuilder()
.addModule(module)
.build();
assertEquals("{\"x\":3,\"y\":7}", mapper.writeValueAsString(new Immutable()));
}

Expand Down Expand Up @@ -279,8 +330,9 @@ public void testWithCustomElements() throws Exception

SimpleModule module = new SimpleModule("test", Version.unknownVersion());
module.addSerializer(String.class, new UCStringSerializer());
ObjectMapper mapper = new ObjectMapper()
.registerModule(module);
ObjectMapper mapper = jsonMapperBuilder()
.addModule(module)
.build();

assertEquals(q("FOOBAR"), mapper.writeValueAsString("foobar"));
assertEquals(a2q("['FOO',null]"),
Expand All @@ -306,4 +358,28 @@ public void testIssue2475() throws Exception {
assertEquals(a2q("{'id':'ID-2','set':[]}"),
writer.writeValueAsString(new Item2475(new HashSet<String>(), "ID-2")));
}

// [databind#4575]
public void testIssue4575() throws Exception {
com.fasterxml.jackson.databind.Module module = new SimpleModule() {
{
setSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(
SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer
) {
return new NullSerializer4575(config.getTypeFactory(), serializer);
}
});
}
};

ObjectMapper mapper = jsonMapperBuilder()
.addModule(module)
.build();

assertEquals("{\"@type\":\"Super\"}", mapper.writeValueAsString(new Super4575()));
assertEquals("{\"@type\":\"Sub\"}", mapper.writeValueAsString(new Sub4575()));
assertEquals("null", mapper.writeValueAsString(Super4575.NULL));
}
}

0 comments on commit 577fe9c

Please sign in to comment.