summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin
diff options
context:
space:
mode:
authorMatti Hosio <mhosio@vaadin.com>2013-07-15 15:56:07 +0300
committerVaadin Code Review <review@vaadin.com>2013-08-09 08:13:00 +0000
commit9f126db566b14afaa8e025056539a38a5d7b9904 (patch)
treeb25d791c4c8a8ddacaf0d85d12cb796ceeb4a4a6 /server/src/com/vaadin
parent437b6de4eea416317bd79399a5dde9870b306975 (diff)
downloadvaadin-framework-9f126db566b14afaa8e025056539a38a5d7b9904.tar.gz
vaadin-framework-9f126db566b14afaa8e025056539a38a5d7b9904.zip
Support for null intermediate beans in NestedMethodProperty (#11435)
Allows intermediate beans to return null in the NestedMethodProperty. The feature is not enabled by default and thus should be fully backwards compatible. Change-Id: I438d0f787c5c76f61ab234f3c92dd927a8354a37
Diffstat (limited to 'server/src/com/vaadin')
-rw-r--r--server/src/com/vaadin/data/util/AbstractBeanContainer.java57
-rw-r--r--server/src/com/vaadin/data/util/BeanItem.java21
-rw-r--r--server/src/com/vaadin/data/util/NestedMethodProperty.java59
-rw-r--r--server/src/com/vaadin/data/util/NestedPropertyDescriptor.java24
4 files changed, 156 insertions, 5 deletions
diff --git a/server/src/com/vaadin/data/util/AbstractBeanContainer.java b/server/src/com/vaadin/data/util/AbstractBeanContainer.java
index 35403d6419..cd5c0c809d 100644
--- a/server/src/com/vaadin/data/util/AbstractBeanContainer.java
+++ b/server/src/com/vaadin/data/util/AbstractBeanContainer.java
@@ -845,8 +845,32 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
* @return true if the property was added
*/
public boolean addNestedContainerProperty(String propertyId) {
+ return addNestedContainerProperty(propertyId, false);
+ }
+
+ /**
+ * Adds a nested container property for the container, e.g.
+ * "manager.address.street".
+ *
+ * All intermediate getters must exist and must return non-null values when
+ * the property value is accessed or the <code>nullBeansAllowed</code> must
+ * be set to true. If the <code>nullBeansAllowed</code> flag is set to true,
+ * calling getValue of the added property will return null if the property
+ * or any of its intermediate getters returns null. If set to false, null
+ * values returned by intermediate getters will cause NullPointerException.
+ * The default value is false to ensure backwards compatibility.
+ *
+ * @see NestedMethodProperty
+ *
+ * @param propertyId
+ * @param nullBeansAllowed
+ * set true to allow null values from intermediate getters
+ * @return true if the property was added
+ */
+ public boolean addNestedContainerProperty(String propertyId,
+ boolean nullBeansAllowed) {
return addContainerProperty(propertyId, new NestedPropertyDescriptor(
- propertyId, type));
+ propertyId, type, nullBeansAllowed));
}
/**
@@ -864,13 +888,42 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
*/
@SuppressWarnings("unchecked")
public void addNestedContainerBean(String propertyId) {
+ addNestedContainerBean(propertyId, false);
+ }
+
+ /**
+ * Adds a nested container properties for all sub-properties of a named
+ * property to the container. The named property itself is removed from the
+ * model as its subproperties are added.
+ *
+ * Unless
+ * <code>nullBeansAllowed<code> is set to true, all intermediate getters must
+ * exist and must return non-null values when the property values are
+ * accessed. If the <code>nullBeansAllowed</code> flag is set to true,
+ * calling getValue of the added subproperties will return null if the
+ * property or any of their intermediate getters returns null. If set to
+ * false, null values returned by intermediate getters will cause
+ * NullPointerException. The default value is false to ensure backwards
+ * compatibility.
+ *
+ * @see NestedMethodProperty
+ * @see #addNestedContainerProperty(String)
+ *
+ * @param propertyId
+ * @param nullBeansAllowed
+ * set true to allow null values from intermediate getters
+ */
+ @SuppressWarnings("unchecked")
+ public void addNestedContainerBean(String propertyId,
+ boolean nullBeansAllowed) {
Class<?> propertyType = getType(propertyId);
LinkedHashMap<String, VaadinPropertyDescriptor<Object>> pds = BeanItem
.getPropertyDescriptors((Class<Object>) propertyType);
for (String subPropertyId : pds.keySet()) {
String qualifiedPropertyId = propertyId + "." + subPropertyId;
NestedPropertyDescriptor<BEANTYPE> pd = new NestedPropertyDescriptor<BEANTYPE>(
- qualifiedPropertyId, (Class<BEANTYPE>) type);
+ qualifiedPropertyId, (Class<BEANTYPE>) type,
+ nullBeansAllowed);
model.put(qualifiedPropertyId, pd);
model.remove(propertyId);
for (BeanItem<BEANTYPE> item : itemIdToItem.values()) {
diff --git a/server/src/com/vaadin/data/util/BeanItem.java b/server/src/com/vaadin/data/util/BeanItem.java
index fc51be8f36..4834fe4f89 100644
--- a/server/src/com/vaadin/data/util/BeanItem.java
+++ b/server/src/com/vaadin/data/util/BeanItem.java
@@ -268,6 +268,27 @@ public class BeanItem<BT> extends PropertysetItem {
}
/**
+ * Adds a nested property to the item. If the <code>nullBeansAllowed</code>
+ * flag is set to true, calling getValue of the added property will return
+ * null if the property or any of its intermediate getters returns null. If
+ * set to false, null values returned by intermediate getters will cause
+ * NullPointerException. The default value is false to ensure backwards
+ * compatibility.
+ *
+ * @param nestedPropertyId
+ * property id to add. This property must not exist in the item
+ * already and must of of form "field1.field2" where field2 is a
+ * field in the object referenced to by field1
+ * @param nullBeansAllowed
+ * set true to allow null values from intermediate getters
+ */
+ public void addNestedProperty(String nestedPropertyId,
+ boolean nullBeansAllowed) {
+ addItemProperty(nestedPropertyId, new NestedMethodProperty<Object>(
+ getBean(), nestedPropertyId, nullBeansAllowed));
+ }
+
+ /**
* Gets the underlying JavaBean object.
*
* @return the bean object.
diff --git a/server/src/com/vaadin/data/util/NestedMethodProperty.java b/server/src/com/vaadin/data/util/NestedMethodProperty.java
index b62ecfbfc3..7a3963c17e 100644
--- a/server/src/com/vaadin/data/util/NestedMethodProperty.java
+++ b/server/src/com/vaadin/data/util/NestedMethodProperty.java
@@ -32,7 +32,7 @@ import com.vaadin.data.util.MethodProperty.MethodException;
* can contain multiple levels of nesting.
*
* When accessing the property value, all intermediate getters must return
- * non-null values.
+ * non-null values or the <code>nullBeansAllowed</code> must be set to true.
*
* @see MethodProperty
*
@@ -55,6 +55,15 @@ public class NestedMethodProperty<T> extends AbstractProperty<T> {
*/
private Object instance;
+ /**
+ * a boolean flag indicating whether intermediate getters may return null
+ * values. If the flag is set to true, calling getValue will return null if
+ * the property or any of its intermediate getters returns null. If set to
+ * false, intermediate getters returning null value will throw Exception.
+ * The default value is false to ensure backwards compatibility.
+ */
+ private boolean nullBeansAllowed = false;
+
private Class<? extends T> type;
/* Special serialization to handle method references */
@@ -85,7 +94,33 @@ public class NestedMethodProperty<T> extends AbstractProperty<T> {
* if the property name is invalid
*/
public NestedMethodProperty(Object instance, String propertyName) {
+ this(instance, propertyName, false);
+ }
+
+ /**
+ * Constructs a nested method property for a given object instance. The
+ * property name is a dot separated string pointing to a nested property,
+ * e.g. "manager.address.street". The <code>nullBeansAllowed</code> controls
+ * the behavior in cases where the intermediate getters may return null
+ * values. If the flag is set to true, calling getValue will return null if
+ * the property or any of its intermediate getters returns null. If set to
+ * false, null values returned by intermediate getters will cause
+ * NullPointerException. The default value is false to ensure backwards
+ * compatibility.
+ *
+ * @param instance
+ * top-level bean to which the property applies
+ * @param propertyName
+ * dot separated nested property name
+ * @param nullBeansAllowed
+ * set true to allow null values from intermediate getters
+ * @throws IllegalArgumentException
+ * if the property name is invalid
+ */
+ public NestedMethodProperty(Object instance, String propertyName,
+ boolean nullBeansAllowed) {
this.instance = instance;
+ this.nullBeansAllowed = nullBeansAllowed;
initialize(instance.getClass(), propertyName);
}
@@ -104,6 +139,25 @@ public class NestedMethodProperty<T> extends AbstractProperty<T> {
}
/**
+ * For internal use to deduce property type etc. without a bean instance.
+ * Calling {@link #setValue(Object)} or {@link #getValue()} on properties
+ * constructed this way is not supported.
+ *
+ * @param instanceClass
+ * class of the top-level bean
+ * @param propertyName
+ * dot separated nested property name
+ * @param nullBeansAllowed
+ * set true to allow null values from intermediate getters
+ */
+ NestedMethodProperty(Class<?> instanceClass, String propertyName,
+ boolean nullBeansAllowed) {
+ instance = null;
+ this.nullBeansAllowed = nullBeansAllowed;
+ initialize(instanceClass, propertyName);
+ }
+
+ /**
* Initializes most of the internal fields based on the top-level bean
* instance and property name (dot-separated string).
*
@@ -199,6 +253,9 @@ public class NestedMethodProperty<T> extends AbstractProperty<T> {
Object object = instance;
for (Method m : getMethods) {
object = m.invoke(object);
+ if (object == null && nullBeansAllowed) {
+ return null;
+ }
}
return (T) object;
} catch (final Throwable e) {
diff --git a/server/src/com/vaadin/data/util/NestedPropertyDescriptor.java b/server/src/com/vaadin/data/util/NestedPropertyDescriptor.java
index b2055fe776..67eb30fae5 100644
--- a/server/src/com/vaadin/data/util/NestedPropertyDescriptor.java
+++ b/server/src/com/vaadin/data/util/NestedPropertyDescriptor.java
@@ -34,6 +34,7 @@ public class NestedPropertyDescriptor<BT> implements
private final String name;
private final Class<?> propertyType;
+ private final boolean nullBeansAllowed;
/**
* Creates a property descriptor that can create MethodProperty instances to
@@ -48,10 +49,29 @@ public class NestedPropertyDescriptor<BT> implements
*/
public NestedPropertyDescriptor(String name, Class<BT> beanType)
throws IllegalArgumentException {
+ this(name, beanType, false);
+ }
+
+ /**
+ * Creates a property descriptor that can create MethodProperty instances to
+ * access the underlying bean property.
+ *
+ * @param name
+ * of the property in a dotted path format, e.g. "address.street"
+ * @param beanType
+ * type (class) of the top-level bean
+ * @param nullBeansAllowed
+ * set true to allow null values from intermediate getters
+ * @throws IllegalArgumentException
+ * if the property name is invalid
+ */
+ public NestedPropertyDescriptor(String name, Class<BT> beanType,
+ boolean nullBeansAllowed) throws IllegalArgumentException {
this.name = name;
NestedMethodProperty<?> property = new NestedMethodProperty<Object>(
- beanType, name);
+ beanType, name, nullBeansAllowed);
this.propertyType = property.getType();
+ this.nullBeansAllowed = nullBeansAllowed;
}
@Override
@@ -66,7 +86,7 @@ public class NestedPropertyDescriptor<BT> implements
@Override
public Property<?> createProperty(BT bean) {
- return new NestedMethodProperty<Object>(bean, name);
+ return new NestedMethodProperty<Object>(bean, name, nullBeansAllowed);
}
}