|
9 | 9 | import com.fasterxml.jackson.annotation.JsonPropertyDescription; |
10 | 10 | import com.fasterxml.jackson.annotation.JsonSubTypes; |
11 | 11 | import com.fasterxml.jackson.annotation.JsonTypeInfo; |
12 | | -import com.fasterxml.jackson.annotation.JsonTypeName; |
13 | 12 | import com.fasterxml.jackson.annotation.JsonUnwrapped; |
14 | 13 | import com.fasterxml.jackson.annotation.ObjectIdGenerators; |
15 | 14 | import com.fasterxml.jackson.annotation.PropertyAccessor; |
|
36 | 35 | import com.fasterxml.jackson.databind.deser.DefaultDeserializationContext; |
37 | 36 | import com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap; |
38 | 37 | import com.fasterxml.jackson.databind.introspect.AnnotatedClass; |
39 | | -import com.fasterxml.jackson.databind.introspect.AnnotatedClassResolver; |
40 | 38 | import com.fasterxml.jackson.databind.jsontype.NamedType; |
| 39 | +import com.fasterxml.jackson.databind.jsontype.SubtypeResolver; |
| 40 | +import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; |
| 41 | +import com.fasterxml.jackson.databind.jsontype.TypeSerializer; |
41 | 42 | import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; |
42 | 43 | import com.fasterxml.jackson.databind.ser.BeanSerializer; |
43 | 44 | import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; |
|
67 | 68 | import java.util.Collection; |
68 | 69 | import java.util.Collections; |
69 | 70 | import java.util.Comparator; |
| 71 | +import java.util.LinkedHashSet; |
70 | 72 | import java.util.List; |
71 | 73 | import java.util.Map; |
72 | 74 | import java.util.Objects; |
@@ -297,13 +299,13 @@ private BeanModel parseBean(SourceType<Class<?>> sourceClass, List<String> class |
297 | 299 | final JsonTypeInfo jsonTypeInfo = classWithJsonTypeInfo.getValue2(); |
298 | 300 | discriminantProperty = getDiscriminantPropertyName(jsonTypeInfo); |
299 | 301 | syntheticDiscriminantProperty = isDiscriminantPropertySynthetic(jsonTypeInfo); |
300 | | - discriminantLiteral = isInterfaceOrAbstract(sourceClass.type) ? null : getTypeName(jsonTypeInfo, sourceClass.type); |
| 302 | + discriminantLiteral = isInterfaceOrAbstract(sourceClass.type) ? null : getTypeName(sourceClass.type); |
301 | 303 | } else if (isTaggedUnion(parentClassWithJsonTypeInfo = getAnnotationRecursive(sourceClass.type, JsonTypeInfo.class))) { |
302 | 304 | // this is child class |
303 | 305 | final JsonTypeInfo parentJsonTypeInfo = parentClassWithJsonTypeInfo.getValue2(); |
304 | 306 | discriminantProperty = getDiscriminantPropertyName(parentJsonTypeInfo); |
305 | 307 | syntheticDiscriminantProperty = isDiscriminantPropertySynthetic(parentJsonTypeInfo); |
306 | | - discriminantLiteral = getTypeName(parentJsonTypeInfo, sourceClass.type); |
| 308 | + discriminantLiteral = getTypeName(sourceClass.type); |
307 | 309 | } else { |
308 | 310 | // not part of explicit hierarchy |
309 | 311 | discriminantProperty = null; |
@@ -435,59 +437,53 @@ private String getDiscriminantPropertyName(JsonTypeInfo jsonTypeInfo) { |
435 | 437 | : jsonTypeInfo.property(); |
436 | 438 | } |
437 | 439 |
|
438 | | - private String getTypeName(JsonTypeInfo parentJsonTypeInfo, final Class<?> cls) { |
439 | | - // Id.CLASS |
440 | | - if (parentJsonTypeInfo.use() == JsonTypeInfo.Id.CLASS) { |
441 | | - return cls.getName(); |
442 | | - } |
443 | | - // find custom name registered with `registerSubtypes` |
444 | | - AnnotatedClass annotatedClass = AnnotatedClassResolver |
445 | | - .resolveWithoutSuperTypes(objectMapper.getSerializationConfig(), cls); |
446 | | - Collection<NamedType> subtypes = objectMapper.getSubtypeResolver() |
447 | | - .collectAndResolveSubtypesByClass(objectMapper.getSerializationConfig(), |
448 | | - annotatedClass); |
449 | | - |
450 | | - if (subtypes.size() == 1) { |
451 | | - NamedType subtype = subtypes.iterator().next(); |
| 440 | + private String getTypeName(Class<?> cls) { |
| 441 | + final List<String> typeNames = getTypeNamesOrEmptyOrNull(cls); |
| 442 | + return typeNames != null && !typeNames.isEmpty() ? typeNames.get(0) : null; |
| 443 | + } |
452 | 444 |
|
453 | | - if (subtype.getName() != null) { |
454 | | - return subtype.getName(); |
| 445 | + private List<String> getTypeNamesOrEmptyOrNull(Class<?> cls) { |
| 446 | + try { |
| 447 | + final SerializationConfig config = objectMapper.getSerializationConfig(); |
| 448 | + final JavaType javaType = config.constructType(cls); |
| 449 | + final TypeSerializer typeSerializer = objectMapper.getSerializerProviderInstance().findTypeSerializer(javaType); |
| 450 | + final TypeIdResolver typeIdResolver = typeSerializer.getTypeIdResolver(); |
| 451 | + if (typeIdResolver.getMechanism() == JsonTypeInfo.Id.NAME) { |
| 452 | + final SubtypeResolver subtypeResolver = config.getSubtypeResolver(); |
| 453 | + final BeanDescription beanDescription = config.introspectClassAnnotations(cls); |
| 454 | + final AnnotatedClass annotatedClass = beanDescription.getClassInfo(); |
| 455 | + final Collection<NamedType> serializationSubtypes = subtypeResolver.collectAndResolveSubtypesByClass(config, annotatedClass); |
| 456 | + final Collection<NamedType> deserializationSubtypes = subtypeResolver.collectAndResolveSubtypesByTypeId(config, annotatedClass); |
| 457 | + final List<String> serializationTypeNames = getTypeNamesFromSubtypes(serializationSubtypes, cls); // 0 or 1 |
| 458 | + final List<String> deserializationTypeNames = getTypeNamesFromSubtypes(deserializationSubtypes, cls); // 0 or n |
| 459 | + final LinkedHashSet<String> typeNames = Stream |
| 460 | + .concat(serializationTypeNames.stream(), deserializationTypeNames.stream()) |
| 461 | + .collect(Collectors.toCollection(LinkedHashSet::new)); |
| 462 | + if (typeNames.isEmpty()) { |
| 463 | + return isInterfaceOrAbstract(cls) ? null : Utils.listFromNullable(typeIdResolver.idFromBaseType()); |
| 464 | + } else { |
| 465 | + return new ArrayList<>(typeNames); |
| 466 | + } |
| 467 | + } else { |
| 468 | + return Utils.listFromNullable(typeIdResolver.idFromBaseType()); |
455 | 469 | } |
| 470 | + } catch (Exception e) { |
| 471 | + return null; |
456 | 472 | } |
| 473 | + } |
457 | 474 |
|
458 | | - // find @JsonTypeName recursively |
459 | | - final JsonTypeName jsonTypeName = getAnnotationRecursive(cls, JsonTypeName.class).getValue2(); |
460 | | - if (jsonTypeName != null && !jsonTypeName.value().isEmpty()) { |
461 | | - return jsonTypeName.value(); |
462 | | - } |
463 | | - // find @JsonSubTypes.Type recursively |
464 | | - final JsonSubTypes jsonSubTypes = getAnnotationRecursive(cls, JsonSubTypes.class, (JsonSubTypes types) -> getJsonSubTypeForClass(types, cls) != null).getValue2(); |
465 | | - if (jsonSubTypes != null) { |
466 | | - final JsonSubTypes.Type jsonSubType = getJsonSubTypeForClass(jsonSubTypes, cls); |
467 | | - if (!jsonSubType.name().isEmpty()) { |
468 | | - return jsonSubType.name(); |
469 | | - } |
470 | | - } |
471 | | - // use simplified class name if it's not an interface or abstract |
472 | | - if(!isInterfaceOrAbstract(cls)) { |
473 | | - return cls.getName().substring(cls.getName().lastIndexOf(".") + 1); |
474 | | - } |
475 | | - return null; |
| 475 | + private static List<String> getTypeNamesFromSubtypes(Collection<NamedType> subtypes, Class<?> cls) { |
| 476 | + return subtypes.stream() |
| 477 | + .filter(subtype -> Objects.equals(subtype.getType(), cls)) |
| 478 | + .filter(NamedType::hasName) |
| 479 | + .map(NamedType::getName) |
| 480 | + .collect(Collectors.toList()); |
476 | 481 | } |
477 | 482 |
|
478 | 483 | private boolean isInterfaceOrAbstract(Class<?> cls) { |
479 | 484 | return cls.isInterface() || Modifier.isAbstract(cls.getModifiers()); |
480 | 485 | } |
481 | 486 |
|
482 | | - private static JsonSubTypes.Type getJsonSubTypeForClass(JsonSubTypes types, Class<?> cls) { |
483 | | - for (JsonSubTypes.Type type : types.value()) { |
484 | | - if (type.value().equals(cls)) { |
485 | | - return type; |
486 | | - } |
487 | | - } |
488 | | - return null; |
489 | | - } |
490 | | - |
491 | 487 | private static <T extends Annotation> Pair<Class<?>, T> getAnnotationRecursive(Class<?> cls, Class<T> annotationClass) { |
492 | 488 | return getAnnotationRecursive(cls, annotationClass, null); |
493 | 489 | } |
|
0 commit comments