You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by mb...@apache.org on 2011/02/17 18:28:16 UTC
svn commit: r1071712 - in /incubator/bval/sandbox/lang3-work:
bval-core/src/main/java/org/apache/bval/util/
bval-jsr303/src/main/java/org/apache/bval/jsr303/
bval-jsr303/src/main/java/org/apache/bval/jsr303/util/
Author: mbenson
Date: Thu Feb 17 17:28:16 2011
New Revision: 1071712
URL: http://svn.apache.org/viewvc?rev=1071712&view=rev
Log:
when processing classes with the Jsr303MetaBeanFactory, ensure that a new MetaProperty is only retained when some processing took place. This prevents overlarge amounts of metadata being stored as a result of field-reading in particular; specifically the use of AOP weaving can add arbitrarily numerous numbers of fields to a class which realistically need no validation. ValidationContextTraversal has been modified to handle validations requested specifically for non-constrained, but valid, properties.
Modified:
incubator/bval/sandbox/lang3-work/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java
incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java
incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/ValidationContextTraversal.java
Modified: incubator/bval/sandbox/lang3-work/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java?rev=1071712&r1=1071711&r2=1071712&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-core/src/main/java/org/apache/bval/util/PropertyAccess.java Thu Feb 17 17:28:16 2011
@@ -22,12 +22,13 @@ import java.beans.PropertyDescriptor;
import java.lang.annotation.ElementType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
/**
- * Description: Undefined dynamic strategy (FIELD or METHOD access) Uses
- * PropertyUtils or tries to determine field to access the value<br/>
+ * Description: Undefined dynamic strategy (FIELD or METHOD access) Uses PropertyUtils or tries to determine field to
+ * access the value<br/>
*/
public class PropertyAccess extends AccessStrategy {
private final Class<?> beanClass;
@@ -49,7 +50,7 @@ public class PropertyAccess extends Acce
* {@inheritDoc}
*/
public ElementType getElementType() {
- return (rememberField != null) ? ElementType.FIELD : ElementType.METHOD;
+ return rememberField != null ? ElementType.FIELD : ElementType.METHOD;
}
private static Object getPublicProperty(Object bean, String property) throws InvocationTargetException,
@@ -87,32 +88,65 @@ public class PropertyAccess extends Acce
* {@inheritDoc}
*/
public Type getJavaType() {
- /*
- * if(Map.class.isAssignableFrom(beanClass)) { return beanClass. }
- */
- if (rememberField != null) { // use cached field of previous access
+ Type result = getTypeInner();
+ return result == null ? Object.class : result;
+ }
+
+ /**
+ * Learn whether this {@link PropertyAccess} references a known property.
+ *
+ * @return boolean
+ */
+ public boolean isKnown() {
+ return getTypeInner() != null;
+ }
+
+ /**
+ * Find out what, if any, type can be calculated.
+ *
+ * @return type found or <code>null</code>
+ */
+ private Type getTypeInner() {
+ if (rememberField != null) {
+ return rememberField.getGenericType();
+ }
+ Method readMethod = getPropertyReadMethod(propertyName, beanClass);
+ if (readMethod != null) {
+ return readMethod.getGenericReturnType();
+ }
+ Field fld = getField(propertyName, beanClass);
+ if (fld != null) {
+ cacheField(fld);
return rememberField.getGenericType();
}
+ return null;
+ }
+
+ private static Method getPropertyReadMethod(String propertyName, Class<?> beanClass) {
for (PropertyDescriptor each : PropertyUtils.getPropertyDescriptors(beanClass)) {
- if (each.getName().equals(propertyName) && each.getReadMethod() != null) {
- return each.getReadMethod().getGenericReturnType();
+ if (each.getName().equals(propertyName)) {
+ return each.getReadMethod();
}
}
+ return null;
+ }
+
+ private static Field getField(String propertyName, Class<?> beanClass) {
try { // try public field
- return beanClass.getField(propertyName).getGenericType();
+ return beanClass.getField(propertyName);
} catch (NoSuchFieldException ex2) {
// search for private/protected field up the hierarchy
Class<?> theClass = beanClass;
while (theClass != null) {
try {
- return theClass.getDeclaredField(propertyName).getGenericType();
+ return theClass.getDeclaredField(propertyName);
} catch (NoSuchFieldException ex3) {
// do nothing
}
theClass = theClass.getSuperclass();
}
}
- return Object.class; // unknown type: allow any type??
+ return null;
}
/**
@@ -130,7 +164,6 @@ public class PropertyAccess extends Acce
if (rememberField != null) { // cache field of previous access
return rememberField.get(bean);
}
-
try { // try public method
return getPublicProperty(bean, propertyName);
} catch (NoSuchMethodException ex) {
@@ -144,31 +177,19 @@ public class PropertyAccess extends Acce
}
private Object getFieldValue(Object bean) throws IllegalAccessException {
- Object value;
- try { // try public field
- Field aField = bean.getClass().getField(propertyName);
- value = aField.get(bean);
- rememberField = aField;
- return value;
- } catch (NoSuchFieldException ex2) {
- // search for private/protected field up the hierarchy
- Class<?> theClass = bean.getClass();
- while (theClass != null) {
- try {
- Field aField = theClass.getDeclaredField(propertyName);
- if (!aField.isAccessible()) {
- aField.setAccessible(true);
- }
- value = aField.get(bean);
- rememberField = aField;
- return value;
- } catch (NoSuchFieldException ex3) {
- // do nothing
- }
- theClass = theClass.getSuperclass();
- }
- throw new IllegalArgumentException("cannot access field " + propertyName);
+ Field field = getField(propertyName, beanClass);
+ if (field != null) {
+ cacheField(field);
+ return rememberField.get(bean);
+ }
+ throw new IllegalArgumentException("cannot access field " + propertyName);
+ }
+
+ private void cacheField(Field field) {
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
}
+ this.rememberField = field;
}
/**
Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java?rev=1071712&r1=1071711&r2=1071712&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/Jsr303MetaBeanFactory.java Thu Feb 17 17:28:16 2011
@@ -22,7 +22,6 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
@@ -46,9 +45,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Description: process the class annotations for JSR303 constraint validations
- * to build the MetaBean with information from annotations and JSR303 constraint
- * mappings (defined in xml)<br/>
+ * Description: process the class annotations for JSR303 constraint validations to build the MetaBean with information
+ * from annotations and JSR303 constraint mappings (defined in xml)<br/>
*/
public class Jsr303MetaBeanFactory implements MetaBeanFactory {
/** Shared log instance */
@@ -74,8 +72,7 @@ public class Jsr303MetaBeanFactory imple
}
/**
- * {@inheritDoc} Add the validation features to the metabean that come from
- * JSR303 annotations in the beanClass.
+ * {@inheritDoc} Add the validation features to the metabean that come from JSR303 annotations in the beanClass.
*/
public void buildMetaBean(MetaBean metabean) {
try {
@@ -127,11 +124,15 @@ public class Jsr303MetaBeanFactory imple
// create a property for those fields for which there is not yet a
// MetaProperty
if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(field)) {
- if (metaProperty == null) {
- metaProperty = addMetaProperty(metabean, field.getName(), field.getGenericType());
+ AccessStrategy access = new FieldAccess(field);
+ boolean create = metaProperty == null;
+ if (create) {
+ metaProperty = addMetaProperty(metabean, access);
+ }
+ if (!annotationProcessor.processAnnotations(metaProperty, beanClass, field, access,
+ new AppendValidationToMeta(metaProperty)) && create) {
+ metabean.putProperty(metaProperty.getName(), null);
}
- annotationProcessor.processAnnotations(metaProperty, beanClass, field, new FieldAccess(field),
- new AppendValidationToMeta(metaProperty));
}
}
final Method[] methods = SecureActions.getDeclaredMethods(beanClass);
@@ -142,14 +143,18 @@ public class Jsr303MetaBeanFactory imple
}
if (propName != null) {
if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(method)) {
+ AccessStrategy access = new MethodAccess(propName, method);
MetaProperty metaProperty = metabean.getProperty(propName);
+ boolean create = metaProperty == null;
// create a property for those methods for which there is
// not yet a MetaProperty
- if (metaProperty == null) {
- metaProperty = addMetaProperty(metabean, propName, method.getGenericReturnType());
+ if (create) {
+ metaProperty = addMetaProperty(metabean, access);
+ }
+ if (!annotationProcessor.processAnnotations(metaProperty, beanClass, method, access,
+ new AppendValidationToMeta(metaProperty)) && create) {
+ metabean.putProperty(propName, null);
}
- annotationProcessor.processAnnotations(metaProperty, beanClass, method, new MethodAccess(propName,
- method), new AppendValidationToMeta(metaProperty));
}
} else if (hasValidationConstraintsDefined(method)) {
throw new ValidationException("Property " + method.getName() + " does not follow javabean conventions.");
@@ -160,8 +165,7 @@ public class Jsr303MetaBeanFactory imple
}
/**
- * Learn whether a given Method has validation constraints defined via
- * JSR303 annotations.
+ * Learn whether a given Method has validation constraints defined via JSR303 annotations.
*
* @param method
* @return <code>true</code> if constraints detected
@@ -208,25 +212,32 @@ public class Jsr303MetaBeanFactory imple
InvocationTargetException {
for (MetaConstraint<?, ? extends Annotation> meta : factoryContext.getFactory().getMetaConstraints(beanClass)) {
MetaProperty metaProperty;
- if (meta.getAccessStrategy() == null) { // class level
+ AccessStrategy access = meta.getAccessStrategy();
+ boolean create = false;
+ if (access == null) { // class level
metaProperty = null;
} else { // property level
- metaProperty = metabean.getProperty(meta.getAccessStrategy().getPropertyName());
- if (metaProperty == null) {
- metaProperty =
- addMetaProperty(metabean, meta.getAccessStrategy().getPropertyName(), meta.getAccessStrategy()
- .getJavaType());
+ metaProperty = metabean.getProperty(access.getPropertyName());
+ create = metaProperty == null;
+ if (create) {
+ metaProperty = addMetaProperty(metabean, access);
}
}
- annotationProcessor.processAnnotation(meta.getAnnotation(), metaProperty, beanClass, meta
- .getAccessStrategy(), new AppendValidationToMeta(metaProperty == null ? metabean : metaProperty));
+ if (!annotationProcessor.processAnnotation(meta.getAnnotation(), metaProperty, beanClass,
+ meta.getAccessStrategy(), new AppendValidationToMeta(metaProperty == null ? metabean : metaProperty))
+ && create) {
+ metabean.putProperty(access.getPropertyName(), null);
+ }
}
for (AccessStrategy access : factoryContext.getFactory().getValidAccesses(beanClass)) {
MetaProperty metaProperty = metabean.getProperty(access.getPropertyName());
- if (metaProperty == null) {
- metaProperty = addMetaProperty(metabean, access.getPropertyName(), access.getJavaType());
+ boolean create = metaProperty == null;
+ if (create) {
+ metaProperty = addMetaProperty(metabean, access);
+ }
+ if (!annotationProcessor.addAccessStrategy(metaProperty, access) && create) {
+ metabean.putProperty(access.getPropertyName(), null);
}
- annotationProcessor.addAccessStrategy(metaProperty, access);
}
}
@@ -268,13 +279,19 @@ public class Jsr303MetaBeanFactory imple
log.debug("Default group sequence for bean {} is: {}", beanClass.getName(), groupSeq);
}
- private static MetaProperty addMetaProperty(MetaBean parentMetaBean, String propName, Type type) {
- MetaProperty metaProperty;
- metaProperty = new MetaProperty();
- metaProperty.setName(propName);
- metaProperty.setType(type);
- parentMetaBean.putProperty(propName, metaProperty);
- return metaProperty;
+ /**
+ * Add a {@link MetaProperty} to a {@link MetaBean}.
+ * @param parentMetaBean
+ * @param access
+ * @return the created {@link MetaProperty}
+ */
+ public static MetaProperty addMetaProperty(MetaBean parentMetaBean, AccessStrategy access) {
+ final MetaProperty result = new MetaProperty();
+ final String name = access.getPropertyName();
+ result.setName(name);
+ result.setType(access.getJavaType());
+ parentMetaBean.putProperty(name, result);
+ return result;
}
}
Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/ValidationContextTraversal.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/ValidationContextTraversal.java?rev=1071712&r1=1071711&r2=1071712&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/ValidationContextTraversal.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/ValidationContextTraversal.java Thu Feb 17 17:28:16 2011
@@ -19,6 +19,7 @@ package org.apache.bval.jsr303.util;
import java.lang.reflect.Type;
import org.apache.bval.DynamicMetaBean;
+import org.apache.bval.jsr303.Jsr303MetaBeanFactory;
import org.apache.bval.jsr303.UnknownPropertyException;
import org.apache.bval.jsr303.util.PathNavigation.CallbackProcedure;
import org.apache.bval.model.MetaBean;
@@ -122,7 +123,13 @@ public class ValidationContextTraversal
}
MetaProperty mp = metaBean.getProperty(token);
if (mp == null) {
- throw new UnknownPropertyException("unknown property '" + token + "' in " + metaBean.getId());
+ PropertyAccess access = new PropertyAccess(rawType, token);
+ if (access.isKnown()) {
+ // add heretofore unknown, but valid, property on the fly:
+ mp = Jsr303MetaBeanFactory.addMetaProperty(metaBean, access);
+ } else {
+ throw new UnknownPropertyException("unknown property '" + token + "' in " + metaBean.getId());
+ }
}
validationContext.setMetaProperty(mp);
setType(mp.getType());
@@ -169,7 +176,7 @@ public class ValidationContextTraversal
public Type getType() {
return type;
}
-
+
/**
* @return the rawType
*/