Skip to content

Commit a92e2be

Browse files
committed
Fix #848
1 parent 80c1bbb commit a92e2be

File tree

4 files changed

+182
-119
lines changed

4 files changed

+182
-119
lines changed

release-notes/VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Project: jackson-databind
7676
#828: Respect DeserializationFeatures.WRAP_EXCEPTIONS in CollectionDeserializer
7777
(contributed by Steve G, thezerobit@github)
7878
#840: Change semantics of `@JsonPropertyOrder(alphabetic)` to only count `true` value
79+
#848: Custom serializer not used if POJO has `@JsonValue`
7980
- Remove old cglib compatibility tests; cause problems in Eclipse
8081

8182
2.5.4 (09-Jun-2015)

src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java

+128-97
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ protected JsonSerializer<?> buildContainerSerializer(SerializerProvider prov,
547547
{
548548
final SerializationConfig config = prov.getConfig();
549549

550-
/* [Issue#23], 15-Mar-2013, tatu: must force static handling of root value type,
550+
/* [databind#23], 15-Mar-2013, tatu: must force static handling of root value type,
551551
* with just one important exception: if value type is "untyped", let's
552552
* leave it as is; no clean way to make it work.
553553
*/
@@ -568,62 +568,70 @@ protected JsonSerializer<?> buildContainerSerializer(SerializerProvider prov,
568568
}
569569
JsonSerializer<Object> elementValueSerializer = _findContentSerializer(prov,
570570
beanDesc.getClassInfo());
571-
572571
if (type.isMapLikeType()) { // implements java.util.Map
573572
MapLikeType mlt = (MapLikeType) type;
574573
/* 29-Sep-2012, tatu: This is actually too early to (try to) find
575574
* key serializer from property annotations, and can lead to caching
576-
* issues (see [Issue#75]). Instead, must be done from 'createContextual()' call.
575+
* issues (see [databind#75]). Instead, must be done from 'createContextual()' call.
577576
* But we do need to check class annotations.
578577
*/
579578
JsonSerializer<Object> keySerializer = _findKeySerializer(prov, beanDesc.getClassInfo());
580579
if (mlt.isTrueMapType()) {
581-
return buildMapSerializer(config, (MapType) mlt, beanDesc, staticTyping,
580+
return buildMapSerializer(prov, (MapType) mlt, beanDesc, staticTyping,
582581
keySerializer, elementTypeSerializer, elementValueSerializer);
583582
}
584-
// Only custom serializers may be available:
585-
for (Serializers serializers : customSerializers()) {
586-
MapLikeType mlType = (MapLikeType) type;
587-
JsonSerializer<?> ser = serializers.findMapLikeSerializer(config,
583+
// With Map-like, just 2 options: (1) Custom, (2) Annotations
584+
JsonSerializer<?> ser = null;
585+
MapLikeType mlType = (MapLikeType) type;
586+
for (Serializers serializers : customSerializers()) { // (1) Custom
587+
ser = serializers.findMapLikeSerializer(config,
588588
mlType, beanDesc, keySerializer, elementTypeSerializer, elementValueSerializer);
589589
if (ser != null) {
590-
// [Issue#120]: Allow post-processing
591-
if (_factoryConfig.hasSerializerModifiers()) {
592-
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
593-
ser = mod.modifyMapLikeSerializer(config, mlType, beanDesc, ser);
594-
}
590+
break;
591+
}
592+
}
593+
if (ser == null) { // (2) Annotations-based ones:
594+
ser = findSerializerByAnnotations(prov, type, beanDesc);
595+
}
596+
if (ser != null) {
597+
if (_factoryConfig.hasSerializerModifiers()) {
598+
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
599+
ser = mod.modifyMapLikeSerializer(config, mlType, beanDesc, ser);
595600
}
596-
return ser;
597601
}
598602
}
599-
return null;
603+
return ser;
600604
}
601605
if (type.isCollectionLikeType()) {
602606
CollectionLikeType clt = (CollectionLikeType) type;
603607
if (clt.isTrueCollectionType()) {
604-
return buildCollectionSerializer(config, (CollectionType) clt, beanDesc, staticTyping,
608+
return buildCollectionSerializer(prov, (CollectionType) clt, beanDesc, staticTyping,
605609
elementTypeSerializer, elementValueSerializer);
606610
}
611+
// With Map-like, just 2 options: (1) Custom, (2) Annotations
612+
JsonSerializer<?> ser = null;
607613
CollectionLikeType clType = (CollectionLikeType) type;
608-
// Only custom variants for this:
609-
for (Serializers serializers : customSerializers()) {
610-
JsonSerializer<?> ser = serializers.findCollectionLikeSerializer(config,
614+
for (Serializers serializers : customSerializers()) { // (1) Custom
615+
ser = serializers.findCollectionLikeSerializer(config,
611616
clType, beanDesc, elementTypeSerializer, elementValueSerializer);
612617
if (ser != null) {
613-
// [Issue#120]: Allow post-processing
614-
if (_factoryConfig.hasSerializerModifiers()) {
615-
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
616-
ser = mod.modifyCollectionLikeSerializer(config, clType, beanDesc, ser);
617-
}
618+
break;
619+
}
620+
}
621+
if (ser == null) { // (2) Annotations-based ones:
622+
ser = findSerializerByAnnotations(prov, type, beanDesc);
623+
}
624+
if (ser != null) {
625+
if (_factoryConfig.hasSerializerModifiers()) {
626+
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
627+
ser = mod.modifyCollectionLikeSerializer(config, clType, beanDesc, ser);
618628
}
619-
return ser;
620629
}
621630
}
622-
// fall through either way (whether shape dictates serialization as POJO or not)
623-
return null;
631+
return ser;
624632
}
625633
if (type.isArrayType()) {
626-
return buildArraySerializer(config, (ArrayType) type, beanDesc, staticTyping,
634+
return buildArraySerializer(prov, (ArrayType) type, beanDesc, staticTyping,
627635
elementTypeSerializer, elementValueSerializer);
628636
}
629637
return null;
@@ -635,14 +643,18 @@ protected JsonSerializer<?> buildContainerSerializer(SerializerProvider prov,
635643
*
636644
* @since 2.1
637645
*/
638-
protected JsonSerializer<?> buildCollectionSerializer(SerializationConfig config,
646+
protected JsonSerializer<?> buildCollectionSerializer(SerializerProvider prov,
639647
CollectionType type, BeanDescription beanDesc, boolean staticTyping,
640648
TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
641649
throws JsonMappingException
642650
{
651+
SerializationConfig config = prov.getConfig();
643652
JsonSerializer<?> ser = null;
644-
// Module-provided custom collection serializers?
645-
for (Serializers serializers : customSerializers()) {
653+
// Order of lookups:
654+
// 1. Custom serializers
655+
// 2. Annotations (@JsonValue, @JsonDeserialize)
656+
// 3. Defaults
657+
for (Serializers serializers : customSerializers()) { // (1) Custom
646658
ser = serializers.findCollectionSerializer(config,
647659
type, beanDesc, elementTypeSerializer, elementValueSerializer);
648660
if (ser != null) {
@@ -651,46 +663,49 @@ protected JsonSerializer<?> buildCollectionSerializer(SerializationConfig config
651663
}
652664

653665
if (ser == null) {
654-
// We may also want to use serialize Collections "as beans", if (and only if)
655-
// this is specified with `@JsonFormat(shape=Object)`
656-
JsonFormat.Value format = beanDesc.findExpectedFormat(null);
657-
if (format != null && format.getShape() == JsonFormat.Shape.OBJECT) {
658-
return null;
659-
}
660-
Class<?> raw = type.getRawClass();
661-
if (EnumSet.class.isAssignableFrom(raw)) {
662-
// this may or may not be available (Class doesn't; type of field/method does)
663-
JavaType enumType = type.getContentType();
664-
// and even if nominally there is something, only use if it really is enum
665-
if (!enumType.isEnumType()) {
666-
enumType = null;
666+
ser = findSerializerByAnnotations(prov, type, beanDesc); // (2) Annotations
667+
if (ser == null) {
668+
// We may also want to use serialize Collections "as beans", if (and only if)
669+
// this is specified with `@JsonFormat(shape=Object)`
670+
JsonFormat.Value format = beanDesc.findExpectedFormat(null);
671+
if (format != null && format.getShape() == JsonFormat.Shape.OBJECT) {
672+
return null;
667673
}
668-
ser = buildEnumSetSerializer(enumType);
669-
} else {
670-
Class<?> elementRaw = type.getContentType().getRawClass();
671-
if (isIndexedList(raw)) {
672-
if (elementRaw == String.class) {
674+
Class<?> raw = type.getRawClass();
675+
if (EnumSet.class.isAssignableFrom(raw)) {
676+
// this may or may not be available (Class doesn't; type of field/method does)
677+
JavaType enumType = type.getContentType();
678+
// and even if nominally there is something, only use if it really is enum
679+
if (!enumType.isEnumType()) {
680+
enumType = null;
681+
}
682+
ser = buildEnumSetSerializer(enumType);
683+
} else {
684+
Class<?> elementRaw = type.getContentType().getRawClass();
685+
if (isIndexedList(raw)) {
686+
if (elementRaw == String.class) {
687+
// [JACKSON-829] Must NOT use if we have custom serializer
688+
if (elementValueSerializer == null || ClassUtil.isJacksonStdImpl(elementValueSerializer)) {
689+
ser = IndexedStringListSerializer.instance;
690+
}
691+
} else {
692+
ser = buildIndexedListSerializer(type.getContentType(), staticTyping,
693+
elementTypeSerializer, elementValueSerializer);
694+
}
695+
} else if (elementRaw == String.class) {
673696
// [JACKSON-829] Must NOT use if we have custom serializer
674697
if (elementValueSerializer == null || ClassUtil.isJacksonStdImpl(elementValueSerializer)) {
675-
ser = IndexedStringListSerializer.instance;
698+
ser = StringCollectionSerializer.instance;
676699
}
677-
} else {
678-
ser = buildIndexedListSerializer(type.getContentType(), staticTyping,
679-
elementTypeSerializer, elementValueSerializer);
680700
}
681-
} else if (elementRaw == String.class) {
682-
// [JACKSON-829] Must NOT use if we have custom serializer
683-
if (elementValueSerializer == null || ClassUtil.isJacksonStdImpl(elementValueSerializer)) {
684-
ser = StringCollectionSerializer.instance;
701+
if (ser == null) {
702+
ser = buildCollectionSerializer(type.getContentType(), staticTyping,
703+
elementTypeSerializer, elementValueSerializer);
685704
}
686705
}
687-
if (ser == null) {
688-
ser = buildCollectionSerializer(type.getContentType(), staticTyping,
689-
elementTypeSerializer, elementValueSerializer);
690-
}
691706
}
692707
}
693-
// [Issue#120]: Allow post-processing
708+
// [databind#120]: Allow post-processing
694709
if (_factoryConfig.hasSerializerModifiers()) {
695710
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
696711
ser = mod.modifyCollectionSerializer(config, type, beanDesc, ser);
@@ -733,48 +748,58 @@ public JsonSerializer<?> buildEnumSetSerializer(JavaType enumType) {
733748
* Helper method that handles configuration details when constructing serializers for
734749
* {@link java.util.Map} types.
735750
*/
736-
protected JsonSerializer<?> buildMapSerializer(SerializationConfig config,
751+
protected JsonSerializer<?> buildMapSerializer(SerializerProvider prov,
737752
MapType type, BeanDescription beanDesc,
738753
boolean staticTyping, JsonSerializer<Object> keySerializer,
739754
TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
740755
throws JsonMappingException
741756
{
757+
final SerializationConfig config = prov.getConfig();
742758
JsonSerializer<?> ser = null;
743-
for (Serializers serializers : customSerializers()) {
759+
760+
// Order of lookups:
761+
// 1. Custom serializers
762+
// 2. Annotations (@JsonValue, @JsonDeserialize)
763+
// 3. Defaults
764+
765+
for (Serializers serializers : customSerializers()) { // (1) Custom
744766
ser = serializers.findMapSerializer(config, type, beanDesc,
745767
keySerializer, elementTypeSerializer, elementValueSerializer);
746768
if (ser != null) { break; }
747769
}
748770
if (ser == null) {
749-
// 08-Nov-2014, tatu: As per [databind#601], better just use default Map serializer
750-
/*
751-
if (EnumMap.class.isAssignableFrom(type.getRawClass())
752-
&& ((keySerializer == null) || ClassUtil.isJacksonStdImpl(keySerializer))) {
753-
JavaType keyType = type.getKeyType();
754-
// Need to find key enum values...
755-
EnumValues enums = null;
756-
if (keyType.isEnumType()) { // non-enum if we got it as type erased class (from instance)
757-
@SuppressWarnings("unchecked")
758-
Class<Enum<?>> enumClass = (Class<Enum<?>>) keyType.getRawClass();
759-
enums = EnumValues.construct(config, enumClass);
771+
ser = findSerializerByAnnotations(prov, type, beanDesc); // (2) Annotations
772+
if (ser == null) {
773+
// 08-Nov-2014, tatu: As per [databind#601], better just use default Map serializer
774+
/*
775+
if (EnumMap.class.isAssignableFrom(type.getRawClass())
776+
&& ((keySerializer == null) || ClassUtil.isJacksonStdImpl(keySerializer))) {
777+
JavaType keyType = type.getKeyType();
778+
// Need to find key enum values...
779+
EnumValues enums = null;
780+
if (keyType.isEnumType()) { // non-enum if we got it as type erased class (from instance)
781+
@SuppressWarnings("unchecked")
782+
Class<Enum<?>> enumClass = (Class<Enum<?>>) keyType.getRawClass();
783+
enums = EnumValues.construct(config, enumClass);
784+
}
785+
ser = new EnumMapSerializer(type.getContentType(), staticTyping, enums,
786+
elementTypeSerializer, elementValueSerializer);
787+
} else {
788+
*/
789+
Object filterId = findFilterId(config, beanDesc);
790+
AnnotationIntrospector ai = config.getAnnotationIntrospector();
791+
MapSerializer mapSer = MapSerializer.construct(ai.findPropertiesToIgnore(beanDesc.getClassInfo(), true),
792+
type, staticTyping, elementTypeSerializer,
793+
keySerializer, elementValueSerializer, filterId);
794+
Object suppressableValue = findSuppressableContentValue(config,
795+
type.getContentType(), beanDesc);
796+
if (suppressableValue != null) {
797+
mapSer = mapSer.withContentInclusion(suppressableValue);
760798
}
761-
ser = new EnumMapSerializer(type.getContentType(), staticTyping, enums,
762-
elementTypeSerializer, elementValueSerializer);
763-
} else {
764-
*/
765-
Object filterId = findFilterId(config, beanDesc);
766-
AnnotationIntrospector ai = config.getAnnotationIntrospector();
767-
MapSerializer mapSer = MapSerializer.construct(ai.findPropertiesToIgnore(beanDesc.getClassInfo(), true),
768-
type, staticTyping, elementTypeSerializer,
769-
keySerializer, elementValueSerializer, filterId);
770-
Object suppressableValue = findSuppressableContentValue(config,
771-
type.getContentType(), beanDesc);
772-
if (suppressableValue != null) {
773-
mapSer = mapSer.withContentInclusion(suppressableValue);
799+
ser = mapSer;
774800
}
775-
ser = mapSer;
776801
}
777-
// [Issue#120]: Allow post-processing
802+
// [databind#120]: Allow post-processing
778803
if (_factoryConfig.hasSerializerModifiers()) {
779804
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
780805
ser = mod.modifyMapSerializer(config, type, beanDesc, ser);
@@ -821,22 +846,28 @@ protected Object findSuppressableContentValue(SerializationConfig config,
821846
* Helper method that handles configuration details when constructing serializers for
822847
* <code>Object[]</code> (and subtypes, except for String).
823848
*/
824-
protected JsonSerializer<?> buildArraySerializer(SerializationConfig config,
849+
protected JsonSerializer<?> buildArraySerializer(SerializerProvider prov,
825850
ArrayType type, BeanDescription beanDesc,
826851
boolean staticTyping,
827852
TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
828853
throws JsonMappingException
829854
{
830-
JsonSerializer<?> ser = null;
831-
// Module-provided custom collection serializers?
832-
for (Serializers serializers : customSerializers()) {
855+
// 25-Jun-2015, tatu: Note that unlike with Collection(Like) and Map(Like) types, array
856+
// types can not be annotated (in theory I guess we could have mix-ins but... ?)
857+
// so we need not do primary annotation lookup here.
858+
// So all we need is (1) Custom, (2) Default array serializers
859+
SerializationConfig config = prov.getConfig();
860+
JsonSerializer<?> ser = null;
861+
862+
for (Serializers serializers : customSerializers()) { // (1) Custom
833863
ser = serializers.findArraySerializer(config,
834864
type, beanDesc, elementTypeSerializer, elementValueSerializer);
835865
if (ser != null) {
836866
break;
837867
}
838-
}
839-
if (ser == null) {
868+
}
869+
870+
if (ser == null) {
840871
Class<?> raw = type.getRawClass();
841872
// Important: do NOT use standard serializers if non-standard element value serializer specified
842873
if (elementValueSerializer == null || ClassUtil.isJacksonStdImpl(elementValueSerializer)) {
@@ -852,7 +883,7 @@ protected JsonSerializer<?> buildArraySerializer(SerializationConfig config,
852883
elementValueSerializer);
853884
}
854885
}
855-
// [Issue#120]: Allow post-processing
886+
// [databind#120]: Allow post-processing
856887
if (_factoryConfig.hasSerializerModifiers()) {
857888
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
858889
ser = mod.modifyArraySerializer(config, type, beanDesc, ser);

0 commit comments

Comments
 (0)