Skip to content

Commit c239616

Browse files
authored
Merge branch '3.x' into 5342-fix-prevent-name-conflict-JsonAnyGetter
2 parents 5d67470 + 80c5764 commit c239616

File tree

12 files changed

+653
-154
lines changed

12 files changed

+653
-154
lines changed

release-notes/VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Versions: 3.x (for earlier see VERSION-2.x)
1414
#1654: @JsonDeserialize(contentUsing=...) is ignored if content
1515
type is determined by @JsonTypeInfo
1616
(reported by @pdegoeje)
17+
(fix by @cowtowncoder, @JacksonJang)
1718
#1980: Add method `remove(JsonPointer)` in `ContainerNode`
1819
(fix by @cowtowncoder, w/ Claude code)
1920
#3964: Deserialization issue: MismatchedInputException, Bean not

src/main/java/tools/jackson/databind/ValueSerializer.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Set;
55

66
import com.fasterxml.jackson.annotation.JsonFormat;
7+
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
78

89
import tools.jackson.core.*;
910
import tools.jackson.databind.jsonFormatVisitors.JsonFormatVisitable;
@@ -252,13 +253,20 @@ public void serializeWithType(T value, JsonGenerator gen, SerializationContext c
252253
TypeSerializer typeSer)
253254
throws JacksonException
254255
{
256+
// 07-Dec-2025, tatu: [databind#1654] Check for "no-op" type serializer
257+
// indirectly
258+
if (typeSer.getTypeInclusion() == As.NOTHING) {
259+
serialize(value, gen, ctxt);
260+
return;
261+
}
262+
255263
Class<?> clz = handledType();
256264
if (clz == null) {
257265
clz = value.getClass();
258266
}
259267
ctxt.reportBadDefinition(clz, String.format(
260-
"Type id handling not implemented for type %s (by serializer of type %s)",
261-
clz.getName(), getClass().getName()));
268+
"Type id handling (method `serializeWithType()`) not implemented for type %s (by serializer of type %s)",
269+
ClassUtil.nameOf(clz), ClassUtil.nameOf(getClass())));
262270
}
263271

264272
/*

src/main/java/tools/jackson/databind/deser/BasicDeserializerFactory.java

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import tools.jackson.databind.ext.jdk8.OptionalLongDeserializer;
2525
import tools.jackson.databind.introspect.*;
2626
import tools.jackson.databind.jsontype.TypeDeserializer;
27+
import tools.jackson.databind.jsontype.impl.NoOpTypeDeserializer;
2728
import tools.jackson.databind.type.*;
2829
import tools.jackson.databind.util.*;
2930

@@ -714,17 +715,14 @@ public ValueDeserializer<?> createArrayDeserializer(DeserializationContext ctxt,
714715
ArrayType type, BeanDescription.Supplier beanDescRef)
715716
{
716717
final DeserializationConfig config = ctxt.getConfig();
717-
JavaType elemType = type.getContentType();
718+
final JavaType elemType = type.getContentType();
718719

719720
// Very first thing: is deserializer hard-coded for elements?
720721
@SuppressWarnings("unchecked")
721-
ValueDeserializer<Object> contentDeser = (ValueDeserializer<Object>) elemType.getValueHandler();
722+
final ValueDeserializer<Object> contentDeser = (ValueDeserializer<Object>) elemType.getValueHandler();
722723
// Then optional type info: if type has been resolved, we may already know type deserializer:
723-
TypeDeserializer elemTypeDeser = (TypeDeserializer) elemType.getTypeHandler();
724-
// but if not, may still be possible to find:
725-
if (elemTypeDeser == null) {
726-
elemTypeDeser = ctxt.findTypeDeserializer(elemType);
727-
}
724+
final TypeDeserializer elemTypeDeser = _findContentTypeDeserializer(ctxt, elemType);
725+
728726
// 23-Nov-2010, tatu: Custom array deserializer?
729727
ValueDeserializer<?> deser = _findCustomArrayDeserializer(type,
730728
config, beanDescRef, elemTypeDeser, contentDeser);
@@ -760,17 +758,11 @@ public ValueDeserializer<?> createArrayDeserializer(DeserializationContext ctxt,
760758
public ValueDeserializer<?> createCollectionDeserializer(DeserializationContext ctxt,
761759
CollectionType type, BeanDescription.Supplier beanDescRef)
762760
{
763-
JavaType contentType = type.getContentType();
764-
// Very first thing: is deserializer hard-coded for elements?
765-
ValueDeserializer<Object> contentDeser = (ValueDeserializer<Object>) contentType.getValueHandler();
761+
final JavaType contentType = type.getContentType();
762+
final ValueDeserializer<Object> contentDeser = (ValueDeserializer<Object>) contentType.getValueHandler();
763+
final TypeDeserializer contentTypeDeser = _findContentTypeDeserializer(ctxt, contentType);
766764
final DeserializationConfig config = ctxt.getConfig();
767765

768-
// Then optional type info: if type has been resolved, we may already know type deserializer:
769-
TypeDeserializer contentTypeDeser = (TypeDeserializer) contentType.getTypeHandler();
770-
// but if not, may still be possible to find:
771-
if (contentTypeDeser == null) {
772-
contentTypeDeser = ctxt.findTypeDeserializer(contentType);
773-
}
774766
// 23-Nov-2010, tatu: Custom deserializer?
775767
ValueDeserializer<?> deser = _findCustomCollectionDeserializer(type,
776768
config, beanDescRef, contentTypeDeser, contentDeser);
@@ -853,18 +845,13 @@ protected CollectionType _mapAbstractCollectionType(JavaType type, Deserializati
853845
public ValueDeserializer<?> createCollectionLikeDeserializer(DeserializationContext ctxt,
854846
CollectionLikeType type, BeanDescription.Supplier beanDescRef)
855847
{
856-
JavaType contentType = type.getContentType();
848+
final JavaType contentType = type.getContentType();
857849
// Very first thing: is deserializer hard-coded for elements?
858850
@SuppressWarnings("unchecked")
859851
ValueDeserializer<Object> contentDeser = (ValueDeserializer<Object>) contentType.getValueHandler();
860852
final DeserializationConfig config = ctxt.getConfig();
853+
final TypeDeserializer contentTypeDeser = _findContentTypeDeserializer(ctxt, contentType);
861854

862-
// Then optional type info: if type has been resolved, we may already know type deserializer:
863-
TypeDeserializer contentTypeDeser = (TypeDeserializer)contentType.getTypeHandler();
864-
// but if not, may still be possible to find:
865-
if (contentTypeDeser == null) {
866-
contentTypeDeser = ctxt.findTypeDeserializer(contentType);
867-
}
868855
ValueDeserializer<?> deser = _findCustomCollectionLikeDeserializer(type, config, beanDescRef,
869856
contentTypeDeser, contentDeser);
870857
if (deser != null) {
@@ -889,8 +876,8 @@ public ValueDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
889876
MapType type, BeanDescription.Supplier beanDescRef)
890877
{
891878
final DeserializationConfig config = ctxt.getConfig();
892-
JavaType keyType = type.getKeyType();
893-
JavaType contentType = type.getContentType();
879+
final JavaType keyType = type.getKeyType();
880+
final JavaType contentType = type.getContentType();
894881

895882
// First: is there annotation-specified deserializer for values?
896883
@SuppressWarnings("unchecked")
@@ -899,11 +886,7 @@ public ValueDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
899886
// Ok: need a key deserializer (null indicates 'default' here)
900887
KeyDeserializer keyDes = (KeyDeserializer) keyType.getValueHandler();
901888
// Then optional type info; either attached to type, or resolved separately:
902-
TypeDeserializer contentTypeDeser = (TypeDeserializer) contentType.getTypeHandler();
903-
// but if not, may still be possible to find:
904-
if (contentTypeDeser == null) {
905-
contentTypeDeser = ctxt.findTypeDeserializer(contentType);
906-
}
889+
final TypeDeserializer contentTypeDeser = _findContentTypeDeserializer(ctxt, contentType);
907890

908891
// 23-Nov-2010, tatu: Custom deserializer?
909892
ValueDeserializer<?> deser = _findCustomMapDeserializer(type, config, beanDescRef,
@@ -1007,8 +990,8 @@ protected MapType _mapAbstractMapType(JavaType type, DeserializationConfig confi
1007990
public ValueDeserializer<?> createMapLikeDeserializer(DeserializationContext ctxt,
1008991
MapLikeType type, BeanDescription.Supplier beanDescRef)
1009992
{
1010-
JavaType keyType = type.getKeyType();
1011-
JavaType contentType = type.getContentType();
993+
final JavaType keyType = type.getKeyType();
994+
final JavaType contentType = type.getContentType();
1012995
final DeserializationConfig config = ctxt.getConfig();
1013996

1014997
// First: is there annotation-specified deserializer for values?
@@ -1023,11 +1006,7 @@ public ValueDeserializer<?> createMapLikeDeserializer(DeserializationContext ctx
10231006
}
10241007
*/
10251008
// Then optional type info; either attached to type, or resolve separately:
1026-
TypeDeserializer contentTypeDeser = (TypeDeserializer) contentType.getTypeHandler();
1027-
// but if not, may still be possible to find:
1028-
if (contentTypeDeser == null) {
1029-
contentTypeDeser = ctxt.findTypeDeserializer(contentType);
1030-
}
1009+
final TypeDeserializer contentTypeDeser = _findContentTypeDeserializer(ctxt, contentType);
10311010
ValueDeserializer<?> deser = _findCustomMapLikeDeserializer(type, config,
10321011
beanDescRef, keyDes, contentTypeDeser, contentDeser);
10331012
if (deser != null) {
@@ -1139,11 +1118,7 @@ public ValueDeserializer<?> createReferenceDeserializer(DeserializationContext c
11391118
@SuppressWarnings("unchecked")
11401119
ValueDeserializer<Object> contentDeser = (ValueDeserializer<Object>) contentType.getValueHandler();
11411120
final DeserializationConfig config = ctxt.getConfig();
1142-
// Then optional type info: if type has been resolved, we may already know type deserializer:
1143-
TypeDeserializer contentTypeDeser = (TypeDeserializer) contentType.getTypeHandler();
1144-
if (contentTypeDeser == null) { // or if not, may be able to find:
1145-
contentTypeDeser = ctxt.findTypeDeserializer(contentType);
1146-
}
1121+
final TypeDeserializer contentTypeDeser = _findContentTypeDeserializer(ctxt, contentType);
11471122
ValueDeserializer<?> deser = _findCustomReferenceDeserializer(type, config, beanDescRef,
11481123
contentTypeDeser, contentDeser);
11491124

@@ -1738,6 +1713,24 @@ protected boolean _hasCreatorAnnotation(MapperConfig<?> config,
17381713
return false;
17391714
}
17401715

1716+
// @since 3.1
1717+
protected TypeDeserializer _findContentTypeDeserializer(DeserializationContext ctxt,
1718+
JavaType contentType)
1719+
{
1720+
// Then optional type info: if type has been resolved, we may already know type deserializer:
1721+
TypeDeserializer contentTypeDeser = (TypeDeserializer) contentType.getTypeHandler();
1722+
// [databind#1654]: @JsonTypeInfo(use = Id.NONE) should not apply type deserializer
1723+
// when custom content deserializer is specified via @JsonDeserialize(contentUsing = ...)
1724+
if (contentTypeDeser instanceof NoOpTypeDeserializer) {
1725+
return null;
1726+
}
1727+
if (contentTypeDeser == null) {
1728+
// but if not, may still be possible to find:
1729+
contentTypeDeser = ctxt.findTypeDeserializer(contentType);
1730+
}
1731+
return contentTypeDeser;
1732+
}
1733+
17411734
/*
17421735
/**********************************************************************
17431736
/* Helper classes

src/main/java/tools/jackson/databind/jsontype/TypeResolverProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ public TypeSerializer findPropertyTypeSerializer(SerializationContext ctxt,
119119
if (b == NO_RESOLVER) {
120120
// 07-Dec-2025, tatu: Should we actually do this? (No test coverage yet)
121121
//return NoOpTypeSerializer.instance();
122+
122123
return null;
123124
}
124125
Collection<NamedType> subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByClass(

src/main/java/tools/jackson/databind/jsontype/TypeSerializer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ public WritableTypeId typeId(Object value, JsonToken valueShape) {
9292
case WRAPPER_OBJECT:
9393
typeIdDef.include = WritableTypeId.Inclusion.WRAPPER_OBJECT;
9494
break;
95+
case NOTHING:
96+
// 07-Dec-2025, tatu: No suitable constant to use. Should add "NOTHING"?
97+
typeIdDef.include = null;
98+
break;
9599
default:
96100
VersionUtil.throwInternal();
97101
}

src/main/java/tools/jackson/databind/jsontype/impl/NoOpTypeDeserializer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ public TypeDeserializer forProperty(BeanProperty prop) {
4848

4949
@Override
5050
public JsonTypeInfo.As getTypeInclusion() {
51-
// No proper value but need to return something
52-
return JsonTypeInfo.As.EXISTING_PROPERTY;
51+
return JsonTypeInfo.As.NOTHING;
5352
}
5453

5554
@Override

src/main/java/tools/jackson/databind/jsontype/impl/NoOpTypeSerializer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ public TypeSerializer forProperty(SerializationContext ctxt, BeanProperty prop)
3838

3939
@Override
4040
public JsonTypeInfo.As getTypeInclusion() {
41-
// No proper one to use but must return something:
42-
return JsonTypeInfo.As.EXISTING_PROPERTY;
41+
return JsonTypeInfo.As.NOTHING;
4342
}
4443

4544
@Override

0 commit comments

Comments
 (0)