From f544df0b2c65ab0118da5be3ab1c7d59cb5975ff Mon Sep 17 00:00:00 2001
From: Artur Signell
@@ -659,9 +688,9 @@ public class FieldGroup implements Serializable {
*
*
*
+ * This method processes all (Java) member 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. Fields that are not initialized (null) are built
+ * using the field factory. All non-null fields for which a property id can
+ * be determined are bound to the property id.
+ *
+ * For example:
+ *
+ *
+ * public class MyForm extends VerticalLayout {
+ * private TextField firstName = new TextField("First name");
+ * @PropertyId("last")
+ * private TextField lastName = new TextField("Last name");
+ * private TextField age;
+ *
+ * MyForm myForm = new MyForm();
+ * ...
+ * fieldGroup.buildAndBindMemberFields(myForm);
+ *
+ *
+ *
+ * This binds the firstName TextField to a "firstName" property in the item, + * lastName TextField to a "last" property and builds an age TextField using + * the field factory and then binds it to the "age" property. + *
+ * + * @param objectWithMemberFields + * The object that contains (Java) member fields to build and + * bind + * @throws BindException + * If there is a problem binding or building a field + */ + public void buildAndBindMemberFields(Object objectWithMemberFields) + throws BindException { + buildAndBindMemberFields(objectWithMemberFields, true); + } + + /** + * Binds member fields found in the given object and optionally builds + * member fields that have not been initialized. + *+ * This method processes all (Java) member 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. Fields that are not initialized (null) are built + * using the field factory is buildFields is true. All non-null fields for + * which a property id can be determined are bound to the property id. + *
+ * + * @param objectWithMemberFields + * The object that contains (Java) member fields to build and + * bind + * @throws BindException + * If there is a problem binding or building a field + */ + protected void buildAndBindMemberFields(Object objectWithMemberFields, + boolean buildFields) throws BindException { Class> objectClass = objectWithMemberFields.getClass(); - for (java.lang.reflect.Field f : objectClass.getDeclaredFields()) { + for (java.lang.reflect.Field memberField : objectClass + .getDeclaredFields()) { - if (!Field.class.isAssignableFrom(f.getType())) { + if (!Field.class.isAssignableFrom(memberField.getType())) { // Process next field continue; } - PropertyId propertyIdAnnotation = f.getAnnotation(PropertyId.class); + PropertyId propertyIdAnnotation = memberField + .getAnnotation(PropertyId.class); - Class extends Field> fieldType = (Class extends Field>) f + Class extends Field> fieldType = (Class extends Field>) memberField .getType(); Object propertyId = null; @@ -689,7 +787,7 @@ public class FieldGroup implements Serializable { // @PropertyId(propertyId) always overrides property id propertyId = propertyIdAnnotation.value(); } else { - propertyId = f.getName(); + propertyId = memberField.getName(); } // Ensure that the property id exists @@ -702,18 +800,51 @@ public class FieldGroup implements Serializable { continue; } + Field> field; try { // Get the field from the object - Field> field = (Field>) ReflectTools.getJavaFieldValue( - objectWithMemberFields, f); - // Bind it to the property id - bind(field, propertyId); + field = (Field>) ReflectTools.getJavaFieldValue( + objectWithMemberFields, memberField); } catch (Exception e) { // If we cannot determine the value, just skip the field and try // the next one continue; } + if (field == null && buildFields) { + Caption captionAnnotation = memberField + .getAnnotation(Caption.class); + String caption; + if (captionAnnotation != null) { + caption = captionAnnotation.value(); + } else { + caption = DefaultFieldFactory + .createCaptionByPropertyId(propertyId); + } + + // Create the component (Field) + field = build(caption, propertyType, fieldType); + + // Store it in the field + try { + ReflectTools.setJavaFieldValue(objectWithMemberFields, + memberField, field); + } catch (IllegalArgumentException e) { + throw new BindException("Could not assign value to field '" + + memberField.getName() + "'", e); + } catch (IllegalAccessException e) { + throw new BindException("Could not assign value to field '" + + memberField.getName() + "'", e); + } catch (InvocationTargetException e) { + throw new BindException("Could not assign value to field '" + + memberField.getName() + "'", e); + } + } + + if (field != null) { + // Bind it to the property id + bind(field, propertyId); + } } } @@ -752,4 +883,96 @@ public class FieldGroup implements Serializable { } } -} + + /** + * Builds a field and binds it to the given property id using the field + * binder. + * + * @param propertyId + * The property id to bind to. Must be present in the field + * finder. + * @throws BindException + * If there is a problem while building or binding + * @return The created and bound field + */ + public Field> buildAndBind(Object propertyId) throws BindException { + String caption = DefaultFieldFactory + .createCaptionByPropertyId(propertyId); + return buildAndBind(caption, propertyId); + } + + /** + * Builds a field using the given caption and binds it to the given property + * id using the field binder. + * + * @param caption + * The caption for the field + * @param propertyId + * The property id to bind to. Must be present in the field + * finder. + * @throws BindException + * If there is a problem while building or binding + * @return The created and bound field. Can be any type of {@link Field}. + */ + public Field> buildAndBind(String caption, Object propertyId) + throws BindException { + Class> type = getPropertyType(propertyId); + return buildAndBind(caption, propertyId, Field.class); + + } + + /** + * Builds a field using the given caption and binds it to the given property + * id using the field binder. Ensures the new field is of the given type. + * + * @param caption + * The caption for the field + * @param propertyId + * The property id to bind to. Must be present in the field + * finder. + * @throws BindException + * If the field could not be created + * @return The created and bound field. Can be any type of {@link Field}. + */ + + public+ * The data type is the type that we want to edit using the field. The field + * type is the type of field we want to create, can be {@link Field} if any + * Field is good. + *
+ * + * @param caption + * The caption for the new field + * @param dataType + * The data model type that we want to edit using the field + * @param fieldType + * The type of field that we want to create + * @return A Field capable of editing the given type + * @throws BindException + * If the field could not be created + */ + protected
- *
- * FIXME Javadoc
- */
-public class FormBuilder implements Serializable {
-
- private FormBuilderFieldFactory fieldFactory = new DefaultFormBuilderFieldFactory();
- private FieldGroup fieldBinder;
- private static final Logger logger = Logger.getLogger(FormBuilder.class
- .getName());
-
- /**
- * Constructs a FormBuilder that can be used to build forms automatically.
- *
- * @param fieldBinder
- * The FieldBinder to use for binding the fields to the data
- * source
- */
- public FormBuilder(FieldGroup fieldBinder) {
- this.fieldBinder = fieldBinder;
- }
-
- /**
- * TODO: javadoc
- */
- protected FieldGroup getFieldBinder() {
- return fieldBinder;
- }
-
- /**
- * TODO: javadoc
- */
- public FormBuilderFieldFactory getFieldFactory() {
- return fieldFactory;
- }
-
- /**
- * TODO: javadoc
- */
- public void setFieldFactory(FormBuilderFieldFactory fieldFactory) {
- this.fieldFactory = fieldFactory;
- }
-
- /**
- * Builds a field and binds it to the given property id using the field
- * binder.
- *
- * @param propertyId
- * The property id to bind to. Must be present in the field
- * finder.
- * @return The created and bound field
- */
- public Field> buildAndBind(Object propertyId) {
- String caption = DefaultFieldFactory
- .createCaptionByPropertyId(propertyId);
- return buildAndBind(caption, propertyId);
- }
-
- /**
- * Builds a field using the given caption and binds it to the given property
- * id using the field binder.
- *
- * @param caption
- * The caption for the field
- * @param propertyId
- * The property id to bind to. Must be present in the field
- * finder.
- * @return The created and bound field. Can be any type of {@link Field}.
- */
- public Field> buildAndBind(String caption, Object propertyId) {
- Class> type = getFieldBinder().getPropertyType(propertyId);
- return buildAndBind(caption, propertyId, type, Field.class);
-
- }
-
- /**
- * Builds a field using the given caption and binds it to the given property
- * id using the field binder. Ensures the new field is of the given type.
- *
- * @param caption
- * The caption for the field
- * @param propertyId
- * The property id to bind to. Must be present in the field
- * finder.
- * @return The created and bound field. Can be any type of {@link Field}.
- */
- public
- * The data type is the type that we want to edit using the field. The field
- * type is the type of field we want to create, can be {@link Field} if any
- * Field is good.
- *
- * 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
- * @throws FormBuilderException
- * If there is a problem building or binding a field
- */
- public void buildAndBindFields(Object object) throws FormBuilderException {
- Class> objectClass = object.getClass();
-
- for (java.lang.reflect.Field f : objectClass.getDeclaredFields()) {
- PropertyId propertyIdAnnotation = f.getAnnotation(PropertyId.class);
-
- if (!Field.class.isAssignableFrom(f.getType())) {
- // Process next field
- continue;
- }
- Class extends Field> fieldType = (Class extends Field>) 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 = fieldBinder.getPropertyType(propertyId);
- } catch (BindException e) {
- // Property id was not found, skip this field
- continue;
- }
-
- Field> builtField;
- try {
- 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) {
- // Field is null -> build the field
- Caption captionAnnotation = f.getAnnotation(Caption.class);
- String caption;
- if (captionAnnotation != null) {
- caption = captionAnnotation.value();
- } else {
- caption = DefaultFieldFactory
- .createCaptionByPropertyId(propertyId);
- }
-
- // Create the component (Field)
- builtField = build(caption, propertyType, fieldType);
-
- // Store it in the field
- try {
- ReflectTools.setJavaFieldValue(object, f, builtField);
- } catch (IllegalArgumentException e) {
- throw new BuildException(
- "Could not assign value to field '" + f.getName()
- + "'", e);
- } catch (IllegalAccessException e) {
- throw new BuildException(
- "Could not assign value to field '" + f.getName()
- + "'", e);
- } catch (InvocationTargetException e) {
- throw new BuildException(
- "Could not assign value to field '" + f.getName()
- + "'", e);
- }
- }
-
- // Bind it to the property id
- if (builtField != null) {
- fieldBinder.bind(builtField, propertyId);
- }
-
- }
- }
-
- public static class FormBuilderException extends RuntimeException {
-
- public FormBuilderException() {
- super();
- // TODO Auto-generated constructor stub
- }
-
- public FormBuilderException(String message, Throwable cause) {
- super(message, cause);
- // TODO Auto-generated constructor stub
- }
-
- public FormBuilderException(String message) {
- super(message);
- // TODO Auto-generated constructor stub
- }
-
- public FormBuilderException(Throwable cause) {
- super(cause);
- // TODO Auto-generated constructor stub
- }
-
- }
-
- public static class BuildException extends RuntimeException {
-
- public BuildException(String message) {
- super(message);
- }
-
- public BuildException(String message, Throwable t) {
- super(message, t);
- }
-
- }
-
-}
diff --git a/tests/testbench/com/vaadin/tests/fieldbinder/BasicPersonForm.java b/tests/testbench/com/vaadin/tests/fieldbinder/BasicPersonForm.java
index 0a6fa40b3a..dd3f201f49 100644
--- a/tests/testbench/com/vaadin/tests/fieldbinder/BasicPersonForm.java
+++ b/tests/testbench/com/vaadin/tests/fieldbinder/BasicPersonForm.java
@@ -5,7 +5,6 @@ import com.vaadin.data.fieldbinder.FieldGroup;
import com.vaadin.data.fieldbinder.FieldGroup.CommitEvent;
import com.vaadin.data.fieldbinder.FieldGroup.CommitException;
import com.vaadin.data.fieldbinder.FieldGroup.CommitHandler;
-import com.vaadin.data.fieldbinder.FormBuilder;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.converter.StringToBooleanConverter;
import com.vaadin.data.validator.EmailValidator;
@@ -65,13 +64,12 @@ public class BasicPersonForm extends TestBase {
super("Configuration");
BeanItem