From: Artur Signell Date: Mon, 19 Dec 2011 13:41:10 +0000 (+0200) Subject: #8095 Allow binding all fields in a class using FieldBinder instead of X-Git-Tag: 7.0.0.alpha1~100 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=dd6a5e5b25c5e297dfd45851f820bedb4661e410;p=vaadin-framework.git #8095 Allow binding all fields in a class using FieldBinder instead of FormBuilder --- diff --git a/src/com/vaadin/data/fieldbinder/FieldBinder.java b/src/com/vaadin/data/fieldbinder/FieldBinder.java index 78c2b6c8fb..39045df96f 100644 --- a/src/com/vaadin/data/fieldbinder/FieldBinder.java +++ b/src/com/vaadin/data/fieldbinder/FieldBinder.java @@ -16,7 +16,9 @@ import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.TransactionalProperty; import com.vaadin.data.Validator.InvalidValueException; +import com.vaadin.data.fieldbinder.FormBuilder.FormBuilderException; import com.vaadin.data.util.TransactionalPropertyWrapper; +import com.vaadin.tools.ReflectTools; import com.vaadin.ui.Field; /** @@ -620,6 +622,68 @@ public class FieldBinder implements Serializable { return false; } + /** + * Binds fields for the given class. + *

+ * This method processes all fields whose type extends {@link Field} and + * that can be mapped to a property id. Property id mapping is done based on + * the field name or on a {@link PropertyId} annotation on the field. All + * non-null fields for which a property id can be determined are bound to + * the property id. + * + * @param object + * The object to process + * @throws FormBuilderException + * If there is a problem building or binding a field + */ + public void bindFields(Object object) throws BindException { + Class objectClass = object.getClass(); + + for (java.lang.reflect.Field f : objectClass.getDeclaredFields()) { + + if (!Field.class.isAssignableFrom(f.getType())) { + // Process next field + continue; + } + + PropertyId propertyIdAnnotation = f.getAnnotation(PropertyId.class); + + Class fieldType = (Class) f + .getType(); + + Object propertyId = null; + if (propertyIdAnnotation != null) { + // @PropertyId(propertyId) always overrides property id + propertyId = propertyIdAnnotation.value(); + } else { + propertyId = f.getName(); + } + + // Ensure that the property id exists + Class propertyType; + + try { + propertyType = getPropertyType(propertyId); + } catch (BindException e) { + // Property id was not found, skip this field + continue; + } + + try { + // Get the field from the object + Field field = (Field) ReflectTools.getJavaFieldValue( + object, f); + // Bind it to the property id + bind(field, propertyId); + } catch (Exception e) { + // If we cannot determine the value, just skip the field and try + // the next one + continue; + } + + } + } + public static class CommitException extends Exception { public CommitException() { diff --git a/src/com/vaadin/data/fieldbinder/FormBuilder.java b/src/com/vaadin/data/fieldbinder/FormBuilder.java index 2dc567570e..c5f88185b1 100644 --- a/src/com/vaadin/data/fieldbinder/FormBuilder.java +++ b/src/com/vaadin/data/fieldbinder/FormBuilder.java @@ -3,16 +3,13 @@ */ package com.vaadin.data.fieldbinder; -import java.beans.IntrospectionException; -import java.beans.PropertyDescriptor; import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.logging.Logger; import org.apache.tools.ant.BuildException; import com.vaadin.data.fieldbinder.FieldBinder.BindException; +import com.vaadin.tools.ReflectTools; import com.vaadin.ui.DefaultFieldFactory; import com.vaadin.ui.Field; @@ -162,29 +159,6 @@ public class FormBuilder implements Serializable { * If there is a problem building or binding a field */ public void buildAndBindFields(Object object) throws FormBuilderException { - buildAndBindFields(object, false); - } - - /** - * Builds and binds fields for the given class. - *

- * This method processes all fields whose type extends {@link Field} and - * that can be mapped to a property id. Property id mapping is done based on - * the field name or on a {@link PropertyId} annotation on the field. All - * fields for which a property id can be determined are built if they are - * null and then bound to the property id. Also existing fields are bound to - * the corresponding property id. - * - * @param object - * The object to process - * @param onlyBind - * true if only binding should be done, false if also building - * should be done when necessary - * @throws FormBuilderException - * If there is a problem building or binding a field - */ - public void buildAndBindFields(Object object, boolean onlyBind) - throws FormBuilderException { Class objectClass = object.getClass(); for (java.lang.reflect.Field f : objectClass.getDeclaredFields()) { @@ -217,14 +191,15 @@ public class FormBuilder implements Serializable { Field builtField; try { - builtField = (Field) getJavaFieldValue(object, f); + builtField = (Field) ReflectTools.getJavaFieldValue(object, + f); } catch (Exception e) { // If we cannot determine the value, just skip the field and try // the next one continue; } - if (builtField == null && !onlyBind) { + if (builtField == null) { // Field is null -> build the field Caption captionAnnotation = f.getAnnotation(Caption.class); String caption; @@ -234,10 +209,12 @@ public class FormBuilder implements Serializable { caption = DefaultFieldFactory .createCaptionByPropertyId(propertyId); } + // Create the component (Field) builtField = build(caption, propertyType, fieldType); + // Store it in the field - setJavaFieldValue(object, f, builtField); + ReflectTools.setJavaFieldValue(object, f, builtField); } // Bind it to the property id @@ -248,132 +225,6 @@ public class FormBuilder implements Serializable { } } - /** - * Returns the value of the java field. - *

- * Uses getter if present, otherwise tries to access even private fields. - * - * @param object - * The object containing the field - * @param field - * The field we want to get the value for - * @return The value of the field in the object - * @throws FormBuilderException - * If the field value cannot be determined - */ - protected Object getJavaFieldValue(Object object, - java.lang.reflect.Field field) throws FormBuilderException { - PropertyDescriptor pd; - try { - pd = new PropertyDescriptor(field.getName(), object.getClass()); - Method getter = pd.getReadMethod(); - if (getter != null) { - return getter.invoke(object, (Object[]) null); - } - } catch (Exception e) { - // Ignore all problems with getter and try to get the value directly - // from the field - } - - try { - if (!field.isAccessible()) { - // Try to gain access even if field is private - field.setAccessible(true); - } - return field.get(object); - } catch (IllegalArgumentException e) { - throw new FormBuilderException("Could not get value for field '" - + field.getName() + "'", e.getCause()); - } catch (IllegalAccessException e) { - throw new FormBuilderException( - "Access denied while assigning built component to field '" - + field.getName() + "' in " - + object.getClass().getName(), e); - } - } - - /** - * Sets the value of a java field. - *

- * Uses setter if present, otherwise tries to access even private fields - * directly. - * - * @param object - * The object containing the field - * @param field - * The field we want to set the value for - * @param value - * The value to set - * @throws FormBuilderException - * If the value could not be assigned to the field - */ - protected void setJavaFieldValue(Object object, - java.lang.reflect.Field field, Object value) - throws FormBuilderException { - PropertyDescriptor pd; - try { - pd = new PropertyDescriptor(field.getName(), object.getClass()); - Method setter = pd.getWriteMethod(); - if (setter != null) { - try { - setter.invoke(object, value); - } catch (IllegalArgumentException e) { - throw new FormBuilderException( - "Could not assign built component to field '" - + field.getName() + "'", e); - } catch (IllegalAccessException e) { - throw new FormBuilderException( - "Access denied while assigning built component to field using " - + setter.getName() + " in " - + object.getClass().getName(), e); - } catch (InvocationTargetException e) { - throw new FormBuilderException( - "Could not assign built component to field '" - + field.getName() + "'", e.getCause()); - } - } - } catch (IntrospectionException e1) { - // Ignore this and try to set directly using the field - } - - try { - if (!field.isAccessible()) { - // Try to gain access even if field is private - field.setAccessible(true); - } - field.set(object, value); - } catch (IllegalArgumentException e) { - throw new FormBuilderException( - "Could not assign built component to field '" - + field.getName() + "'", e.getCause()); - } catch (IllegalAccessException e) { - throw new FormBuilderException( - "Access denied while assigning built component to field '" - + field.getName() + "' in " - + object.getClass().getName(), e); - } - } - - // /** - // * Constructs fields for all properties in the data source and adds them - // to - // * the given component container. The order of the fields is determined by - // * the order in which the item returns its property ids. - // * - // * This is pretty much what the old Form class used to do. - // * - // * @param cc - // * The ComponentContainer where fields should be added. - // */ - // public void buildAndBindEverything(ComponentContainer cc) { - // Item ds = getFieldBinder().getItemDataSource(); - // for (Object propertyId : ds.getItemPropertyIds()) { - // Field f = buildAndBind(propertyId); - // cc.addComponent(f); - // } - // - // } - public static class FormBuilderException extends RuntimeException { public FormBuilderException() { diff --git a/src/com/vaadin/tools/ReflectTools.java b/src/com/vaadin/tools/ReflectTools.java index 9f0667f90e..03c5b8be92 100644 --- a/src/com/vaadin/tools/ReflectTools.java +++ b/src/com/vaadin/tools/ReflectTools.java @@ -3,8 +3,13 @@ */ package com.vaadin.tools; +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import com.vaadin.data.fieldbinder.FormBuilder.FormBuilderException; + /** * An util class with helpers for reflection operations. Used internally by * Vaadin and should not be used by application developers. Subject to change at @@ -37,4 +42,110 @@ public class ReflectTools { throw new ExceptionInInitializerError(e); } } + + /** + * Returns the value of the java field. + *

+ * Uses getter if present, otherwise tries to access even private fields + * directly. + * + * @param object + * The object containing the field + * @param field + * The field we want to get the value for + * @return The value of the field in the object + * @throws FormBuilderException + * If the field value cannot be determined + */ + public static Object getJavaFieldValue(Object object, + java.lang.reflect.Field field) throws FormBuilderException { + PropertyDescriptor pd; + try { + pd = new PropertyDescriptor(field.getName(), object.getClass()); + Method getter = pd.getReadMethod(); + if (getter != null) { + return getter.invoke(object, (Object[]) null); + } + } catch (Exception e) { + // Ignore all problems with getter and try to get the value directly + // from the field + } + + try { + if (!field.isAccessible()) { + // Try to gain access even if field is private + field.setAccessible(true); + } + return field.get(object); + } catch (IllegalArgumentException e) { + throw new FormBuilderException("Could not get value for field '" + + field.getName() + "'", e.getCause()); + } catch (IllegalAccessException e) { + throw new FormBuilderException( + "Access denied while assigning built component to field '" + + field.getName() + "' in " + + object.getClass().getName(), e); + } + } + + /** + * Sets the value of a java field. + *

+ * Uses setter if present, otherwise tries to access even private fields + * directly. + * + * @param object + * The object containing the field + * @param field + * The field we want to set the value for + * @param value + * The value to set + * @throws FormBuilderException + * If the value could not be assigned to the field + */ + public static void setJavaFieldValue(Object object, + java.lang.reflect.Field field, Object value) + throws FormBuilderException { + PropertyDescriptor pd; + try { + pd = new PropertyDescriptor(field.getName(), object.getClass()); + Method setter = pd.getWriteMethod(); + if (setter != null) { + try { + setter.invoke(object, value); + } catch (IllegalArgumentException e) { + throw new FormBuilderException( + "Could not assign value to field '" + + field.getName() + "'", e); + } catch (IllegalAccessException e) { + throw new FormBuilderException( + "Access denied while assigning value to field using " + + setter.getName() + " in " + + object.getClass().getName(), e); + } catch (InvocationTargetException e) { + throw new FormBuilderException( + "Could not assign value to field '" + + field.getName() + "'", e.getCause()); + } + } + } catch (IntrospectionException e1) { + // Ignore this and try to set directly using the field + } + + try { + if (!field.isAccessible()) { + // Try to gain access even if field is private + field.setAccessible(true); + } + field.set(object, value); + } catch (IllegalArgumentException e) { + throw new FormBuilderException("Could not assign value to field '" + + field.getName() + "'", e.getCause()); + } catch (IllegalAccessException e) { + throw new FormBuilderException( + "Access denied while assigning value to field '" + + field.getName() + "' in " + + object.getClass().getName(), e); + } + } }