diff --git a/src/main/java/org/springframework/data/util/TypeDiscoverer.java b/src/main/java/org/springframework/data/util/TypeDiscoverer.java index 4e09d75a6..f5abe9dab 100644 --- a/src/main/java/org/springframework/data/util/TypeDiscoverer.java +++ b/src/main/java/org/springframework/data/util/TypeDiscoverer.java @@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.BeanUtils; import org.springframework.core.GenericTypeResolver; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; /** @@ -47,7 +48,7 @@ class TypeDiscoverer implements TypeInformation { private final Type type; private final Map, Type> typeVariableMap; - private final Map> fieldTypes = new ConcurrentHashMap>(); + private final Map fieldTypes = new ConcurrentHashMap(); private final int hashCode; private boolean componentTypeResolved = false; @@ -188,14 +189,14 @@ class TypeDiscoverer implements TypeInformation { int separatorIndex = fieldname.indexOf('.'); if (separatorIndex == -1) { + if (fieldTypes.containsKey(fieldname)) { - return fieldTypes.get(fieldname); + return fieldTypes.get(fieldname).getType(); } TypeInformation propertyInformation = getPropertyInformation(fieldname); - if (propertyInformation != null) { - fieldTypes.put(fieldname, propertyInformation); - } + fieldTypes.put(fieldname, ValueHolder.of(propertyInformation)); + return propertyInformation; } @@ -645,4 +646,73 @@ class TypeDiscoverer implements TypeInformation { return result; } } + + /** + * Simple wrapper type to cache {@literal null} {@link TypeInformation}s. + * + * @author Oliver Gierke + */ + private static class ValueHolder { + + private static final ValueHolder NULL_HOLDER = new ValueHolder(null); + + private final TypeInformation type; + + /** + * Creates a new {@link ValueHolder} for the given {@link TypeInformation}. + * + * @param value can be {@literal null}. + */ + private ValueHolder(TypeInformation value) { + this.type = value; + } + + /** + * Returns a {@link ValueHolder} for the given {@link TypeInformation}. + * + * @param value can be {@literal null}. + * @return will never be {@literal null}. + */ + public static ValueHolder of(TypeInformation value) { + return value == null ? NULL_HOLDER : new ValueHolder(value); + } + + /** + * Returns the {@link TypeInformation} contained in the {@link ValueHolder}. + * + * @return can be {@literal null}. + */ + public TypeInformation getType() { + return type; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + + if (obj == this) { + return true; + } + + if (!(obj instanceof ValueHolder)) { + return false; + } + + ValueHolder that = (ValueHolder) obj; + + return ObjectUtils.nullSafeEquals(this.type, that.type); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return ObjectUtils.nullSafeHashCode(type); + } + } }