Browse Source

revised BeanTypeDescriptor into core PropertyTypeDescriptor; consider method annotations for return type (SPR-6979)

pull/23217/head
Juergen Hoeller 15 years ago
parent
commit
65b0a8fcb2
  1. 5
      org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java
  2. 7
      org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java
  3. 9
      org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
  4. 24
      org.springframework.core/src/main/java/org/springframework/core/convert/support/PropertyTypeDescriptor.java
  5. 108
      org.springframework.expression/src/main/java/org/springframework/expression/spel/support/BeanTypeDescriptor.java
  6. 38
      org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java

5
org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java

@ -44,6 +44,7 @@ import org.springframework.core.MethodParameter; @@ -44,6 +44,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.PropertyTypeDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@ -368,10 +369,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -368,10 +369,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (pd != null) {
Class type = getPropertyType(propertyName);
if (pd.getReadMethod() != null) {
return new BeanTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), type);
return new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), type);
}
else if (pd.getWriteMethod() != null) {
return new BeanTypeDescriptor(pd, BeanUtils.getWriteMethodParameter(pd), type);
return new PropertyTypeDescriptor(pd, BeanUtils.getWriteMethodParameter(pd), type);
}
}
}

7
org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java

@ -33,6 +33,7 @@ import org.springframework.core.GenericCollectionTypeResolver; @@ -33,6 +33,7 @@ import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.PropertyTypeDescriptor;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@ -152,7 +153,7 @@ class TypeConverterDelegate { @@ -152,7 +153,7 @@ class TypeConverterDelegate {
throws IllegalArgumentException {
return convertIfNecessary(descriptor.getName(), oldValue, newValue, descriptor.getPropertyType(),
new BeanTypeDescriptor(descriptor));
new PropertyTypeDescriptor(descriptor, BeanUtils.getWriteMethodParameter(descriptor)));
}
/**
@ -348,8 +349,8 @@ class TypeConverterDelegate { @@ -348,8 +349,8 @@ class TypeConverterDelegate {
*/
protected PropertyEditor findDefaultEditor(Class requiredType, TypeDescriptor typeDescriptor) {
PropertyEditor editor = null;
if (typeDescriptor instanceof BeanTypeDescriptor) {
PropertyDescriptor pd = ((BeanTypeDescriptor) typeDescriptor).getPropertyDescriptor();
if (typeDescriptor instanceof PropertyTypeDescriptor) {
PropertyDescriptor pd = ((PropertyTypeDescriptor) typeDescriptor).getPropertyDescriptor();
editor = pd.createPropertyEditor(this.targetObject);
}
if (editor == null && requiredType != null) {

9
org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

@ -345,7 +345,14 @@ public class TypeDescriptor { @@ -345,7 +345,14 @@ public class TypeDescriptor {
return this.cachedFieldAnnotations;
}
else if (this.methodParameter != null) {
return this.methodParameter.getParameterAnnotations();
if (this.methodParameter.getParameterIndex() < 0) {
// The best we can do for return type metadata is to expose
// method-level annotations when the target is the return type...
return this.methodParameter.getMethodAnnotations();
}
else {
return this.methodParameter.getParameterAnnotations();
}
}
else {
return new Annotation[0];

24
org.springframework.beans/src/main/java/org/springframework/beans/BeanTypeDescriptor.java → org.springframework.core/src/main/java/org/springframework/core/convert/support/PropertyTypeDescriptor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 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.
@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.beans;
package org.springframework.core.convert.support;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
@ -35,7 +35,7 @@ import org.springframework.util.ReflectionUtils; @@ -35,7 +35,7 @@ import org.springframework.util.ReflectionUtils;
* @author Juergen Hoeller
* @since 3.0
*/
class BeanTypeDescriptor extends TypeDescriptor {
public class PropertyTypeDescriptor extends TypeDescriptor {
private final PropertyDescriptor propertyDescriptor;
@ -45,9 +45,10 @@ class BeanTypeDescriptor extends TypeDescriptor { @@ -45,9 +45,10 @@ class BeanTypeDescriptor extends TypeDescriptor {
/**
* Create a new BeanTypeDescriptor for the given bean property.
* @param propertyDescriptor the corresponding JavaBean PropertyDescriptor
* @param methodParameter the target method parameter
*/
public BeanTypeDescriptor(PropertyDescriptor propertyDescriptor) {
super(BeanUtils.getWriteMethodParameter(propertyDescriptor));
public PropertyTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter) {
super(methodParameter);
this.propertyDescriptor = propertyDescriptor;
}
@ -57,7 +58,7 @@ class BeanTypeDescriptor extends TypeDescriptor { @@ -57,7 +58,7 @@ class BeanTypeDescriptor extends TypeDescriptor {
* @param methodParameter the target method parameter
* @param type the specific type to expose (may be an array/collection element)
*/
public BeanTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class type) {
public PropertyTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class type) {
super(methodParameter, type);
this.propertyDescriptor = propertyDescriptor;
}
@ -70,7 +71,6 @@ class BeanTypeDescriptor extends TypeDescriptor { @@ -70,7 +71,6 @@ class BeanTypeDescriptor extends TypeDescriptor {
return this.propertyDescriptor;
}
@Override
public Annotation[] getAnnotations() {
Annotation[] anns = this.cachedAnnotations;
if (anns == null) {
@ -82,20 +82,22 @@ class BeanTypeDescriptor extends TypeDescriptor { @@ -82,20 +82,22 @@ class BeanTypeDescriptor extends TypeDescriptor {
annMap.put(ann.annotationType(), ann);
}
}
Method targetMethod = getMethodParameter().getMethod();
Method writeMethod = this.propertyDescriptor.getWriteMethod();
Method readMethod = this.propertyDescriptor.getReadMethod();
if (writeMethod != null && writeMethod != targetMethod) {
if (writeMethod != null && writeMethod != getMethodParameter().getMethod()) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
if (readMethod != null && readMethod != targetMethod) {
if (readMethod != null && readMethod != getMethodParameter().getMethod()) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
for (Annotation ann : targetMethod.getAnnotations()) {
for (Annotation ann : getMethodParameter().getMethodAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
for (Annotation ann : getMethodParameter().getParameterAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
anns = annMap.values().toArray(new Annotation[annMap.size()]);

108
org.springframework.expression/src/main/java/org/springframework/expression/spel/support/BeanTypeDescriptor.java

@ -1,108 +0,0 @@ @@ -1,108 +0,0 @@
/*
* Copyright 2002-2009 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.ReflectionUtils;
/**
* {@link TypeDescriptor} extension that exposes additional annotations as
* conversion metadata: namely, annotations on other accessor methods
* (getter/setter) and on the underlying field, if found.
*
* org.springframework.beans.BeanTypeDescriptor (beans module) is very
* similar to this but depending on that would introduce a beans
* dependency from the SpEL module.
*
* @author Juergen Hoeller
* @author Andy Clement
* @since 3.0
*/
public class BeanTypeDescriptor extends TypeDescriptor {
private final PropertyDescriptor propertyDescriptor;
private Annotation[] cachedAnnotations;
/**
* Create a new BeanTypeDescriptor for the given bean property.
*
* @param propertyDescriptor
* the corresponding JavaBean PropertyDescriptor
* @param methodParameter
* the target method parameter
* @param type
* the specific type to expose (may be an array/collection
* element)
*/
public BeanTypeDescriptor(PropertyDescriptor propertyDescriptor,
MethodParameter methodParameter, Class type) {
super(methodParameter, type);
this.propertyDescriptor = propertyDescriptor;
}
/**
* Return the underlying PropertyDescriptor.
*/
public PropertyDescriptor getPropertyDescriptor() {
return this.propertyDescriptor;
}
@Override
public Annotation[] getAnnotations() {
Annotation[] anns = this.cachedAnnotations;
if (anns == null) {
Field underlyingField = ReflectionUtils.findField(
getMethodParameter().getMethod().getDeclaringClass(),
this.propertyDescriptor.getName());
Map<Class, Annotation> annMap = new LinkedHashMap<Class, Annotation>();
if (underlyingField != null) {
for (Annotation ann : underlyingField.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
Method targetMethod = getMethodParameter().getMethod();
Method writeMethod = this.propertyDescriptor.getWriteMethod();
Method readMethod = this.propertyDescriptor.getReadMethod();
if (writeMethod != null && writeMethod != targetMethod) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
if (readMethod != null && readMethod != targetMethod) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
for (Annotation ann : targetMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
anns = annMap.values().toArray(new Annotation[annMap.size()]);
this.cachedAnnotations = anns;
}
return anns;
}
}

38
org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 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.
@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap; @@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.PropertyTypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@ -80,17 +81,18 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { @@ -80,17 +81,18 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
Method method = findGetterForProperty(name, type, target instanceof Class);
if (method != null) {
// Treat it like a property
PropertyDescriptor propertyDescriptor = null;
try {
// The readerCache will only contain gettable properties (let's not worry about setters for now)
propertyDescriptor = new PropertyDescriptor(name,method,null);
} catch (IntrospectionException ex) {
throw new AccessException("Unable to access property '" + name + "' through getter "+method, ex);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
TypeDescriptor typeDescriptor =
new PropertyTypeDescriptor(propertyDescriptor, new MethodParameter(method, -1));
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
catch (IntrospectionException ex) {
throw new AccessException("Unable to access property '" + name + "' through getter " + method, ex);
}
TypeDescriptor typeDescriptor = new BeanTypeDescriptor(propertyDescriptor, new MethodParameter(method,-1), method.getReturnType());
this.readerCache.put(cacheKey, new InvokerPair(method,typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
else {
Field field = findField(name, type, target instanceof Class);
@ -130,16 +132,18 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { @@ -130,16 +132,18 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (method != null) {
// TODO remove the duplication here between canRead and read
// Treat it like a property
PropertyDescriptor propertyDescriptor = null;
try {
// The readerCache will only contain gettable properties (let's not worry about setters for now)
propertyDescriptor = new PropertyDescriptor(name,method,null);
} catch (IntrospectionException ex) {
throw new AccessException("Unable to access property '" + name + "' through getter "+method, ex);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
TypeDescriptor typeDescriptor =
new PropertyTypeDescriptor(propertyDescriptor, new MethodParameter(method, -1));
invoker = new InvokerPair(method, typeDescriptor);
this.readerCache.put(cacheKey, invoker);
}
catch (IntrospectionException ex) {
throw new AccessException(
"Unable to access property '" + name + "' through getter " + method, ex);
}
TypeDescriptor typeDescriptor = new BeanTypeDescriptor(propertyDescriptor, new MethodParameter(method,-1), method.getReturnType());
invoker = new InvokerPair(method,typeDescriptor);
this.readerCache.put(cacheKey, invoker);
}
}
if (method != null) {
@ -201,7 +205,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { @@ -201,7 +205,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
throw new AccessException("Unable to access property '" + name + "' through setter "+method, ex);
}
MethodParameter mp = new MethodParameter(method,0);
TypeDescriptor typeDescriptor = new BeanTypeDescriptor(propertyDescriptor,mp,mp.getParameterType());
TypeDescriptor typeDescriptor = new PropertyTypeDescriptor(propertyDescriptor, mp);
this.writerCache.put(cacheKey, method);
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;

Loading…
Cancel
Save