import java.util.Map;
import java.util.Set;
+import com.vaadin.data.Property;
+
/**
* A wrapper class for adding the Item interface to any Java Bean.
*
/**
* The bean which this Item is based on.
*/
- private final BT bean;
+ private BT bean;
/**
* <p>
return bean;
}
+ /**
+ * Changes the Java Bean this item is based on.
+ * <p>
+ * This will cause any existing properties to be re-mapped to the new bean.
+ * Any added custom properties which are not of type {@link MethodProperty}
+ * or {@link NestedMethodProperty} will not be updated to reflect the change
+ * of bean.
+ * <p>
+ * Changing the bean will fire value change events for all properties of
+ * type {@link MethodProperty} or {@link NestedMethodProperty}.
+ *
+ * @param bean
+ * The new bean to use for this item, not <code>null</code>
+ */
+ public void setBean(BT bean) {
+ if (bean == null) {
+ throw new IllegalArgumentException("Bean cannot be null");
+ }
+
+ if (getBean().getClass() != bean.getClass()) {
+ throw new IllegalArgumentException(
+ "The new bean class " + bean.getClass().getName()
+ + " does not match the old bean class "
+ + getBean().getClass());
+ }
+
+ // Remap properties
+ for (Object propertyId : getItemPropertyIds()) {
+ Property p = getItemProperty(propertyId);
+ if (p instanceof MethodProperty) {
+ MethodProperty mp = (MethodProperty) p;
+ assert (mp.getInstance() == getBean());
+ mp.setInstance(bean);
+ } else if (p instanceof NestedMethodProperty) {
+ NestedMethodProperty nmp = (NestedMethodProperty) p;
+ assert (nmp.getInstance() == getBean());
+ nmp.setInstance(bean);
+ }
+ }
+
+ this.bean = bean;
+ }
}
super.fireValueChange();
}
+ /**
+ * The instance used by this property
+ *
+ * @return the instance used for fetching the property value
+ */
+ public Object getInstance() {
+ return instance;
+ }
+
+ /**
+ * Sets the instance used by this property.
+ * <p>
+ * The new instance must be of the same type as the old instance
+ * <p>
+ * To be consistent with {@link #setValue(Object)}, this method will fire a
+ * value change event even if the value stays the same
+ *
+ * @param instance
+ * the instance to use
+ */
+ public void setInstance(Object instance) {
+ if (this.instance.getClass() != instance.getClass()) {
+ throw new IllegalArgumentException("The new instance is of type "
+ + instance.getClass().getName()
+ + " which does not match the old instance type "
+ + this.instance.getClass().getName());
+ }
+ this.instance = instance;
+ fireValueChange();
+ }
+
private static final Logger getLogger() {
return Logger.getLogger(MethodProperty.class.getName());
}
/**
* Gets the value stored in the Property. The value is resolved by calling
- * the specified getter method with the argument specified at instantiation.
+ * the specified getter methods on the current instance:
*
* @return the value of the Property
+ * @see #getInstance()
*/
@Override
public T getValue() {
return Collections.unmodifiableList(getMethods);
}
+ /**
+ * The instance used by this property
+ *
+ * @return the instance used for fetching the property value
+ */
+ public Object getInstance() {
+ return instance;
+ }
+
+ /**
+ * Sets the instance used by this property.
+ * <p>
+ * The new instance must be of the same type as the old instance
+ * <p>
+ * To be consistent with {@link #setValue(Object)}, this method will fire a
+ * value change event even if the value stays the same
+ *
+ * @param instance
+ * the instance to use
+ */
+ public void setInstance(Object instance) {
+ if (this.instance.getClass() != instance.getClass()) {
+ throw new IllegalArgumentException("The new instance is of type "
+ + instance.getClass().getName()
+ + " which does not match the old instance type "
+ + this.instance.getClass().getName());
+ }
+ this.instance = instance;
+ fireValueChange();
+ }
+
}
// Should not be exception
property.setValue(null);
}
+
+ @Test
+ public void testChangeBean() {
+ BeanItem<MyClass> beanItem = new BeanItem<BeanItemTest.MyClass>(
+ new MyClass("Foo"));
+ beanItem.setBean(new MyClass("Bar"));
+ Assert.assertEquals("Bar", beanItem.getItemProperty("name").getValue());
+ }
+
+ @Test
+ public void testChangeBeanNestedProperty() {
+ BeanItem<MyClass> beanItem = new BeanItem<BeanItemTest.MyClass>(
+ new MyClass("Foo"));
+ beanItem.setBean(new MyClass("Bar"));
+ Assert.assertEquals("Bar", beanItem.getItemProperty("name").getValue());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testChangeBeanToIncompatibleOne() {
+ BeanItem<Object> beanItem = new BeanItem<Object>(new MyClass("Foo"));
+ beanItem.setBean(new Generic<String>());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testChangeBeanToSubclass() {
+ BeanItem<MyClass> beanItem = new BeanItem<BeanItemTest.MyClass>(
+ new MyClass("Foo"));
+ beanItem.setBean(new MyClass("Bar"));
+ beanItem.setBean(new MyClass2("foo"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testChangeBeanToNull() {
+ BeanItem<Object> beanItem = new BeanItem<Object>(new MyClass("Foo"));
+ beanItem.setBean(null);
+ }
+
}
--- /dev/null
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.util;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.data.util.NestedMethodPropertyTest.Address;
+
+public class MethodPropertyTest {
+
+ private Address testObject;
+
+ @Before
+ public void setup() {
+ testObject = new NestedMethodPropertyTest.Address("some street", 123);
+ }
+
+ @Test
+ public void getValue() {
+ MethodProperty<String> mp = new MethodProperty<String>(testObject,
+ "street");
+ Assert.assertEquals("some street", mp.getValue());
+ }
+
+ @Test
+ public void getValueAfterBeanUpdate() {
+ MethodProperty<String> mp = new MethodProperty<String>(testObject,
+ "street");
+ testObject.setStreet("Foo street");
+ Assert.assertEquals("Foo street", mp.getValue());
+ }
+
+ @Test
+ public void setValue() {
+ MethodProperty<String> mp = new MethodProperty<String>(testObject,
+ "street");
+ mp.setValue("Foo street");
+ Assert.assertEquals("Foo street", testObject.getStreet());
+ }
+
+ @Test
+ public void changeInstance() {
+ MethodProperty<String> mp = new MethodProperty<String>(testObject,
+ "street");
+ Address newStreet = new Address("new street", 999);
+ mp.setInstance(newStreet);
+ Assert.assertEquals("new street", mp.getValue());
+ Assert.assertEquals("some street", testObject.getStreet());
+
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void changeInstanceToIncompatible() {
+ MethodProperty<String> mp = new MethodProperty<String>(testObject,
+ "street");
+ mp.setInstance("foobar");
+
+ }
+
+}
Assert.assertTrue(booleanProperty.isReadOnly());
}
+ @Test
+ public void testChangeInstance() {
+ NestedMethodProperty<String> streetProperty = new NestedMethodProperty<String>(
+ vaadin, "manager.address.street");
+
+ Address somewhere = new Address("The street", 1234);
+ Person someone = new Person("Someone", somewhere);
+ Team someteam = new Team("The team", someone);
+ streetProperty.setInstance(someteam);
+
+ Assert.assertEquals("The street", streetProperty.getValue());
+ Assert.assertEquals("Ruukinkatu 2-4", vaadin.getManager().getAddress()
+ .getStreet());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testChangeInstanceToIncompatible() {
+ NestedMethodProperty<String> streetProperty = new NestedMethodProperty<String>(
+ vaadin, "manager.address.street");
+
+ streetProperty.setInstance("bar");
+ }
+
}