@@ -36,7 +36,8 @@ public class JacksonAnnotationIntrospector
3636 @ SuppressWarnings ("unchecked" )
3737 private final static Class <? extends Annotation >[] ANNOTATIONS_TO_INFER_SER = (Class <? extends Annotation >[])
3838 new Class <?>[] {
39- JsonSerialize .class ,
39+ JsonSerialize .class , // databind-specific
40+ JsonSerializeAs .class , // since 2.21 alias (and eventual replacement) for `@JsonSerialize.as`
4041 JsonView .class ,
4142 JsonFormat .class ,
4243 JsonTypeInfo .class ,
@@ -49,14 +50,15 @@ public class JacksonAnnotationIntrospector
4950 @ SuppressWarnings ("unchecked" )
5051 private final static Class <? extends Annotation >[] ANNOTATIONS_TO_INFER_DESER = (Class <? extends Annotation >[])
5152 new Class <?>[] {
52- JsonDeserialize .class ,
53+ JsonDeserialize .class , // databind-specific
54+ JsonDeserializeAs .class , // since 2.21 alias (and eventual replacement) for `@JsonDeserialize.as`
5355 JsonView .class ,
5456 JsonFormat .class ,
5557 JsonTypeInfo .class ,
5658 JsonUnwrapped .class ,
5759 JsonBackReference .class ,
5860 JsonManagedReference .class ,
59- JsonMerge .class // since 2.9
61+ JsonMerge .class
6062 };
6163
6264 // NOTE: To avoid mandatory Module dependency to "java.beans", support for 2
@@ -885,10 +887,15 @@ public JavaType refineSerializationType(final MapperConfig<?> config,
885887 final TypeFactory tf = config .getTypeFactory ();
886888
887889 final JsonSerialize jsonSer = _findAnnotation (a , JsonSerialize .class );
890+ final JsonSerializeAs jsonSerAs = _findAnnotation (a , JsonSerializeAs .class );
888891
889892 // Ok: start by refining the main type itself; common to all types
890893
891- final Class <?> serClass = (jsonSer == null ) ? null : _classIfExplicit (jsonSer .as ());
894+ Class <?> serClass = (jsonSer == null ) ? null : _classIfExplicit (jsonSer .as ());
895+ // 09-Dec-2025, tatu: [databind#5476] Also check @JsonSerializeAs
896+ if (serClass == null && jsonSerAs != null ) {
897+ serClass = _classIfExplicit (jsonSerAs .value ());
898+ }
892899 if (serClass != null ) {
893900 if (type .hasRawClass (serClass )) {
894901 // 30-Nov-2015, tatu: As per [databind#1023], need to allow forcing of
@@ -923,7 +930,11 @@ public JavaType refineSerializationType(final MapperConfig<?> config,
923930 // First, key type (for Maps, Map-like types):
924931 if (type .isMapLikeType ()) {
925932 JavaType keyType = type .getKeyType ();
926- final Class <?> keyClass = (jsonSer == null ) ? null : _classIfExplicit (jsonSer .keyAs ());
933+ Class <?> keyClass = (jsonSer == null ) ? null : _classIfExplicit (jsonSer .keyAs ());
934+ // 09-Dec-2025, tatu: [databind#5476] Also check @JsonSerializeAs
935+ if (keyClass == null && jsonSerAs != null ) {
936+ keyClass = _classIfExplicit (jsonSerAs .key ());
937+ }
927938 if (keyClass != null ) {
928939 if (keyType .hasRawClass (keyClass )) {
929940 keyType = keyType .withStaticTyping ();
@@ -958,7 +969,11 @@ public JavaType refineSerializationType(final MapperConfig<?> config,
958969 JavaType contentType = type .getContentType ();
959970 if (contentType != null ) { // collection[like], map[like], array, reference
960971 // And then value types for all containers:
961- final Class <?> contentClass = (jsonSer == null ) ? null : _classIfExplicit (jsonSer .contentAs ());
972+ Class <?> contentClass = (jsonSer == null ) ? null : _classIfExplicit (jsonSer .contentAs ());
973+ // 09-Dec-2025, tatu: [databind#5476] Also check @JsonSerializeAs
974+ if (contentClass == null && jsonSerAs != null ) {
975+ contentClass = _classIfExplicit (jsonSerAs .content ());
976+ }
962977 if (contentClass != null ) {
963978 if (contentType .hasRawClass (contentClass )) {
964979 contentType = contentType .withStaticTyping ();
@@ -1245,9 +1260,14 @@ public JavaType refineDeserializationType(final MapperConfig<?> config,
12451260 final TypeFactory tf = config .getTypeFactory ();
12461261
12471262 final JsonDeserialize jsonDeser = _findAnnotation (a , JsonDeserialize .class );
1263+ final JsonDeserializeAs jsonDeserAs = _findAnnotation (a , JsonDeserializeAs .class );
12481264
12491265 // Ok: start by refining the main type itself; common to all types
1250- final Class <?> valueClass = (jsonDeser == null ) ? null : _classIfExplicit (jsonDeser .as ());
1266+ Class <?> valueClass = (jsonDeser == null ) ? null : _classIfExplicit (jsonDeser .as ());
1267+ // 09-Dec-2025, tatu: [databind#5475] Also check @JsonDeserializeAs
1268+ if (valueClass == null && jsonDeserAs != null ) {
1269+ valueClass = _classIfExplicit (jsonDeserAs .value ());
1270+ }
12511271 if ((valueClass != null ) && !type .hasRawClass (valueClass )
12521272 && !_primitiveAndWrapper (type , valueClass )) {
12531273 try {
@@ -1263,7 +1283,11 @@ public JavaType refineDeserializationType(final MapperConfig<?> config,
12631283 // First, key type (for Maps, Map-like types):
12641284 if (type .isMapLikeType ()) {
12651285 JavaType keyType = type .getKeyType ();
1266- final Class <?> keyClass = (jsonDeser == null ) ? null : _classIfExplicit (jsonDeser .keyAs ());
1286+ Class <?> keyClass = (jsonDeser == null ) ? null : _classIfExplicit (jsonDeser .keyAs ());
1287+ // 09-Dec-2025, tatu: [databind#5475] Also check @JsonDeserializeAs
1288+ if (keyClass == null && jsonDeserAs != null ) {
1289+ keyClass = _classIfExplicit (jsonDeserAs .keys ());
1290+ }
12671291 if ((keyClass != null )
12681292 && !_primitiveAndWrapper (keyType , keyClass )) {
12691293 try {
@@ -1279,7 +1303,11 @@ public JavaType refineDeserializationType(final MapperConfig<?> config,
12791303 JavaType contentType = type .getContentType ();
12801304 if (contentType != null ) { // collection[like], map[like], array, reference
12811305 // And then value types for all containers:
1282- final Class <?> contentClass = (jsonDeser == null ) ? null : _classIfExplicit (jsonDeser .contentAs ());
1306+ Class <?> contentClass = (jsonDeser == null ) ? null : _classIfExplicit (jsonDeser .contentAs ());
1307+ // 09-Dec-2025, tatu: [databind#5475] Also check @JsonDeserializeAs
1308+ if (contentClass == null && jsonDeserAs != null ) {
1309+ contentClass = _classIfExplicit (jsonDeserAs .content ());
1310+ }
12831311 if ((contentClass != null )
12841312 && !_primitiveAndWrapper (contentType , contentClass )) {
12851313 try {
0 commit comments