DATACMNS-518 - Avoid potential infinite loops in PreferredConstructor.
We now synchronize the (seldom) writes to the isPropertyParameterCache HashMap in PreferredConstructor via a ReadWriteLock. We could as well have used a ConcurrentHashMap here without the need for manual locking but this would potentially waste memory for a mostly read-only data structure. We also anticipate potential multiple writes for the same property. Original pull request: #86.
This commit is contained in:
committed by
Oliver Gierke
parent
a885b57dbf
commit
2586344218
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,8 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
@@ -36,6 +38,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
@@ -43,6 +46,10 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
private final List<Parameter<Object, P>> parameters;
|
||||
private final Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<PersistentProperty<?>, Boolean>();
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final Lock read = lock.readLock();
|
||||
private final Lock write = lock.writeLock();
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructor} from the given {@link Constructor} and {@link Parameter}s.
|
||||
*
|
||||
@@ -117,21 +124,36 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
Assert.notNull(property);
|
||||
|
||||
Boolean cached = isPropertyParameterCache.get(property);
|
||||
try {
|
||||
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
read.lock();
|
||||
Boolean cached = isPropertyParameterCache.get(property);
|
||||
|
||||
for (Parameter<?, P> parameter : parameters) {
|
||||
if (parameter.maps(property)) {
|
||||
isPropertyParameterCache.put(property, true);
|
||||
return true;
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
|
||||
isPropertyParameterCache.put(property, false);
|
||||
return false;
|
||||
try {
|
||||
|
||||
write.lock();
|
||||
|
||||
for (Parameter<?, P> parameter : parameters) {
|
||||
if (parameter.maps(property)) {
|
||||
isPropertyParameterCache.put(property, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
isPropertyParameterCache.put(property, false);
|
||||
return false;
|
||||
|
||||
} finally {
|
||||
write.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user