Polishing along with backports to 3.1.4
This commit is contained in:
parent
3458d4d945
commit
6e8117c627
|
|
@ -36,8 +36,9 @@ import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple PropertyAccessor that uses reflection to access properties for reading and writing. A property can be accessed
|
* Simple PropertyAccessor that uses reflection to access properties for reading and writing.
|
||||||
* if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written).
|
* A property can be accessed if it is accessible as a field on the object or through a
|
||||||
|
* getter (if being read) or a setter (if being written).
|
||||||
*
|
*
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
|
@ -45,11 +46,11 @@ import org.springframework.util.StringUtils;
|
||||||
*/
|
*/
|
||||||
public class ReflectivePropertyAccessor implements PropertyAccessor {
|
public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
|
|
||||||
protected final Map<CacheKey, InvokerPair> readerCache = new ConcurrentHashMap<CacheKey, InvokerPair>();
|
private final Map<CacheKey, InvokerPair> readerCache = new ConcurrentHashMap<CacheKey, InvokerPair>();
|
||||||
|
|
||||||
protected final Map<CacheKey, Member> writerCache = new ConcurrentHashMap<CacheKey, Member>();
|
private final Map<CacheKey, Member> writerCache = new ConcurrentHashMap<CacheKey, Member>();
|
||||||
|
|
||||||
protected final Map<CacheKey, TypeDescriptor> typeDescriptorCache = new ConcurrentHashMap<CacheKey, TypeDescriptor>();
|
private final Map<CacheKey, TypeDescriptor> typeDescriptorCache = new ConcurrentHashMap<CacheKey, TypeDescriptor>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -365,52 +366,6 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Captures the member (method/field) to call reflectively to access a property value and the type descriptor for the
|
|
||||||
* value returned by the reflective call.
|
|
||||||
*/
|
|
||||||
private static class InvokerPair {
|
|
||||||
|
|
||||||
final Member member;
|
|
||||||
|
|
||||||
final TypeDescriptor typeDescriptor;
|
|
||||||
|
|
||||||
public InvokerPair(Member member, TypeDescriptor typeDescriptor) {
|
|
||||||
this.member = member;
|
|
||||||
this.typeDescriptor = typeDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CacheKey {
|
|
||||||
|
|
||||||
private final Class clazz;
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
public CacheKey(Class clazz, String name) {
|
|
||||||
this.clazz = clazz;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object other) {
|
|
||||||
if (this == other) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(other instanceof CacheKey)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
CacheKey otherKey = (CacheKey) other;
|
|
||||||
return (this.clazz.equals(otherKey.clazz) && this.name.equals(otherKey.name));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return this.clazz.hashCode() * 29 + this.name.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to create an optimized property accessor tailored for a property of a particular name on
|
* Attempt to create an optimized property accessor tailored for a property of a particular name on
|
||||||
* a particular class. The general ReflectivePropertyAccessor will always work but is not optimal
|
* a particular class. The general ReflectivePropertyAccessor will always work but is not optimal
|
||||||
|
|
@ -463,29 +418,82 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An optimized form of a PropertyAccessor that will use reflection but only knows how to access a particular property
|
* Captures the member (method/field) to call reflectively to access a property value
|
||||||
* on a particular class. This is unlike the general ReflectivePropertyResolver which manages a cache of methods/fields that
|
* and the type descriptor for the value returned by the reflective call.
|
||||||
* may be invoked to access different properties on different classes. This optimal accessor exists because looking up
|
|
||||||
* the appropriate reflective object by class/name on each read is not cheap.
|
|
||||||
*/
|
*/
|
||||||
static class OptimalPropertyAccessor implements PropertyAccessor {
|
private static class InvokerPair {
|
||||||
|
|
||||||
|
final Member member;
|
||||||
|
|
||||||
|
final TypeDescriptor typeDescriptor;
|
||||||
|
|
||||||
|
public InvokerPair(Member member, TypeDescriptor typeDescriptor) {
|
||||||
|
this.member = member;
|
||||||
|
this.typeDescriptor = typeDescriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class CacheKey {
|
||||||
|
|
||||||
|
private final Class clazz;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public CacheKey(Class clazz, String name) {
|
||||||
|
this.clazz = clazz;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (this == other) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(other instanceof CacheKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CacheKey otherKey = (CacheKey) other;
|
||||||
|
return (this.clazz.equals(otherKey.clazz) && this.name.equals(otherKey.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return this.clazz.hashCode() * 29 + this.name.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optimized form of a PropertyAccessor that will use reflection but only knows
|
||||||
|
* how to access a particular property on a particular class. This is unlike the
|
||||||
|
* general ReflectivePropertyResolver which manages a cache of methods/fields that
|
||||||
|
* may be invoked to access different properties on different classes. This optimal
|
||||||
|
* accessor exists because looking up the appropriate reflective object by class/name
|
||||||
|
* on each read is not cheap.
|
||||||
|
*/
|
||||||
|
private static class OptimalPropertyAccessor implements PropertyAccessor {
|
||||||
|
|
||||||
private final Member member;
|
private final Member member;
|
||||||
|
|
||||||
private final TypeDescriptor typeDescriptor;
|
private final TypeDescriptor typeDescriptor;
|
||||||
|
|
||||||
private final boolean needsToBeMadeAccessible;
|
private final boolean needsToBeMadeAccessible;
|
||||||
|
|
||||||
OptimalPropertyAccessor(InvokerPair target) {
|
OptimalPropertyAccessor(InvokerPair target) {
|
||||||
this.member = target.member;
|
this.member = target.member;
|
||||||
this.typeDescriptor = target.typeDescriptor;
|
this.typeDescriptor = target.typeDescriptor;
|
||||||
if (this.member instanceof Field) {
|
if (this.member instanceof Field) {
|
||||||
Field field = (Field)member;
|
Field field = (Field) this.member;
|
||||||
needsToBeMadeAccessible = (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()))
|
this.needsToBeMadeAccessible = (!Modifier.isPublic(field.getModifiers()) ||
|
||||||
&& !field.isAccessible();
|
!Modifier.isPublic(field.getDeclaringClass().getModifiers())) && !field.isAccessible();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Method method = (Method)member;
|
Method method = (Method) this.member;
|
||||||
needsToBeMadeAccessible = ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
|
this.needsToBeMadeAccessible = ((!Modifier.isPublic(method.getModifiers()) ||
|
||||||
&& !method.isAccessible());
|
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -501,8 +509,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
if (type.isArray()) {
|
if (type.isArray()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (member instanceof Method) {
|
if (this.member instanceof Method) {
|
||||||
Method method = (Method)member;
|
Method method = (Method) this.member;
|
||||||
String getterName = "get" + StringUtils.capitalize(name);
|
String getterName = "get" + StringUtils.capitalize(name);
|
||||||
if (getterName.equals(method.getName())) {
|
if (getterName.equals(method.getName())) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -511,31 +519,31 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
return getterName.equals(method.getName());
|
return getterName.equals(method.getName());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Field field = (Field)member;
|
Field field = (Field) this.member;
|
||||||
return field.getName().equals(name);
|
return field.getName().equals(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||||
if (member instanceof Method) {
|
if (this.member instanceof Method) {
|
||||||
try {
|
try {
|
||||||
if (needsToBeMadeAccessible) {
|
if (this.needsToBeMadeAccessible) {
|
||||||
ReflectionUtils.makeAccessible((Method) member);
|
ReflectionUtils.makeAccessible((Method) this.member);
|
||||||
}
|
}
|
||||||
Object value = ((Method) member).invoke(target);
|
Object value = ((Method) this.member).invoke(target);
|
||||||
return new TypedValue(value, typeDescriptor.narrow(value));
|
return new TypedValue(value, this.typeDescriptor.narrow(value));
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new AccessException("Unable to access property '" + name + "' through getter", ex);
|
throw new AccessException("Unable to access property '" + name + "' through getter", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (member instanceof Field) {
|
if (this.member instanceof Field) {
|
||||||
try {
|
try {
|
||||||
if (needsToBeMadeAccessible) {
|
if (this.needsToBeMadeAccessible) {
|
||||||
ReflectionUtils.makeAccessible((Field)member);
|
ReflectionUtils.makeAccessible((Field) this.member);
|
||||||
}
|
}
|
||||||
Object value = ((Field)member).get(target);
|
Object value = ((Field) this.member).get(target);
|
||||||
return new TypedValue(value, typeDescriptor.narrow(value));
|
return new TypedValue(value, this.typeDescriptor.narrow(value));
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new AccessException("Unable to access field: " + name, ex);
|
throw new AccessException("Unable to access field: " + name, ex);
|
||||||
|
|
@ -544,12 +552,11 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||||
throw new AccessException("Neither getter nor field found for property '" + name + "'");
|
throw new AccessException("Neither getter nor field found for property '" + name + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
public boolean canWrite(EvaluationContext context, Object target, String name) {
|
||||||
throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor");
|
throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(EvaluationContext context, Object target, String name, Object newValue)
|
public void write(EvaluationContext context, Object target, String name, Object newValue) {
|
||||||
throws AccessException {
|
|
||||||
throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor");
|
throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ResourceDatabasePopulator.class);
|
private static final Log logger = LogFactory.getLog(ResourceDatabasePopulator.class);
|
||||||
|
|
||||||
|
|
||||||
private List<Resource> scripts = new ArrayList<Resource>();
|
private List<Resource> scripts = new ArrayList<Resource>();
|
||||||
|
|
||||||
private String sqlScriptEncoding;
|
private String sqlScriptEncoding;
|
||||||
|
|
@ -127,6 +128,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||||
this.ignoreFailedDrops = ignoreFailedDrops;
|
this.ignoreFailedDrops = ignoreFailedDrops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void populate(Connection connection) throws SQLException {
|
public void populate(Connection connection) throws SQLException {
|
||||||
for (Resource script : this.scripts) {
|
for (Resource script : this.scripts) {
|
||||||
executeSqlScript(connection, applyEncodingIfNecessary(script), this.continueOnError, this.ignoreFailedDrops);
|
executeSqlScript(connection, applyEncodingIfNecessary(script), this.continueOnError, this.ignoreFailedDrops);
|
||||||
|
|
@ -191,8 +193,8 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||||
boolean dropStatement = StringUtils.startsWithIgnoreCase(statement.trim(), "drop");
|
boolean dropStatement = StringUtils.startsWithIgnoreCase(statement.trim(), "drop");
|
||||||
if (continueOnError || (dropStatement && ignoreFailedDrops)) {
|
if (continueOnError || (dropStatement && ignoreFailedDrops)) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Failed to execute SQL script statement at line " + lineNumber
|
logger.debug("Failed to execute SQL script statement at line " + lineNumber +
|
||||||
+ " of resource " + resource + ": " + statement, ex);
|
" of resource " + resource + ": " + statement, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -227,8 +229,8 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||||
String currentStatement = lnr.readLine();
|
String currentStatement = lnr.readLine();
|
||||||
StringBuilder scriptBuilder = new StringBuilder();
|
StringBuilder scriptBuilder = new StringBuilder();
|
||||||
while (currentStatement != null) {
|
while (currentStatement != null) {
|
||||||
if (StringUtils.hasText(currentStatement)
|
if (StringUtils.hasText(currentStatement) &&
|
||||||
&& (this.commentPrefix != null && !currentStatement.startsWith(this.commentPrefix))) {
|
(this.commentPrefix != null && !currentStatement.startsWith(this.commentPrefix))) {
|
||||||
if (scriptBuilder.length() > 0) {
|
if (scriptBuilder.length() > 0) {
|
||||||
scriptBuilder.append('\n');
|
scriptBuilder.append('\n');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue