Skip to content

Commit

Permalink
Fix #698, add new ReferenceType sub-class of SimpleType
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Apr 29, 2015
1 parent c85438b commit 9776f5f
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 36 deletions.
1 change: 1 addition & 0 deletions release-notes/VERSION
Expand Up @@ -15,6 +15,7 @@ Project: jackson-databind
(requested by Laird N)
#696: Copy constructor does not preserve `_injectableValues`
(reported by Charles A)
#698: Add support for referential types (ReferenceType)
#700: Cannot Change Default Abstract Type Mapper from LinkedHashMap
(reported by wealdtech@github)
#725: Auto-detect multi-argument constructor with implicit names if it is the only visible creator
Expand Down
Expand Up @@ -1518,6 +1518,17 @@ public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
if (rawType == CLASS_STRING || rawType == CLASS_CHAR_BUFFER) {
return StringDeserializer.instance;
}

if (type.isReferenceType()) {
JavaType referencedType = type.getReferencedType();
if (AtomicReference.class.isAssignableFrom(rawType)) {
TypeDeserializer vts = findTypeDeserializer(ctxt.getConfig(), referencedType);
BeanDescription refdDesc = ctxt.getConfig().introspectClassAnnotations(referencedType);
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, refdDesc.getClassInfo());
return new AtomicReferenceDeserializer(referencedType, vts, deser);
}
// Hmmh. Should we continue here for unknown referential types?
}
if (rawType == CLASS_ITERABLE) {
// [Issue#199]: Can and should 'upgrade' to a Collection type:
TypeFactory tf = ctxt.getTypeFactory();
Expand All @@ -1528,19 +1539,18 @@ public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
return createCollectionDeserializer(ctxt, ct, beanDesc);
}
if (rawType == CLASS_MAP_ENTRY) {
final DeserializationConfig config = ctxt.getConfig();
TypeFactory tf = ctxt.getTypeFactory();
JavaType[] tps = tf.findTypeParameters(type, CLASS_MAP_ENTRY);
JavaType kt, vt;
if (tps == null || tps.length != 2) {
kt = vt = TypeFactory.unknownType();
} else {
kt = tps[0];
vt = tps[1];
// 28-Apr-2015, tatu: TypeFactory does it all for us already so
JavaType kt = type.containedType(0);
if (kt == null) {
kt = TypeFactory.unknownType();
}
JavaType vt = type.containedType(1);
if (vt == null) {
vt = TypeFactory.unknownType();
}
TypeDeserializer vts = (TypeDeserializer) vt.getTypeHandler();
if (vts == null) {
vts = findTypeDeserializer(config, vt);
vts = findTypeDeserializer(ctxt.getConfig(), vt);
}
JsonDeserializer<Object> valueDeser = vt.getValueHandler();
KeyDeserializer keyDes = (KeyDeserializer) kt.getValueHandler();
Expand All @@ -1561,21 +1571,6 @@ public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
if (rawType == TokenBuffer.class) {
return new TokenBufferDeserializer();
}
if (AtomicReference.class.isAssignableFrom(rawType)) {
// Must find parameterization
TypeFactory tf = ctxt.getTypeFactory();
JavaType[] params = tf.findTypeParameters(type, AtomicReference.class);
JavaType referencedType;
if (params == null || params.length < 1) { // untyped (raw)
referencedType = TypeFactory.unknownType();
} else {
referencedType = params[0];
}
TypeDeserializer vts = findTypeDeserializer(ctxt.getConfig(), referencedType);
BeanDescription refdDesc = ctxt.getConfig().introspectClassAnnotations(referencedType);
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, refdDesc.getClassInfo());
return new AtomicReferenceDeserializer(referencedType, vts, deser);
}
JsonDeserializer<?> deser = findOptionalStdDeserializer(ctxt, type, beanDesc);
if (deser != null) {
return deser;
Expand Down
Expand Up @@ -384,13 +384,14 @@ protected final JsonSerializer<?> findSerializerByPrimaryType(SerializerProvider
return DateSerializer.instance;
}
if (Map.Entry.class.isAssignableFrom(raw)) {
JavaType kt, vt;
JavaType[] params = prov.getTypeFactory().findTypeParameters(type, Map.Entry.class);
if (params == null || params.length != 2) { // assume that if we don't get 2, they are wrong...
kt = vt = TypeFactory.unknownType();
} else {
kt = params[0];
vt = params[1];
// 28-Apr-2015, tatu: TypeFactory does it all for us already so
JavaType kt = type.containedType(0);
if (kt == null) {
kt = TypeFactory.unknownType();
}
JavaType vt = type.containedType(1);
if (vt == null) {
vt = TypeFactory.unknownType();
}
return buildMapEntrySerializer(prov.getConfig(), type, beanDesc, staticTyping, kt, vt);
}
Expand Down
Expand Up @@ -185,6 +185,8 @@ public boolean equals(Object o)

ReferenceType other = (ReferenceType) o;

if (other._class != _class) return false;

// Otherwise actually mostly worry about referenced type
return _referencedType.equals(other._referencedType);
}
Expand Down
43 changes: 39 additions & 4 deletions src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java
Expand Up @@ -805,10 +805,10 @@ protected JavaType _fromClass(Class<?> clz, TypeBindings context)
} else {
// 28-Apr-2015, tatu: New class of types, referential...
if (AtomicReference.class.isAssignableFrom(clz)) {

JavaType[] pts = findTypeParameters(clz, AtomicReference.class);
JavaType rt = (pts == null || pts.length != 1) ? unknownType() : pts[0];
result = constructReferenceType(clz, rt);

// 29-Sep-2014, tatu: We may want to pre-resolve well-known generic types
} else if (Map.Entry.class.isAssignableFrom(clz)) {
JavaType[] pts = findTypeParameters(clz, Map.Entry.class);
Expand Down Expand Up @@ -894,7 +894,7 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context)

// Ok: Map or Collection?
if (Map.class.isAssignableFrom(rawType)) {
// 19-Mar-2015, tatu: Looks like 2nd arg ough to be Map.class, but that causes fails
// 19-Mar-2015, tatu: Looks like 2nd arg ought to be Map.class, but that causes fails
JavaType subtype = constructSimpleType(rawType, rawType, pt);
JavaType[] mapParams = findTypeParameters(subtype, Map.class);
if (mapParams.length != 2) {
Expand All @@ -903,21 +903,56 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context)
return MapType.construct(rawType, mapParams[0], mapParams[1]);
}
if (Collection.class.isAssignableFrom(rawType)) {
// 19-Mar-2015, tatu: Looks like 2nd arg ough to be Collection.class, but that causes fails
// 19-Mar-2015, tatu: Looks like 2nd arg ought to be Collection.class, but that causes fails
JavaType subtype = constructSimpleType(rawType, rawType, pt);
JavaType[] collectionParams = findTypeParameters(subtype, Collection.class);
if (collectionParams.length != 1) {
throw new IllegalArgumentException("Could not find 1 type parameter for Collection class "+rawType.getName()+" (found "+collectionParams.length+")");
}
return CollectionType.construct(rawType, collectionParams[0]);
}
// 28-Apr-2015, tatu: New class of types, referential...
if (AtomicReference.class.isAssignableFrom(rawType)) {
JavaType rt = null;

if (rawType == AtomicReference.class) {
if (paramCount == 1) {
rt = pt[0];
}
} else {
JavaType[] pts = findTypeParameters(rawType, AtomicReference.class);
if (pts != null && pts.length != 1) {
rt = pts[0];
}
}
return constructReferenceType(rawType, (rt == null) ? unknownType() : rt);
}
if (Map.Entry.class.isAssignableFrom(rawType)) {
JavaType kt = null, vt = null;

if (rawType == Map.Entry.class) {
if (paramCount == 2) {
kt = pt[0];
vt = pt[1];
}
} else {
JavaType[] pts = findTypeParameters(rawType, Map.Entry.class);
if (pts != null && pts.length != 2) {
kt = pts[0];
vt = pts[1];
}
}
return constructSimpleType(rawType, Map.Entry.class, new JavaType[] {
(kt == null) ? unknownType() : kt,
(vt == null) ? unknownType() : vt });
}

if (paramCount == 0) { // no generics
return new SimpleType(rawType);
}
return constructSimpleType(rawType, pt);
}


protected JavaType _fromArrayType(GenericArrayType type, TypeBindings context)
{
JavaType compType = _constructType(type.getGenericComponentType(), context);
Expand Down

0 comments on commit 9776f5f

Please sign in to comment.