package com.vaadin.v7.data.util; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import org.junit.Assert; import org.junit.Test; import com.vaadin.v7.data.Property; /** * Test BeanItem specific features. * * Only public API is tested, not the methods with package visibility. * * See also {@link PropertySetItemTest}, which tests the base class. */ public class BeanItemTest { @SuppressWarnings("unused") protected static class MySuperClass { private int superPrivate = 1; private int superPrivate2 = 2; protected double superProtected = 3.0; private double superProtected2 = 4.0; public boolean superPublic = true; private boolean superPublic2 = true; public int getSuperPrivate() { return superPrivate; } public void setSuperPrivate(int superPrivate) { this.superPrivate = superPrivate; } public double getSuperProtected() { return superProtected; } public void setSuperProtected(double superProtected) { this.superProtected = superProtected; } public boolean isSuperPublic() { return superPublic; } public void setSuperPublic(boolean superPublic) { this.superPublic = superPublic; } } protected static class MyClass extends MySuperClass { private String name; public int value = 123; public MyClass(String name) { this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setNoField(String name) { } public String getNoField() { return "no field backing this setter"; } public String getName2() { return name; } } protected static class MyClass2 extends MyClass { public MyClass2(String name) { super(name); } @Override public void setName(String name) { super.setName(name + "2"); } @Override public String getName() { return super.getName() + "2"; } @Override public String getName2() { return super.getName(); } public void setName2(String name) { super.setName(name); } } protected static interface MySuperInterface { public int getSuper1(); public void setSuper1(int i); public int getOverride(); } protected static interface MySuperInterface2 { public int getSuper2(); } protected static class Generic<T> { public T getProperty() { return null; } public void setProperty(T t) { throw new UnsupportedOperationException(); } } protected static class SubClass extends Generic<String> { @Override // Has a bridged method public String getProperty() { return ""; } @Override // Has a bridged method public void setProperty(String t) { } } protected static interface MySubInterface extends MySuperInterface, MySuperInterface2 { public int getSub(); public void setSub(int i); @Override public int getOverride(); public void setOverride(int i); } @Test public void testGetProperties() { BeanItem<MySuperClass> item = new BeanItem<MySuperClass>( new MySuperClass()); Collection<?> itemPropertyIds = item.getItemPropertyIds(); Assert.assertEquals(3, itemPropertyIds.size()); Assert.assertTrue(itemPropertyIds.contains("superPrivate")); Assert.assertTrue(itemPropertyIds.contains("superProtected")); Assert.assertTrue(itemPropertyIds.contains("superPublic")); } @Test public void testGetSuperClassProperties() { BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1")); Collection<?> itemPropertyIds = item.getItemPropertyIds(); Assert.assertEquals(6, itemPropertyIds.size()); Assert.assertTrue(itemPropertyIds.contains("superPrivate")); Assert.assertTrue(itemPropertyIds.contains("superProtected")); Assert.assertTrue(itemPropertyIds.contains("superPublic")); Assert.assertTrue(itemPropertyIds.contains("name")); Assert.assertTrue(itemPropertyIds.contains("noField")); Assert.assertTrue(itemPropertyIds.contains("name2")); } @Test public void testOverridingProperties() { BeanItem<MyClass2> item = new BeanItem<MyClass2>(new MyClass2("bean2")); Collection<?> itemPropertyIds = item.getItemPropertyIds(); Assert.assertEquals(6, itemPropertyIds.size()); Assert.assertTrue(MyClass2.class.equals(item.getBean().getClass())); // check that name2 accessed via MyClass2, not MyClass Assert.assertFalse(item.getItemProperty("name2").isReadOnly()); } @Test public void testGetInterfaceProperties() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Method method = BeanItem.class .getDeclaredMethod("getPropertyDescriptors", Class.class); method.setAccessible(true); LinkedHashMap<String, VaadinPropertyDescriptor<Class>> propertyDescriptors = (LinkedHashMap<String, VaadinPropertyDescriptor<Class>>) method .invoke(null, MySuperInterface.class); Assert.assertEquals(2, propertyDescriptors.size()); Assert.assertTrue(propertyDescriptors.containsKey("super1")); Assert.assertTrue(propertyDescriptors.containsKey("override")); MethodProperty<?> property = (MethodProperty<?>) propertyDescriptors .get("override").createProperty(getClass()); Assert.assertTrue(property.isReadOnly()); } @Test public void testGetSuperInterfaceProperties() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Method method = BeanItem.class .getDeclaredMethod("getPropertyDescriptors", Class.class); method.setAccessible(true); LinkedHashMap<String, VaadinPropertyDescriptor<Class>> propertyDescriptors = (LinkedHashMap<String, VaadinPropertyDescriptor<Class>>) method .invoke(null, MySubInterface.class); Assert.assertEquals(4, propertyDescriptors.size()); Assert.assertTrue(propertyDescriptors.containsKey("sub")); Assert.assertTrue(propertyDescriptors.containsKey("super1")); Assert.assertTrue(propertyDescriptors.containsKey("super2")); Assert.assertTrue(propertyDescriptors.containsKey("override")); MethodProperty<?> property = (MethodProperty<?>) propertyDescriptors .get("override").createProperty(getClass()); Assert.assertFalse(property.isReadOnly()); } @Test public void testPropertyExplicitOrder() { Collection<String> ids = new ArrayList<String>(); ids.add("name"); ids.add("superPublic"); ids.add("name2"); ids.add("noField"); BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1"), ids); Iterator<?> it = item.getItemPropertyIds().iterator(); Assert.assertEquals("name", it.next()); Assert.assertEquals("superPublic", it.next()); Assert.assertEquals("name2", it.next()); Assert.assertEquals("noField", it.next()); Assert.assertFalse(it.hasNext()); } @Test public void testPropertyExplicitOrder2() { BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1"), new String[] { "name", "superPublic", "name2", "noField" }); Iterator<?> it = item.getItemPropertyIds().iterator(); Assert.assertEquals("name", it.next()); Assert.assertEquals("superPublic", it.next()); Assert.assertEquals("name2", it.next()); Assert.assertEquals("noField", it.next()); Assert.assertFalse(it.hasNext()); } @Test public void testPropertyBadPropertyName() { Collection<String> ids = new ArrayList<String>(); ids.add("name3"); ids.add("name"); // currently silently ignores non-existent properties BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1"), ids); Iterator<?> it = item.getItemPropertyIds().iterator(); Assert.assertEquals("name", it.next()); Assert.assertFalse(it.hasNext()); } @Test public void testRemoveProperty() { BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1")); Collection<?> itemPropertyIds = item.getItemPropertyIds(); Assert.assertEquals(6, itemPropertyIds.size()); item.removeItemProperty("name2"); Assert.assertEquals(5, itemPropertyIds.size()); Assert.assertFalse(itemPropertyIds.contains("name2")); } @Test public void testRemoveSuperProperty() { BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1")); Collection<?> itemPropertyIds = item.getItemPropertyIds(); Assert.assertEquals(6, itemPropertyIds.size()); item.removeItemProperty("superPrivate"); Assert.assertEquals(5, itemPropertyIds.size()); Assert.assertFalse(itemPropertyIds.contains("superPrivate")); } @Test public void testPropertyTypes() { BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1")); Assert.assertTrue(Integer.class .equals(item.getItemProperty("superPrivate").getType())); Assert.assertTrue(Double.class .equals(item.getItemProperty("superProtected").getType())); Assert.assertTrue(Boolean.class .equals(item.getItemProperty("superPublic").getType())); Assert.assertTrue( String.class.equals(item.getItemProperty("name").getType())); } @Test public void testPropertyReadOnly() { BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1")); Assert.assertFalse(item.getItemProperty("name").isReadOnly()); Assert.assertTrue(item.getItemProperty("name2").isReadOnly()); } @Test public void testCustomProperties() throws Exception { LinkedHashMap<String, VaadinPropertyDescriptor<MyClass>> propertyDescriptors = new LinkedHashMap<String, VaadinPropertyDescriptor<MyClass>>(); propertyDescriptors.put("myname", new MethodPropertyDescriptor<BeanItemTest.MyClass>("myname", MyClass.class, MyClass.class.getDeclaredMethod("getName"), MyClass.class.getDeclaredMethod("setName", String.class))); MyClass instance = new MyClass("bean1"); Constructor<BeanItem> constructor = BeanItem.class .getDeclaredConstructor(Object.class, Map.class); constructor.setAccessible(true); BeanItem<MyClass> item = constructor.newInstance(instance, propertyDescriptors); Assert.assertEquals(1, item.getItemPropertyIds().size()); Assert.assertEquals("bean1", item.getItemProperty("myname").getValue()); } @Test public void testAddRemoveProperty() throws Exception { MethodPropertyDescriptor<BeanItemTest.MyClass> pd = new MethodPropertyDescriptor<BeanItemTest.MyClass>( "myname", MyClass.class, MyClass.class.getDeclaredMethod("getName"), MyClass.class.getDeclaredMethod("setName", String.class)); BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1")); Assert.assertEquals(6, item.getItemPropertyIds().size()); Assert.assertEquals(null, item.getItemProperty("myname")); item.addItemProperty("myname", pd.createProperty(item.getBean())); Assert.assertEquals(7, item.getItemPropertyIds().size()); Assert.assertEquals("bean1", item.getItemProperty("myname").getValue()); item.removeItemProperty("myname"); Assert.assertEquals(6, item.getItemPropertyIds().size()); Assert.assertEquals(null, item.getItemProperty("myname")); } @Test public void testOverridenGenericMethods() { BeanItem<SubClass> item = new BeanItem<SubClass>(new SubClass()); Property<?> property = item.getItemProperty("property"); Assert.assertEquals("Unexpected class for property type", String.class, property.getType()); Assert.assertEquals("Unexpected property value", "", property.getValue()); // 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); } }