From 0ab1d01c8da1f280370452fa2427708fd6de513e Mon Sep 17 00:00:00 2001
From: Henri Sara
Date: Tue, 8 Nov 2011 18:02:55 +0200
Subject: [PATCH] Parameterize Property and Field with the value type.
The interfaces Property and Field and most of their implementations are
now parameterized with the type of their value. The method getValue()
returns the Property type but setValue() takes Object as its parameter.
No implicit conversions between value type and strings are performed in
most locations (fields).
Among others, AbstractTextField, DateField and RichTextArea not have
specific value types and do not accept arbitrary values.
Most locations requiring migration will be visible as compilation
errors, with the exception of some cases where a non-parameterized
Property or Field (or one parametrized with Object) is used.
Not yet done:
- Label
- converters
- setValue() parameterization (causes much more migration effort)
---
src/com/vaadin/data/Property.java | 24 ++++-----
.../data/util/AbstractBeanContainer.java | 10 ++--
.../vaadin/data/util/AbstractProperty.java | 5 +-
src/com/vaadin/data/util/MethodProperty.java | 14 +++---
.../data/util/NestedMethodProperty.java | 13 ++---
src/com/vaadin/data/util/ObjectProperty.java | 13 +++--
.../vaadin/data/util/PropertyFormatter.java | 29 ++++++-----
.../vaadin/data/util/TextFileProperty.java | 6 +--
src/com/vaadin/ui/AbstractField.java | 49 ++++++++++---------
src/com/vaadin/ui/AbstractSelect.java | 3 +-
src/com/vaadin/ui/AbstractTextField.java | 10 ++--
src/com/vaadin/ui/Button.java | 13 ++---
src/com/vaadin/ui/DateField.java | 12 ++---
src/com/vaadin/ui/Field.java | 8 ++-
src/com/vaadin/ui/Form.java | 4 +-
src/com/vaadin/ui/Label.java | 1 +
src/com/vaadin/ui/ProgressIndicator.java | 11 +++--
src/com/vaadin/ui/RichTextArea.java | 6 +--
src/com/vaadin/ui/Slider.java | 9 ++--
.../vaadin/data/util/ObjectPropertyTest.java | 8 ++-
.../data/util/filter/AbstractFilterTest.java | 6 +--
.../validation/TestReadOnlyValidation.java | 2 +-
.../popupview/PopupViewWithRTE.java | 2 +-
.../tests/components/table/FooterClick.java | 2 +-
.../tests/components/table/HeaderClick.java | 2 +-
.../tests/components/table/HugeRowCount.java | 2 +-
.../com/vaadin/tests/tickets/Ticket2119.java | 4 +-
.../com/vaadin/tests/tickets/Ticket2151.java | 20 ++------
.../com/vaadin/tests/tickets/Ticket2998.java | 2 +-
29 files changed, 143 insertions(+), 147 deletions(-)
diff --git a/src/com/vaadin/data/Property.java b/src/com/vaadin/data/Property.java
index 3f0da39514..4e711141e8 100644
--- a/src/com/vaadin/data/Property.java
+++ b/src/com/vaadin/data/Property.java
@@ -30,12 +30,15 @@ import java.io.Serializable;
* needs to be changed through the implementing class.
*
*
+ * @param T
+ * type of values of the property
+ *
* @author IT Mill Ltd
* @version
* @VERSION@
* @since 3.0
*/
-public interface Property extends Serializable {
+public interface Property extends Serializable {
/**
* Gets the value stored in the Property. The returned object is compatible
@@ -43,7 +46,7 @@ public interface Property extends Serializable {
*
* @return the value stored in the Property
*/
- public Object getValue();
+ public T getValue();
/**
* Sets the value of the Property.
@@ -52,26 +55,19 @@ public interface Property extends Serializable {
* missing, one should declare the Property to be in read-only mode and
* throw Property.ReadOnlyException in this function.
*
- * Note : It is not required, but highly recommended to support setting the
- * value also as a String in addition to the native type of the
- * Property (as given by the getType method). If the
- * String conversion fails or is unsupported, the method should
- * throw Property.ConversionException. The string conversion
- * should at least understand the format returned by the
- * toString method of the Property.
*
- * TODO correct this comment as eliminating Property.toString()
+ * Note : Since Vaadin 7.0, setting the value of a non-String property as a
+ * String is no longer supported.
*
* @param newValue
* New value of the Property. This should be assignable to the
- * type returned by getType, but also String type should be
- * supported
+ * type returned by getType
*
* @throws Property.ReadOnlyException
* if the object is in read-only mode
* @throws Property.ConversionException
* if newValue can't be converted into the Property's native
- * type directly or through String
+ * type directly or using a converter
*/
public void setValue(Object newValue) throws Property.ReadOnlyException,
Property.ConversionException;
@@ -85,7 +81,7 @@ public interface Property extends Serializable {
*
* @return type of the Property
*/
- public Class> getType();
+ public Class extends T> getType();
/**
* Tests if the Property is in read-only mode. In read-only mode calls to
diff --git a/src/com/vaadin/data/util/AbstractBeanContainer.java b/src/com/vaadin/data/util/AbstractBeanContainer.java
index b1d0b0672b..c1e1b58b5a 100644
--- a/src/com/vaadin/data/util/AbstractBeanContainer.java
+++ b/src/com/vaadin/data/util/AbstractBeanContainer.java
@@ -104,8 +104,8 @@ public abstract class AbstractBeanContainer extends
+ " not found");
}
try {
- Property property = pd.createProperty(bean);
- return (IDTYPE) property.getValue();
+ Property property = pd.createProperty(bean);
+ return property.getValue();
} catch (MethodException e) {
throw new IllegalArgumentException(e);
}
@@ -746,9 +746,9 @@ public abstract class AbstractBeanContainer extends
}
model.put(propertyId, propertyDescriptor);
- for (BeanItem item : itemIdToItem.values()) {
- item.addItemProperty(propertyId, propertyDescriptor
- .createProperty((BEANTYPE) item.getBean()));
+ for (BeanItem item : itemIdToItem.values()) {
+ item.addItemProperty(propertyId,
+ propertyDescriptor.createProperty(item.getBean()));
}
// Sends a change event
diff --git a/src/com/vaadin/data/util/AbstractProperty.java b/src/com/vaadin/data/util/AbstractProperty.java
index 2297f13734..bc421755a9 100644
--- a/src/com/vaadin/data/util/AbstractProperty.java
+++ b/src/com/vaadin/data/util/AbstractProperty.java
@@ -17,7 +17,7 @@ import com.vaadin.data.Property;
*
* @since 6.6
*/
-public abstract class AbstractProperty implements Property,
+public abstract class AbstractProperty implements Property,
Property.ValueChangeNotifier, Property.ReadOnlyStatusChangeNotifier {
/**
@@ -56,8 +56,7 @@ public abstract class AbstractProperty implements Property,
/**
* Returns the value of the Property in human readable textual
- * format. The return value should be assignable to the
- * setValue method if the Property is not in read-only mode.
+ * format.
*
* @return String representation of the value stored in the Property
* @deprecated use the property value directly, or {@link #getStringValue()}
diff --git a/src/com/vaadin/data/util/MethodProperty.java b/src/com/vaadin/data/util/MethodProperty.java
index deb3177094..3809029223 100644
--- a/src/com/vaadin/data/util/MethodProperty.java
+++ b/src/com/vaadin/data/util/MethodProperty.java
@@ -47,7 +47,7 @@ import com.vaadin.util.SerializerHelper;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class MethodProperty extends AbstractProperty {
+public class MethodProperty extends AbstractProperty {
private static final Logger logger = Logger.getLogger(MethodProperty.class
.getName());
@@ -349,7 +349,7 @@ public class MethodProperty extends AbstractProperty {
}
// Tests the parameter types
- final Class[] c = m[i].getParameterTypes();
+ final Class>[] c = m[i].getParameterTypes();
if (c.length != getArgs.length) {
// not the right amount of parameters, try next method
@@ -398,7 +398,7 @@ public class MethodProperty extends AbstractProperty {
}
// Checks parameter compatibility
- final Class[] c = m[i].getParameterTypes();
+ final Class>[] c = m[i].getParameterTypes();
if (c.length != setArgs.length) {
// not the right amount of parameters, try next method
@@ -569,8 +569,7 @@ public class MethodProperty extends AbstractProperty {
*
* @return type of the Property
*/
- @SuppressWarnings("unchecked")
- public final Class getType() {
+ public final Class extends T> getType() {
return type;
}
@@ -593,9 +592,9 @@ public class MethodProperty extends AbstractProperty {
*
* @return the value of the Property
*/
- public Object getValue() {
+ public T getValue() {
try {
- return getMethod.invoke(instance, getArgs);
+ return (T) getMethod.invoke(instance, getArgs);
} catch (final Throwable e) {
throw new MethodException(this, e);
}
@@ -642,7 +641,6 @@ public class MethodProperty extends AbstractProperty {
* native type directly or through String.
* @see #invokeSetMethod(Object)
*/
- @SuppressWarnings("unchecked")
public void setValue(Object newValue) throws Property.ReadOnlyException,
Property.ConversionException {
diff --git a/src/com/vaadin/data/util/NestedMethodProperty.java b/src/com/vaadin/data/util/NestedMethodProperty.java
index 41d743aa11..1c636fd0c4 100644
--- a/src/com/vaadin/data/util/NestedMethodProperty.java
+++ b/src/com/vaadin/data/util/NestedMethodProperty.java
@@ -26,7 +26,7 @@ import com.vaadin.data.util.MethodProperty.MethodException;
*
* @since 6.6
*/
-public class NestedMethodProperty extends AbstractProperty {
+public class NestedMethodProperty extends AbstractProperty {
// needed for de-serialization
private String propertyName;
@@ -43,7 +43,7 @@ public class NestedMethodProperty extends AbstractProperty {
*/
private Object instance;
- private Class> type;
+ private Class extends T> type;
/* Special serialization to handle method references */
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
@@ -158,13 +158,14 @@ public class NestedMethodProperty extends AbstractProperty {
} catch (final NoSuchMethodException skipped) {
}
- this.type = MethodProperty.convertPrimitiveType(type);
+ this.type = (Class extends T>) MethodProperty
+ .convertPrimitiveType(type);
this.propertyName = propertyName;
this.getMethods = getMethods;
this.setMethod = setMethod;
}
- public Class> getType() {
+ public Class extends T> getType() {
return type;
}
@@ -179,13 +180,13 @@ public class NestedMethodProperty extends AbstractProperty {
*
* @return the value of the Property
*/
- public Object getValue() {
+ public T getValue() {
try {
Object object = instance;
for (Method m : getMethods) {
object = m.invoke(object);
}
- return object;
+ return (T) object;
} catch (final Throwable e) {
throw new MethodException(this, e);
}
diff --git a/src/com/vaadin/data/util/ObjectProperty.java b/src/com/vaadin/data/util/ObjectProperty.java
index 8286e3c6db..fbae448f30 100644
--- a/src/com/vaadin/data/util/ObjectProperty.java
+++ b/src/com/vaadin/data/util/ObjectProperty.java
@@ -19,7 +19,7 @@ import com.vaadin.data.Property;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class ObjectProperty extends AbstractProperty {
+public class ObjectProperty extends AbstractProperty {
/**
* The value contained by the Property.
@@ -48,9 +48,8 @@ public class ObjectProperty extends AbstractProperty {
/**
* Creates a new instance of ObjectProperty with the given value and type.
*
- * Any value of type Object is accepted because, if the type class contains
- * a string constructor, the toString of the value is used to create the new
- * value. See {@link #setValue(Object)}.
+ * Since Vaadin 7, only values of the correct type are accepted, and no
+ * automatic conversions are performed.
*
* @param value
* the Initial value of the Property.
@@ -58,7 +57,7 @@ public class ObjectProperty extends AbstractProperty {
* the type of the value. The value must be assignable to given
* type.
*/
- public ObjectProperty(Object value, Class type) {
+ public ObjectProperty(T value, Class type) {
// Set the values
this.type = type;
@@ -69,7 +68,7 @@ public class ObjectProperty extends AbstractProperty {
* Creates a new instance of ObjectProperty with the given value, type and
* read-only mode status.
*
- * Any value of type Object is accepted, see
+ * Since Vaadin 7, only the correct type of values is accepted, see
* {@link #ObjectProperty(Object, Class)}.
*
* @param value
@@ -80,7 +79,7 @@ public class ObjectProperty extends AbstractProperty {
* @param readOnly
* Sets the read-only mode.
*/
- public ObjectProperty(Object value, Class type, boolean readOnly) {
+ public ObjectProperty(T value, Class type, boolean readOnly) {
this(value, type);
setReadOnly(readOnly);
}
diff --git a/src/com/vaadin/data/util/PropertyFormatter.java b/src/com/vaadin/data/util/PropertyFormatter.java
index 5f97d4d0c7..9d3559ecf2 100644
--- a/src/com/vaadin/data/util/PropertyFormatter.java
+++ b/src/com/vaadin/data/util/PropertyFormatter.java
@@ -29,15 +29,20 @@ import com.vaadin.data.Property;
* standard "1.0" notation with more zeroes.
*
*
+ * @param T
+ * type of the underlying property (a PropertyFormatter is always a
+ * Property<String>)
+ *
* @author IT Mill Ltd.
* @since 5.3.0
*/
@SuppressWarnings("serial")
-public abstract class PropertyFormatter extends AbstractProperty implements
- Property.ValueChangeListener, Property.ReadOnlyStatusChangeListener {
+public abstract class PropertyFormatter extends AbstractProperty
+ implements Property.ValueChangeListener,
+ Property.ReadOnlyStatusChangeListener {
/** Datasource that stores the actual value. */
- Property dataSource;
+ Property dataSource;
/**
* Construct a new {@code PropertyFormatter} that is not connected to any
@@ -56,7 +61,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* @param propertyDataSource
* to connect this property to.
*/
- public PropertyFormatter(Property propertyDataSource) {
+ public PropertyFormatter(Property propertyDataSource) {
setPropertyDataSource(propertyDataSource);
}
@@ -67,7 +72,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* @return the current data source as a Property, or null if
* none defined.
*/
- public Property getPropertyDataSource() {
+ public Property getPropertyDataSource() {
return dataSource;
}
@@ -83,7 +88,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* @param newDataSource
* the new data source Property.
*/
- public void setPropertyDataSource(Property newDataSource) {
+ public void setPropertyDataSource(Property newDataSource) {
boolean readOnly = false;
String prevValue = null;
@@ -124,7 +129,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
}
/* Documented in the interface */
- public Class getType() {
+ public Class getType() {
return String.class;
}
@@ -134,7 +139,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* @return If the datasource returns null, this is null. Otherwise this is
* String given by format().
*/
- public Object getValue() {
+ public String getValue() {
return getStringValue();
}
@@ -147,7 +152,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
*/
@Override
public String getStringValue() {
- Object value = dataSource == null ? false : dataSource.getValue();
+ T value = dataSource == null ? null : dataSource.getValue();
if (value == null) {
return null;
}
@@ -170,7 +175,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* datasource.
* @return
*/
- abstract public String format(Object value);
+ abstract public String format(T value);
/**
* Parse string and convert it to format compatible with datasource.
@@ -184,7 +189,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* Any type of exception can be thrown to indicate that the
* conversion was not succesful.
*/
- abstract public Object parse(String formattedValue) throws Exception;
+ abstract public T parse(String formattedValue) throws Exception;
/**
* Sets the Property's read-only mode to the specified status.
@@ -211,7 +216,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
}
} else {
try {
- dataSource.setValue(parse((String) newValue));
+ dataSource.setValue(parse(newValue.toString()));
if (!newValue.equals(getStringValue())) {
fireValueChange();
}
diff --git a/src/com/vaadin/data/util/TextFileProperty.java b/src/com/vaadin/data/util/TextFileProperty.java
index dba5aa49f0..a2e1a32986 100644
--- a/src/com/vaadin/data/util/TextFileProperty.java
+++ b/src/com/vaadin/data/util/TextFileProperty.java
@@ -26,7 +26,7 @@ import java.nio.charset.Charset;
*
*/
@SuppressWarnings("serial")
-public class TextFileProperty extends AbstractProperty {
+public class TextFileProperty extends AbstractProperty {
private File file;
private Charset charset = null;
@@ -64,7 +64,7 @@ public class TextFileProperty extends AbstractProperty {
*
* @see com.vaadin.data.Property#getType()
*/
- public Class> getType() {
+ public Class getType() {
return String.class;
}
@@ -73,7 +73,7 @@ public class TextFileProperty extends AbstractProperty {
*
* @see com.vaadin.data.Property#getValue()
*/
- public Object getValue() {
+ public String getValue() {
if (file == null) {
return null;
}
diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java
index 7b686fd397..0f209ce04d 100644
--- a/src/com/vaadin/ui/AbstractField.java
+++ b/src/com/vaadin/ui/AbstractField.java
@@ -53,8 +53,8 @@ import com.vaadin.terminal.PaintTarget;
* @since 3.0
*/
@SuppressWarnings("serial")
-public abstract class AbstractField extends AbstractComponent implements Field,
- Property.ReadOnlyStatusChangeListener,
+public abstract class AbstractField extends AbstractComponent implements
+ Field, Property.ReadOnlyStatusChangeListener,
Property.ReadOnlyStatusChangeNotifier, Action.ShortcutNotifier {
/* Private members */
@@ -62,12 +62,12 @@ public abstract class AbstractField extends AbstractComponent implements Field,
/**
* Value of the abstract field.
*/
- private Object value;
+ private T value;
/**
* Connected data-source.
*/
- private Property dataSource = null;
+ private Property> dataSource = null;
/**
* The list of validators.
@@ -189,7 +189,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
* Gets the field type Don't add a JavaDoc comment here, we use the default
* documentation from the implemented interface.
*/
- public abstract Class> getType();
+ public abstract Class extends T> getType();
/**
* The abstract field is read only also if the data source is in read only
@@ -237,13 +237,14 @@ public abstract class AbstractField extends AbstractComponent implements Field,
public void commit() throws Buffered.SourceException, InvalidValueException {
if (dataSource != null && !dataSource.isReadOnly()) {
if ((isInvalidCommitted() || isValid())) {
- final Object newValue = getValue();
+ final T newValue = getValue();
try {
// Commits the value to datasource.
valueWasModifiedByDataSourceDuringCommit = false;
committingValueToDataSource = true;
- dataSource.setValue(newValue);
+ // TODO cast required until conversions applied
+ ((Property) dataSource).setValue(newValue);
} catch (final Throwable e) {
@@ -325,6 +326,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
// If the new value differs from the previous one
if ((newValue == null && value != null)
|| (newValue != null && !newValue.equals(value))) {
+ // TODO use converter
setInternalValue(newValue);
fireValueChange(false);
}
@@ -393,6 +395,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
if (String.class == getType() && newValue != null) {
newValue = newValue.toString();
}
+ // TODO use converter
setInternalValue(newValue);
fireValueChange(false);
}
@@ -416,12 +419,11 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
/**
- * Returns the (UI type) value of the field converted to a String using
- * toString().
+ * Returns the (UI type) value of the field converted to a String.
*
* This method exists to help migration from the use of Property.toString()
- * to get the field value - for new applications, access getValue()
- * directly. This method may disappear in future Vaadin versions.
+ * to get the field value. For new applications, it is often better to
+ * access getValue() directly.
*
* @return string representation of the field value or null if the value is
* null
@@ -440,27 +442,25 @@ public abstract class AbstractField extends AbstractComponent implements Field,
*
*
* This is the visible, modified and possible invalid value the user have
- * entered to the field. In the read-through mode, the abstract buffer is
- * also updated and validation is performed.
+ * entered to the field.
*
*
*
* Note that the object returned is compatible with getType(). For example,
* if the type is String, this returns Strings even when the underlying
- * datasource is of some other type. In order to access the datasources
- * native type, use getPropertyDatasource().getValue() instead.
+ * datasource is of some other type. In order to access the native type of
+ * the datasource, use getPropertyDatasource().getValue() instead.
*
*
*
- * Note that when you extend AbstractField, you must reimplement this method
- * if datasource.getValue() is not assignable to class returned by getType()
- * AND getType() is not String. In case of Strings, getValue() calls
- * datasource.toString() instead of datasource.getValue().
+ * Since Vaadin 7.0, no implicit conversions between other data types and
+ * String are performed, but the converter is used if set.
*
*
* @return the current value of the field.
+ * @throws Property.ConversionException
*/
- public Object getValue() {
+ public T getValue() {
// Give the value from abstract buffers if the field if possible
if (dataSource == null || !isReadThrough() || isModified()) {
@@ -468,10 +468,11 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
Object result = dataSource.getValue();
+ // TODO perform correct conversion, no cast or toString()
if (String.class == getType() && result != null) {
result = result.toString();
}
- return result;
+ return (T) result;
}
/**
@@ -537,7 +538,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
// Commits the value to datasource
committingValueToDataSource = true;
- dataSource.setValue(newValue);
+ ((Property) dataSource).setValue(newValue);
// The buffer is now unmodified
modified = false;
@@ -643,6 +644,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
if (String.class == getType() && newValue != null) {
newValue = newValue.toString();
}
+ // TODO use converter
setInternalValue(newValue);
}
modified = false;
@@ -1070,6 +1072,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
private void readValueFromProperty(Property.ValueChangeEvent event) {
+ // TODO use converter or check type otherwise
setInternalValue(event.getProperty().getValue());
}
@@ -1134,7 +1137,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
* the new value to be set.
*/
protected void setInternalValue(Object newValue) {
- value = newValue;
+ value = (T) newValue;
if (validators != null && !validators.isEmpty()) {
requestRepaint();
}
diff --git a/src/com/vaadin/ui/AbstractSelect.java b/src/com/vaadin/ui/AbstractSelect.java
index eaac3bb4c5..d4bf600651 100644
--- a/src/com/vaadin/ui/AbstractSelect.java
+++ b/src/com/vaadin/ui/AbstractSelect.java
@@ -55,7 +55,8 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
* @since 5.0
*/
@SuppressWarnings("serial")
-public abstract class AbstractSelect extends AbstractField implements
+// TODO currently cannot specify type more precisely in case of multi-select
+public abstract class AbstractSelect extends AbstractField