Browse Source

DATACMNS-1271 - Streamlined implementation of AnnotationBasedPersistentProperty to avoid NullPointerExceptions.

We now use the annotation cache's ….computeIfAbsent(…) to avoid inconsistencies between ….contains(…) and ….get(…) in multi-threaded scenarios.
pull/271/merge
Oliver Gierke 8 years ago
parent
commit
78d21327bb
  1. 34
      src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java
  2. 12
      src/main/java/org/springframework/data/util/StreamUtils.java

34
src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java

@ -39,6 +39,7 @@ import org.springframework.data.mapping.PersistentEntity; @@ -39,6 +39,7 @@ import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.Optionals;
import org.springframework.data.util.StreamUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -229,22 +230,13 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp @@ -229,22 +230,13 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
@SuppressWarnings("unchecked")
private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) {
if (annotationCache != null && annotationCache.containsKey(annotationType)) {
return (Optional<A>) annotationCache.get(annotationType);
}
return cacheAndReturn(annotationType, getAccessors()//
.flatMap(it -> {
A mergedAnnotation = AnnotatedElementUtils.findMergedAnnotation(it, annotationType);
return (Optional<A>) annotationCache.computeIfAbsent(annotationType, type -> {
if (mergedAnnotation == null) {
return Stream.empty();
}
return Stream.of(mergedAnnotation);
})//
.findFirst());
return getAccessors() //
.map(it -> AnnotatedElementUtils.findMergedAnnotation(it, type)) //
.flatMap(StreamUtils::fromNullable) //
.findFirst();
});
}
/*
@ -260,18 +252,6 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp @@ -260,18 +252,6 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
return annotation != null ? annotation : getOwner().findAnnotation(annotationType);
}
/**
* Puts the given annotation into the local cache and returns it.
*
* @param annotation
* @return
*/
private <A extends Annotation> Optional<A> cacheAndReturn(Class<? extends A> type, Optional<A> annotation) {
annotationCache.put(type, annotation);
return annotation;
}
/**
* Returns whether the property carries the an annotation of the given type.
*

12
src/main/java/org/springframework/data/util/StreamUtils.java

@ -28,6 +28,7 @@ import java.util.stream.Collector; @@ -28,6 +28,7 @@ import java.util.stream.Collector;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
@ -95,4 +96,15 @@ public interface StreamUtils { @@ -95,4 +96,15 @@ public interface StreamUtils {
Function<T, V> valueFunction) {
return MultiValueMapCollector.of(keyFunction, valueFunction);
}
/**
* Creates a new {@link Stream} for the given value returning an empty {@link Stream} if the value is {@literal null}.
*
* @param source can be {@literal null}.
* @return a new {@link Stream} for the given value returning an empty {@link Stream} if the value is {@literal null}.
* @since 2.0.6
*/
public static <T> Stream<T> fromNullable(@Nullable T source) {
return source == null ? Stream.empty() : Stream.of(source);
}
}

Loading…
Cancel
Save