summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/data/util/MethodProperty.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/vaadin/data/util/MethodProperty.java')
-rw-r--r--src/com/vaadin/data/util/MethodProperty.java784
1 files changed, 0 insertions, 784 deletions
diff --git a/src/com/vaadin/data/util/MethodProperty.java b/src/com/vaadin/data/util/MethodProperty.java
deleted file mode 100644
index 0c64d90481..0000000000
--- a/src/com/vaadin/data/util/MethodProperty.java
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.data.util;
-
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.vaadin.data.Property;
-import com.vaadin.util.SerializerHelper;
-
-/**
- * <p>
- * Proxy class for creating Properties from pairs of getter and setter methods
- * of a Bean property. An instance of this class can be thought as having been
- * attached to a field of an object. Accessing the object through the Property
- * interface directly manipulates the underlying field.
- * </p>
- *
- * <p>
- * It's assumed that the return value returned by the getter method is
- * assignable to the type of the property, and the setter method parameter is
- * assignable to that value.
- * </p>
- *
- * <p>
- * A valid getter method must always be available, but instance of this class
- * can be constructed with a <code>null</code> setter method in which case the
- * resulting MethodProperty is read-only.
- * </p>
- *
- * <p>
- * MethodProperty implements Property.ValueChangeNotifier, but does not
- * automatically know whether or not the getter method will actually return a
- * new value - value change listeners are always notified when setValue is
- * called, without verifying what the getter returns.
- * </p>
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-@SuppressWarnings("serial")
-public class MethodProperty<T> extends AbstractProperty<T> {
-
- /**
- * The object that includes the property the MethodProperty is bound to.
- */
- private transient Object instance;
-
- /**
- * Argument arrays for the getter and setter methods.
- */
- private transient Object[] setArgs, getArgs;
-
- /**
- * The getter and setter methods.
- */
- private transient Method setMethod, getMethod;
-
- /**
- * Index of the new value in the argument list for the setter method. If the
- * setter method requires several parameters, this index tells which one is
- * the actual value to change.
- */
- private int setArgumentIndex;
-
- /**
- * Type of the property.
- */
- private transient Class<? extends T> type;
-
- /* Special serialization to handle method references */
- private void writeObject(java.io.ObjectOutputStream out) throws IOException {
- out.defaultWriteObject();
- SerializerHelper.writeClass(out, type);
- out.writeObject(instance);
- out.writeObject(setArgs);
- out.writeObject(getArgs);
- if (setMethod != null) {
- out.writeObject(setMethod.getName());
- SerializerHelper
- .writeClassArray(out, setMethod.getParameterTypes());
- } else {
- out.writeObject(null);
- out.writeObject(null);
- }
- if (getMethod != null) {
- out.writeObject(getMethod.getName());
- SerializerHelper
- .writeClassArray(out, getMethod.getParameterTypes());
- } else {
- out.writeObject(null);
- out.writeObject(null);
- }
- };
-
- /* Special serialization to handle method references */
- private void readObject(java.io.ObjectInputStream in) throws IOException,
- ClassNotFoundException {
- in.defaultReadObject();
- try {
- @SuppressWarnings("unchecked")
- // business assumption; type parameters not checked at runtime
- Class<T> class1 = (Class<T>) SerializerHelper.readClass(in);
- type = class1;
- instance = in.readObject();
- setArgs = (Object[]) in.readObject();
- getArgs = (Object[]) in.readObject();
- String name = (String) in.readObject();
- Class<?>[] paramTypes = SerializerHelper.readClassArray(in);
- if (name != null) {
- setMethod = instance.getClass().getMethod(name, paramTypes);
- } else {
- setMethod = null;
- }
-
- name = (String) in.readObject();
- paramTypes = SerializerHelper.readClassArray(in);
- if (name != null) {
- getMethod = instance.getClass().getMethod(name, paramTypes);
- } else {
- getMethod = null;
- }
- } catch (SecurityException e) {
- getLogger().log(Level.SEVERE, "Internal deserialization error", e);
- } catch (NoSuchMethodException e) {
- getLogger().log(Level.SEVERE, "Internal deserialization error", e);
- }
- };
-
- /**
- * <p>
- * Creates a new instance of <code>MethodProperty</code> from a named bean
- * property. This constructor takes an object and the name of a bean
- * property and initializes itself with the accessor methods for the
- * property.
- * </p>
- * <p>
- * The getter method of a <code>MethodProperty</code> instantiated with this
- * constructor will be called with no arguments, and the setter method with
- * only the new value as the sole argument.
- * </p>
- *
- * <p>
- * If the setter method is unavailable, the resulting
- * <code>MethodProperty</code> will be read-only, otherwise it will be
- * read-write.
- * </p>
- *
- * <p>
- * Method names are constructed from the bean property by adding
- * get/is/are/set prefix and capitalising the first character in the name of
- * the given bean property.
- * </p>
- *
- * @param instance
- * the object that includes the property.
- * @param beanPropertyName
- * the name of the property to bind to.
- */
- @SuppressWarnings("unchecked")
- public MethodProperty(Object instance, String beanPropertyName) {
-
- final Class<?> beanClass = instance.getClass();
-
- // Assure that the first letter is upper cased (it is a common
- // mistake to write firstName, not FirstName).
- if (Character.isLowerCase(beanPropertyName.charAt(0))) {
- final char[] buf = beanPropertyName.toCharArray();
- buf[0] = Character.toUpperCase(buf[0]);
- beanPropertyName = new String(buf);
- }
-
- // Find the get method
- getMethod = null;
- try {
- getMethod = initGetterMethod(beanPropertyName, beanClass);
- } catch (final java.lang.NoSuchMethodException ignored) {
- throw new MethodException(this, "Bean property " + beanPropertyName
- + " can not be found");
- }
-
- // In case the get method is found, resolve the type
- Class<?> returnType = getMethod.getReturnType();
-
- // Finds the set method
- setMethod = null;
- try {
- setMethod = beanClass.getMethod("set" + beanPropertyName,
- new Class[] { returnType });
- } catch (final java.lang.NoSuchMethodException skipped) {
- }
-
- // Gets the return type from get method
- if (returnType.isPrimitive()) {
- type = (Class<T>) convertPrimitiveType(returnType);
- if (type.isPrimitive()) {
- throw new MethodException(this, "Bean property "
- + beanPropertyName
- + " getter return type must not be void");
- }
- } else {
- type = (Class<T>) returnType;
- }
-
- setArguments(new Object[] {}, new Object[] { null }, 0);
- this.instance = instance;
- }
-
- /**
- * <p>
- * Creates a new instance of <code>MethodProperty</code> from named getter
- * and setter methods. The getter method of a <code>MethodProperty</code>
- * instantiated with this constructor will be called with no arguments, and
- * the setter method with only the new value as the sole argument.
- * </p>
- *
- * <p>
- * If the setter method is <code>null</code>, the resulting
- * <code>MethodProperty</code> will be read-only, otherwise it will be
- * read-write.
- * </p>
- *
- * @param type
- * the type of the property.
- * @param instance
- * the object that includes the property.
- * @param getMethodName
- * the name of the getter method.
- * @param setMethodName
- * the name of the setter method.
- *
- */
- public MethodProperty(Class<? extends T> type, Object instance,
- String getMethodName, String setMethodName) {
- this(type, instance, getMethodName, setMethodName, new Object[] {},
- new Object[] { null }, 0);
- }
-
- /**
- * <p>
- * Creates a new instance of <code>MethodProperty</code> with the getter and
- * setter methods. The getter method of a <code>MethodProperty</code>
- * instantiated with this constructor will be called with no arguments, and
- * the setter method with only the new value as the sole argument.
- * </p>
- *
- * <p>
- * If the setter method is <code>null</code>, the resulting
- * <code>MethodProperty</code> will be read-only, otherwise it will be
- * read-write.
- * </p>
- *
- * @param type
- * the type of the property.
- * @param instance
- * the object that includes the property.
- * @param getMethod
- * the getter method.
- * @param setMethod
- * the setter method.
- */
- public MethodProperty(Class<? extends T> type, Object instance,
- Method getMethod, Method setMethod) {
- this(type, instance, getMethod, setMethod, new Object[] {},
- new Object[] { null }, 0);
- }
-
- /**
- * <p>
- * Creates a new instance of <code>MethodProperty</code> from named getter
- * and setter methods and argument lists. The getter method of a
- * <code>MethodProperty</code> instantiated with this constructor will be
- * called with the getArgs as arguments. The setArgs will be used as the
- * arguments for the setter method, though the argument indexed by the
- * setArgumentIndex will be replaced with the argument passed to the
- * {@link #setValue(Object newValue)} method.
- * </p>
- *
- * <p>
- * For example, if the <code>setArgs</code> contains <code>A</code>,
- * <code>B</code> and <code>C</code>, and <code>setArgumentIndex =
- * 1</code>, the call <code>methodProperty.setValue(X)</code> would result
- * in the setter method to be called with the parameter set of
- * <code>{A, X, C}</code>
- * </p>
- *
- * @param type
- * the type of the property.
- * @param instance
- * the object that includes the property.
- * @param getMethodName
- * the name of the getter method.
- * @param setMethodName
- * the name of the setter method.
- * @param getArgs
- * the fixed argument list to be passed to the getter method.
- * @param setArgs
- * the fixed argument list to be passed to the setter method.
- * @param setArgumentIndex
- * the index of the argument in <code>setArgs</code> to be
- * replaced with <code>newValue</code> when
- * {@link #setValue(Object newValue)} is called.
- */
- @SuppressWarnings("unchecked")
- public MethodProperty(Class<? extends T> type, Object instance,
- String getMethodName, String setMethodName, Object[] getArgs,
- Object[] setArgs, int setArgumentIndex) {
-
- // Check the setargs and setargs index
- if (setMethodName != null && setArgs == null) {
- throw new IndexOutOfBoundsException("The setArgs can not be null");
- }
- if (setMethodName != null
- && (setArgumentIndex < 0 || setArgumentIndex >= setArgs.length)) {
- throw new IndexOutOfBoundsException(
- "The setArgumentIndex must be >= 0 and < setArgs.length");
- }
-
- // Set type
- this.type = type;
-
- // Find set and get -methods
- final Method[] m = instance.getClass().getMethods();
-
- // Finds get method
- boolean found = false;
- for (int i = 0; i < m.length; i++) {
-
- // Tests the name of the get Method
- if (!m[i].getName().equals(getMethodName)) {
-
- // name does not match, try next method
- continue;
- }
-
- // Tests return type
- if (!type.equals(m[i].getReturnType())) {
- continue;
- }
-
- // Tests the parameter types
- final Class<?>[] c = m[i].getParameterTypes();
- if (c.length != getArgs.length) {
-
- // not the right amount of parameters, try next method
- continue;
- }
- int j = 0;
- while (j < c.length) {
- if (getArgs[j] != null
- && !c[j].isAssignableFrom(getArgs[j].getClass())) {
-
- // parameter type does not match, try next method
- break;
- }
- j++;
- }
- if (j == c.length) {
-
- // all paramteters matched
- if (found == true) {
- throw new MethodException(this,
- "Could not uniquely identify " + getMethodName
- + "-method");
- } else {
- found = true;
- getMethod = m[i];
- }
- }
- }
- if (found != true) {
- throw new MethodException(this, "Could not find " + getMethodName
- + "-method");
- }
-
- // Finds set method
- if (setMethodName != null) {
-
- // Finds setMethod
- found = false;
- for (int i = 0; i < m.length; i++) {
-
- // Checks name
- if (!m[i].getName().equals(setMethodName)) {
-
- // name does not match, try next method
- continue;
- }
-
- // Checks parameter compatibility
- final Class<?>[] c = m[i].getParameterTypes();
- if (c.length != setArgs.length) {
-
- // not the right amount of parameters, try next method
- continue;
- }
- int j = 0;
- while (j < c.length) {
- if (setArgs[j] != null
- && !c[j].isAssignableFrom(setArgs[j].getClass())) {
-
- // parameter type does not match, try next method
- break;
- } else if (j == setArgumentIndex && !c[j].equals(type)) {
-
- // Property type is not the same as setArg type
- break;
- }
- j++;
- }
- if (j == c.length) {
-
- // all parameters match
- if (found == true) {
- throw new MethodException(this,
- "Could not identify unique " + setMethodName
- + "-method");
- } else {
- found = true;
- setMethod = m[i];
- }
- }
- }
- if (found != true) {
- throw new MethodException(this, "Could not identify "
- + setMethodName + "-method");
- }
- }
-
- // Gets the return type from get method
- this.type = (Class<T>) convertPrimitiveType(type);
-
- setArguments(getArgs, setArgs, setArgumentIndex);
- this.instance = instance;
- }
-
- /**
- * <p>
- * Creates a new instance of <code>MethodProperty</code> from the getter and
- * setter methods, and argument lists.
- * </p>
- * <p>
- * This constructor behaves exactly like
- * {@link #MethodProperty(Class type, Object instance, String getMethodName, String setMethodName, Object [] getArgs, Object [] setArgs, int setArgumentIndex)}
- * except that instead of names of the getter and setter methods this
- * constructor is given the actual methods themselves.
- * </p>
- *
- * @param type
- * the type of the property.
- * @param instance
- * the object that includes the property.
- * @param getMethod
- * the getter method.
- * @param setMethod
- * the setter method.
- * @param getArgs
- * the fixed argument list to be passed to the getter method.
- * @param setArgs
- * the fixed argument list to be passed to the setter method.
- * @param setArgumentIndex
- * the index of the argument in <code>setArgs</code> to be
- * replaced with <code>newValue</code> when
- * {@link #setValue(Object newValue)} is called.
- */
- @SuppressWarnings("unchecked")
- // cannot use "Class<? extends T>" because of automatic primitive type
- // conversions
- public MethodProperty(Class<?> type, Object instance, Method getMethod,
- Method setMethod, Object[] getArgs, Object[] setArgs,
- int setArgumentIndex) {
-
- if (getMethod == null) {
- throw new MethodException(this,
- "Property GET-method cannot not be null: " + type);
- }
-
- if (setMethod != null) {
- if (setArgs == null) {
- throw new IndexOutOfBoundsException(
- "The setArgs can not be null");
- }
- if (setArgumentIndex < 0 || setArgumentIndex >= setArgs.length) {
- throw new IndexOutOfBoundsException(
- "The setArgumentIndex must be >= 0 and < setArgs.length");
- }
- }
-
- // Gets the return type from get method
- Class<? extends T> convertedType = (Class<? extends T>) convertPrimitiveType(type);
-
- this.getMethod = getMethod;
- this.setMethod = setMethod;
- setArguments(getArgs, setArgs, setArgumentIndex);
- this.instance = instance;
- this.type = convertedType;
- }
-
- /**
- * Find a getter method for a property (getXyz(), isXyz() or areXyz()).
- *
- * @param propertyName
- * name of the property
- * @param beanClass
- * class in which to look for the getter methods
- * @return Method
- * @throws NoSuchMethodException
- * if no getter found
- */
- static Method initGetterMethod(String propertyName, final Class<?> beanClass)
- throws NoSuchMethodException {
- propertyName = propertyName.substring(0, 1).toUpperCase()
- + propertyName.substring(1);
-
- Method getMethod = null;
- try {
- getMethod = beanClass.getMethod("get" + propertyName,
- new Class[] {});
- } catch (final java.lang.NoSuchMethodException ignored) {
- try {
- getMethod = beanClass.getMethod("is" + propertyName,
- new Class[] {});
- } catch (final java.lang.NoSuchMethodException ignoredAsWell) {
- getMethod = beanClass.getMethod("are" + propertyName,
- new Class[] {});
- }
- }
- return getMethod;
- }
-
- static Class<?> convertPrimitiveType(Class<?> type) {
- // Gets the return type from get method
- if (type.isPrimitive()) {
- if (type.equals(Boolean.TYPE)) {
- type = Boolean.class;
- } else if (type.equals(Integer.TYPE)) {
- type = Integer.class;
- } else if (type.equals(Float.TYPE)) {
- type = Float.class;
- } else if (type.equals(Double.TYPE)) {
- type = Double.class;
- } else if (type.equals(Byte.TYPE)) {
- type = Byte.class;
- } else if (type.equals(Character.TYPE)) {
- type = Character.class;
- } else if (type.equals(Short.TYPE)) {
- type = Short.class;
- } else if (type.equals(Long.TYPE)) {
- type = Long.class;
- }
- }
- return type;
- }
-
- /**
- * Returns the type of the Property. The methods <code>getValue</code> and
- * <code>setValue</code> must be compatible with this type: one must be able
- * to safely cast the value returned from <code>getValue</code> to the given
- * type and pass any variable assignable to this type as an argument to
- * <code>setValue</code>.
- *
- * @return type of the Property
- */
- @Override
- public final Class<? extends T> getType() {
- return type;
- }
-
- /**
- * Tests if the object is in read-only mode. In read-only mode calls to
- * <code>setValue</code> will throw <code>ReadOnlyException</code> and will
- * not modify the value of the Property.
- *
- * @return <code>true</code> if the object is in read-only mode,
- * <code>false</code> if it's not
- */
- @Override
- public boolean isReadOnly() {
- return super.isReadOnly() || (setMethod == null);
- }
-
- /**
- * Gets the value stored in the Property. The value is resolved by calling
- * the specified getter method with the argument specified at instantiation.
- *
- * @return the value of the Property
- */
- @Override
- public T getValue() {
- try {
- return (T) getMethod.invoke(instance, getArgs);
- } catch (final Throwable e) {
- throw new MethodException(this, e);
- }
- }
-
- /**
- * <p>
- * Sets the setter method and getter method argument lists.
- * </p>
- *
- * @param getArgs
- * the fixed argument list to be passed to the getter method.
- * @param setArgs
- * the fixed argument list to be passed to the setter method.
- * @param setArgumentIndex
- * the index of the argument in <code>setArgs</code> to be
- * replaced with <code>newValue</code> when
- * {@link #setValue(Object newValue)} is called.
- */
- public void setArguments(Object[] getArgs, Object[] setArgs,
- int setArgumentIndex) {
- this.getArgs = new Object[getArgs.length];
- for (int i = 0; i < getArgs.length; i++) {
- this.getArgs[i] = getArgs[i];
- }
- this.setArgs = new Object[setArgs.length];
- for (int i = 0; i < setArgs.length; i++) {
- this.setArgs[i] = setArgs[i];
- }
- this.setArgumentIndex = setArgumentIndex;
- }
-
- /**
- * Sets the value of the property.
- *
- * Note that since Vaadin 7, no conversions are performed and the value must
- * be of the correct type.
- *
- * @param newValue
- * the New value of the property.
- * @throws <code>Property.ReadOnlyException</code> if the object is in
- * read-only mode.
- * @see #invokeSetMethod(Object)
- */
- @Override
- @SuppressWarnings("unchecked")
- public void setValue(Object newValue) throws Property.ReadOnlyException {
-
- // Checks the mode
- if (isReadOnly()) {
- throw new Property.ReadOnlyException();
- }
-
- // Checks the type of the value
- if (newValue != null && !type.isAssignableFrom(newValue.getClass())) {
- throw new IllegalArgumentException(
- "Invalid value type for ObjectProperty.");
- }
-
- invokeSetMethod((T) newValue);
- fireValueChange();
- }
-
- /**
- * Internal method to actually call the setter method of the wrapped
- * property.
- *
- * @param value
- */
- protected void invokeSetMethod(T value) {
-
- try {
- // Construct a temporary argument array only if needed
- if (setArgs.length == 1) {
- setMethod.invoke(instance, new Object[] { value });
- } else {
-
- // Sets the value to argument array
- final Object[] args = new Object[setArgs.length];
- for (int i = 0; i < setArgs.length; i++) {
- args[i] = (i == setArgumentIndex) ? value : setArgs[i];
- }
- setMethod.invoke(instance, args);
- }
- } catch (final InvocationTargetException e) {
- final Throwable targetException = e.getTargetException();
- throw new MethodException(this, targetException);
- } catch (final Exception e) {
- throw new MethodException(this, e);
- }
- }
-
- /**
- * <code>Exception</code> object that signals that there were problems
- * calling or finding the specified getter or setter methods of the
- * property.
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
- @SuppressWarnings("rawtypes")
- // Exceptions cannot be parameterized, ever.
- public static class MethodException extends RuntimeException {
-
- /**
- * The method property from which the exception originates from
- */
- private final Property property;
-
- /**
- * Cause of the method exception
- */
- private Throwable cause;
-
- /**
- * Constructs a new <code>MethodException</code> with the specified
- * detail message.
- *
- * @param property
- * the property.
- * @param msg
- * the detail message.
- */
- public MethodException(Property property, String msg) {
- super(msg);
- this.property = property;
- }
-
- /**
- * Constructs a new <code>MethodException</code> from another exception.
- *
- * @param property
- * the property.
- * @param cause
- * the cause of the exception.
- */
- public MethodException(Property property, Throwable cause) {
- this.property = property;
- this.cause = cause;
- }
-
- /**
- * @see java.lang.Throwable#getCause()
- */
- @Override
- public Throwable getCause() {
- return cause;
- }
-
- /**
- * Gets the method property this exception originates from.
- *
- * @return MethodProperty or null if not a valid MethodProperty
- */
- public MethodProperty getMethodProperty() {
- return (property instanceof MethodProperty) ? (MethodProperty) property
- : null;
- }
-
- /**
- * Gets the method property this exception originates from.
- *
- * @return Property from which the exception originates
- */
- public Property getProperty() {
- return property;
- }
- }
-
- /**
- * Sends a value change event to all registered listeners.
- *
- * Public for backwards compatibility, visibility may be reduced in future
- * versions.
- */
- @Override
- public void fireValueChange() {
- super.fireValueChange();
- }
-
- private static final Logger getLogger() {
- return Logger.getLogger(MethodProperty.class.getName());
- }
-}