Skip to content

Commit 9776f5f

Browse files
committed
Fix #698, add new ReferenceType sub-class of SimpleType
1 parent c85438b commit 9776f5f

File tree

5 files changed

+70
-36
lines changed

5 files changed

+70
-36
lines changed

release-notes/VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Project: jackson-databind
1515
(requested by Laird N)
1616
#696: Copy constructor does not preserve `_injectableValues`
1717
(reported by Charles A)
18+
#698: Add support for referential types (ReferenceType)
1819
#700: Cannot Change Default Abstract Type Mapper from LinkedHashMap
1920
(reported by wealdtech@github)
2021
#725: Auto-detect multi-argument constructor with implicit names if it is the only visible creator

src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java

+20-25
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,17 @@ public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
15181518
if (rawType == CLASS_STRING || rawType == CLASS_CHAR_BUFFER) {
15191519
return StringDeserializer.instance;
15201520
}
1521+
1522+
if (type.isReferenceType()) {
1523+
JavaType referencedType = type.getReferencedType();
1524+
if (AtomicReference.class.isAssignableFrom(rawType)) {
1525+
TypeDeserializer vts = findTypeDeserializer(ctxt.getConfig(), referencedType);
1526+
BeanDescription refdDesc = ctxt.getConfig().introspectClassAnnotations(referencedType);
1527+
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, refdDesc.getClassInfo());
1528+
return new AtomicReferenceDeserializer(referencedType, vts, deser);
1529+
}
1530+
// Hmmh. Should we continue here for unknown referential types?
1531+
}
15211532
if (rawType == CLASS_ITERABLE) {
15221533
// [Issue#199]: Can and should 'upgrade' to a Collection type:
15231534
TypeFactory tf = ctxt.getTypeFactory();
@@ -1528,19 +1539,18 @@ public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
15281539
return createCollectionDeserializer(ctxt, ct, beanDesc);
15291540
}
15301541
if (rawType == CLASS_MAP_ENTRY) {
1531-
final DeserializationConfig config = ctxt.getConfig();
1532-
TypeFactory tf = ctxt.getTypeFactory();
1533-
JavaType[] tps = tf.findTypeParameters(type, CLASS_MAP_ENTRY);
1534-
JavaType kt, vt;
1535-
if (tps == null || tps.length != 2) {
1536-
kt = vt = TypeFactory.unknownType();
1537-
} else {
1538-
kt = tps[0];
1539-
vt = tps[1];
1542+
// 28-Apr-2015, tatu: TypeFactory does it all for us already so
1543+
JavaType kt = type.containedType(0);
1544+
if (kt == null) {
1545+
kt = TypeFactory.unknownType();
1546+
}
1547+
JavaType vt = type.containedType(1);
1548+
if (vt == null) {
1549+
vt = TypeFactory.unknownType();
15401550
}
15411551
TypeDeserializer vts = (TypeDeserializer) vt.getTypeHandler();
15421552
if (vts == null) {
1543-
vts = findTypeDeserializer(config, vt);
1553+
vts = findTypeDeserializer(ctxt.getConfig(), vt);
15441554
}
15451555
JsonDeserializer<Object> valueDeser = vt.getValueHandler();
15461556
KeyDeserializer keyDes = (KeyDeserializer) kt.getValueHandler();
@@ -1561,21 +1571,6 @@ public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
15611571
if (rawType == TokenBuffer.class) {
15621572
return new TokenBufferDeserializer();
15631573
}
1564-
if (AtomicReference.class.isAssignableFrom(rawType)) {
1565-
// Must find parameterization
1566-
TypeFactory tf = ctxt.getTypeFactory();
1567-
JavaType[] params = tf.findTypeParameters(type, AtomicReference.class);
1568-
JavaType referencedType;
1569-
if (params == null || params.length < 1) { // untyped (raw)
1570-
referencedType = TypeFactory.unknownType();
1571-
} else {
1572-
referencedType = params[0];
1573-
}
1574-
TypeDeserializer vts = findTypeDeserializer(ctxt.getConfig(), referencedType);
1575-
BeanDescription refdDesc = ctxt.getConfig().introspectClassAnnotations(referencedType);
1576-
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, refdDesc.getClassInfo());
1577-
return new AtomicReferenceDeserializer(referencedType, vts, deser);
1578-
}
15791574
JsonDeserializer<?> deser = findOptionalStdDeserializer(ctxt, type, beanDesc);
15801575
if (deser != null) {
15811576
return deser;

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

+8-7
Original file line numberDiff line numberDiff line change
@@ -384,13 +384,14 @@ protected final JsonSerializer<?> findSerializerByPrimaryType(SerializerProvider
384384
return DateSerializer.instance;
385385
}
386386
if (Map.Entry.class.isAssignableFrom(raw)) {
387-
JavaType kt, vt;
388-
JavaType[] params = prov.getTypeFactory().findTypeParameters(type, Map.Entry.class);
389-
if (params == null || params.length != 2) { // assume that if we don't get 2, they are wrong...
390-
kt = vt = TypeFactory.unknownType();
391-
} else {
392-
kt = params[0];
393-
vt = params[1];
387+
// 28-Apr-2015, tatu: TypeFactory does it all for us already so
388+
JavaType kt = type.containedType(0);
389+
if (kt == null) {
390+
kt = TypeFactory.unknownType();
391+
}
392+
JavaType vt = type.containedType(1);
393+
if (vt == null) {
394+
vt = TypeFactory.unknownType();
394395
}
395396
return buildMapEntrySerializer(prov.getConfig(), type, beanDesc, staticTyping, kt, vt);
396397
}

src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java

+2
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ public boolean equals(Object o)
185185

186186
ReferenceType other = (ReferenceType) o;
187187

188+
if (other._class != _class) return false;
189+
188190
// Otherwise actually mostly worry about referenced type
189191
return _referencedType.equals(other._referencedType);
190192
}

src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java

+39-4
Original file line numberDiff line numberDiff line change
@@ -805,10 +805,10 @@ protected JavaType _fromClass(Class<?> clz, TypeBindings context)
805805
} else {
806806
// 28-Apr-2015, tatu: New class of types, referential...
807807
if (AtomicReference.class.isAssignableFrom(clz)) {
808+
808809
JavaType[] pts = findTypeParameters(clz, AtomicReference.class);
809810
JavaType rt = (pts == null || pts.length != 1) ? unknownType() : pts[0];
810811
result = constructReferenceType(clz, rt);
811-
812812
// 29-Sep-2014, tatu: We may want to pre-resolve well-known generic types
813813
} else if (Map.Entry.class.isAssignableFrom(clz)) {
814814
JavaType[] pts = findTypeParameters(clz, Map.Entry.class);
@@ -894,7 +894,7 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context)
894894

895895
// Ok: Map or Collection?
896896
if (Map.class.isAssignableFrom(rawType)) {
897-
// 19-Mar-2015, tatu: Looks like 2nd arg ough to be Map.class, but that causes fails
897+
// 19-Mar-2015, tatu: Looks like 2nd arg ought to be Map.class, but that causes fails
898898
JavaType subtype = constructSimpleType(rawType, rawType, pt);
899899
JavaType[] mapParams = findTypeParameters(subtype, Map.class);
900900
if (mapParams.length != 2) {
@@ -903,21 +903,56 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context)
903903
return MapType.construct(rawType, mapParams[0], mapParams[1]);
904904
}
905905
if (Collection.class.isAssignableFrom(rawType)) {
906-
// 19-Mar-2015, tatu: Looks like 2nd arg ough to be Collection.class, but that causes fails
906+
// 19-Mar-2015, tatu: Looks like 2nd arg ought to be Collection.class, but that causes fails
907907
JavaType subtype = constructSimpleType(rawType, rawType, pt);
908908
JavaType[] collectionParams = findTypeParameters(subtype, Collection.class);
909909
if (collectionParams.length != 1) {
910910
throw new IllegalArgumentException("Could not find 1 type parameter for Collection class "+rawType.getName()+" (found "+collectionParams.length+")");
911911
}
912912
return CollectionType.construct(rawType, collectionParams[0]);
913913
}
914+
// 28-Apr-2015, tatu: New class of types, referential...
915+
if (AtomicReference.class.isAssignableFrom(rawType)) {
916+
JavaType rt = null;
917+
918+
if (rawType == AtomicReference.class) {
919+
if (paramCount == 1) {
920+
rt = pt[0];
921+
}
922+
} else {
923+
JavaType[] pts = findTypeParameters(rawType, AtomicReference.class);
924+
if (pts != null && pts.length != 1) {
925+
rt = pts[0];
926+
}
927+
}
928+
return constructReferenceType(rawType, (rt == null) ? unknownType() : rt);
929+
}
930+
if (Map.Entry.class.isAssignableFrom(rawType)) {
931+
JavaType kt = null, vt = null;
932+
933+
if (rawType == Map.Entry.class) {
934+
if (paramCount == 2) {
935+
kt = pt[0];
936+
vt = pt[1];
937+
}
938+
} else {
939+
JavaType[] pts = findTypeParameters(rawType, Map.Entry.class);
940+
if (pts != null && pts.length != 2) {
941+
kt = pts[0];
942+
vt = pts[1];
943+
}
944+
}
945+
return constructSimpleType(rawType, Map.Entry.class, new JavaType[] {
946+
(kt == null) ? unknownType() : kt,
947+
(vt == null) ? unknownType() : vt });
948+
}
949+
914950
if (paramCount == 0) { // no generics
915951
return new SimpleType(rawType);
916952
}
917953
return constructSimpleType(rawType, pt);
918954
}
919955

920-
921956
protected JavaType _fromArrayType(GenericArrayType type, TypeBindings context)
922957
{
923958
JavaType compType = _constructType(type.getGenericComponentType(), context);

0 commit comments

Comments
 (0)