diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 717f334828..6c8dd83fa3 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -30,6 +30,8 @@ Project: jackson-databind #3117: Use more limiting default visibility settings for JDK types (java.*, javax.*) #3122: Deep merge for `JsonNode` using `ObjectReader.readTree()` (reported by Eric S) +#3130: Serializing java.lang.Thread fails on JDK 11 and above (should suppress + serialization of ClassLoader) - Fix to avoid problem with `BigDecimalNode`, scale of `Integer.MIN_VALUE` (see [dataformats-binary#264] for details) diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java index 6ecc8ad876..a3e06198c1 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java @@ -475,6 +475,10 @@ protected final JsonSerializer findSerializerByPrimaryType(SerializerProvider } return NumberSerializer.instance; } + // 23-Apr-2021, tatu: [databind#3130]: Suppress ClassLoader... + if (ClassLoader.class.isAssignableFrom(raw)) { + return new ToEmptyObjectSerializer(type); + } return null; } diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnknownSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnknownSerializer.java index 738c55dd2e..f9233bac63 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnknownSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnknownSerializer.java @@ -4,49 +4,43 @@ import java.lang.reflect.Type; import com.fasterxml.jackson.core.*; -import com.fasterxml.jackson.core.type.WritableTypeId; + import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.fasterxml.jackson.databind.ser.std.ToEmptyObjectSerializer; @SuppressWarnings("serial") public class UnknownSerializer - extends StdSerializer + extends ToEmptyObjectSerializer // since 2.13 { public UnknownSerializer() { super(Object.class); } - /** - * @since 2.6 - */ + // @since 2.6 public UnknownSerializer(Class cls) { - super(cls, false); + super(cls); } - + @Override - public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException + public void serialize(Object value, JsonGenerator gen, SerializerProvider ctxt) throws IOException { // 27-Nov-2009, tatu: As per [JACKSON-201] may or may not fail... - if (provider.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)) { - failForEmpty(provider, value); + if (ctxt.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)) { + failForEmpty(ctxt, value); } - // But if it's fine, we'll just output empty JSON Object: - gen.writeStartObject(value, 0); - gen.writeEndObject(); + super.serialize(value, gen, ctxt); } @Override - public final void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider, + public void serializeWithType(Object value, JsonGenerator gen, SerializerProvider ctxt, TypeSerializer typeSer) throws IOException { - if (provider.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)) { - failForEmpty(provider, value); + if (ctxt.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)) { + failForEmpty(ctxt, value); } - WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen, - typeSer.typeId(value, JsonToken.START_OBJECT)); - typeSer.writeTypeSuffix(gen, typeIdDef); + super.serializeWithType(value, gen, ctxt, typeSer); } @Override diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/ToEmptyObjectSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/ToEmptyObjectSerializer.java new file mode 100644 index 0000000000..ef4dbba9c1 --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/ToEmptyObjectSerializer.java @@ -0,0 +1,73 @@ +package com.fasterxml.jackson.databind.ser.std; + +import java.io.IOException; +import java.lang.reflect.Type; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.type.WritableTypeId; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; +import com.fasterxml.jackson.databind.jsontype.TypeSerializer; + +/** + * Simple "bogus" serializer that will just serialize an empty + * Object for any given value. + * Quite similar to {@code UnknownSerializer} with the exception that + * serialization never fails. + * + * @since 2.13 + */ +@JacksonStdImpl +@SuppressWarnings("serial") +public class ToEmptyObjectSerializer + extends StdSerializer +{ + protected ToEmptyObjectSerializer(Class raw) { + super(raw, false); + } + + public ToEmptyObjectSerializer(JavaType type) { + super(type); + } + + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider ctxt) throws IOException + { + gen.writeStartObject(value, 0); + gen.writeEndObject(); + } + + @Override + public void serializeWithType(Object value, JsonGenerator gen, + SerializerProvider ctxt, TypeSerializer typeSer) throws IOException + { + WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen, + typeSer.typeId(value, JsonToken.START_OBJECT)); + typeSer.writeTypeSuffix(gen, typeIdDef); + } + + @Override + public boolean isEmpty(SerializerProvider provider, Object value) { + return true; + } + + @Override + public JsonNode getSchema(SerializerProvider provider, Type typeHint) + throws JsonMappingException { + return null; + } + + @Override + public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, + JavaType typeHint) + throws JsonMappingException + { + /*JsonObjectFormatVisitor v =*/ visitor.expectObjectFormat(typeHint); + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/JDKTypeSerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/JDKTypeSerializationTest.java index cbfdc43a82..6e6f4f507a 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/JDKTypeSerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/JDKTypeSerializationTest.java @@ -199,4 +199,19 @@ public void testNonStandardProperties() throws Exception String json = MAPPER.writeValueAsString(properties); assertEquals("{\"key\":1}", json); } + + // [databind#3130]: fails on JDK 11+ + public void testThreadSerialization() throws Exception + { + final Thread input = Thread.currentThread(); +// String json = MAPPER.writerWithDefaultPrettyPrinter() +// .writeValueAsString(input); + Map asMap = MAPPER.convertValue(input, Map.class); +// System.err.println("PROPS -> "+asMap.keySet()); + + // Should get empty "contextClassLoader" + Map cl = (Map) asMap.get("contextClassLoader"); + assertNotNull(cl); + assertEquals(0, cl.size()); + } }