From: <iro...@us...> - 2009-04-06 04:29:11
|
Revision: 98 http://pojomatic.svn.sourceforge.net/pojomatic/?rev=98&view=rev Author: iroberts Date: 2009-04-06 04:29:10 +0000 (Mon, 06 Apr 2009) Log Message: ----------- Property name derived from getFoo() is now "foo" instead of "getFoo". Allow overriding the property name via the Property annotation. Modified Paths: -------------- trunk/Pojomatic/src/main/java/org/pojomatic/annotations/Property.java trunk/Pojomatic/src/main/java/org/pojomatic/internal/AbstractPropertyElement.java trunk/Pojomatic/src/main/java/org/pojomatic/internal/ClassProperties.java trunk/Pojomatic/src/main/java/org/pojomatic/internal/PojomatorImpl.java trunk/Pojomatic/src/main/java/org/pojomatic/internal/PropertyAccessor.java trunk/Pojomatic/src/main/java/org/pojomatic/internal/PropertyField.java trunk/Pojomatic/src/test/java/org/pojomatic/TestUtils.java trunk/Pojomatic/src/test/java/org/pojomatic/internal/PojomatorImplTest.java trunk/Pojomatic/src/test/java/org/pojomatic/internal/PropertyElementTest.java Modified: trunk/Pojomatic/src/main/java/org/pojomatic/annotations/Property.java =================================================================== --- trunk/Pojomatic/src/main/java/org/pojomatic/annotations/Property.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/main/java/org/pojomatic/annotations/Property.java 2009-04-06 04:29:10 UTC (rev 98) @@ -20,7 +20,19 @@ public @interface Property { /** - * A {@link Property} is included in everything by default + * Which sets of {@link Pojomatic} operations ({@code equals}, {@code hashCode} and + * {@code toString}) should use a property. */ public PojomaticPolicy policy() default PojomaticPolicy.DEFAULT; + + /** + * The name used to identify the property in the standard {@code toString} representation. If + * empty, the following algorithm is used to determine the name. For a propertiy referenced by + * field, the name of the field is used. For a property referenced by a method whose name is of + * the form {@code getSomeField}, the name {@code someField} will be used. For a boolean property + * referenced by a method whose name is of the form {@code isSomeField}, the name + * {@code someField} will be used. For any other property referenced by a method, the name of + * the method is used. + */ + public String name() default ""; } Modified: trunk/Pojomatic/src/main/java/org/pojomatic/internal/AbstractPropertyElement.java =================================================================== --- trunk/Pojomatic/src/main/java/org/pojomatic/internal/AbstractPropertyElement.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/main/java/org/pojomatic/internal/AbstractPropertyElement.java 2009-04-06 04:29:10 UTC (rev 98) @@ -11,10 +11,10 @@ protected final E element; private final String name; - protected AbstractPropertyElement(E element) { + protected AbstractPropertyElement(E element, String name) { element.setAccessible(true); this.element = element; - this.name = element.getName(); + this.name = name; } public String getName() { Modified: trunk/Pojomatic/src/main/java/org/pojomatic/internal/ClassProperties.java =================================================================== --- trunk/Pojomatic/src/main/java/org/pojomatic/internal/ClassProperties.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/main/java/org/pojomatic/internal/ClassProperties.java 2009-04-06 04:29:10 UTC (rev 98) @@ -54,8 +54,9 @@ /* add all fields that are explicitly annotated or auto-detected */ if (propertyPolicy != null || (autoProperty != null && AutoDetectPolicy.FIELD == autoProperty.autoDetect())) { + PropertyField propertyField = new PropertyField(field, getPropertyName(property)); for (PropertyRole role : PropertyFilter.getRoles(propertyPolicy, classPolicy)) { - properties.get(role).add(new PropertyField(field)); + properties.get(role).add(propertyField); } } } @@ -78,8 +79,10 @@ /* add all methods that are explicitly annotated or auto-detected */ if (propertyPolicy != null || (autoProperty != null && AutoDetectPolicy.METHOD == autoProperty.autoDetect())) { + PropertyAccessor propertyAccessor = + new PropertyAccessor(method, getPropertyName(property)); for (PropertyRole role : PropertyFilter.getRoles(propertyPolicy, classPolicy)) { - properties.get(role).add(new PropertyAccessor(method)); + properties.get(role).add(propertyAccessor); } } } @@ -93,6 +96,10 @@ throw new IllegalArgumentException("Class " + pojoClass.getName() + " has no Pojomatic properties"); } + private String getPropertyName(Property property) { + return property == null ? "" : property.name(); + } + private static boolean methodIsAccessor(Method method) { return methodSignatureIsAccessor(method) && isAccessorName(method.getName()); Modified: trunk/Pojomatic/src/main/java/org/pojomatic/internal/PojomatorImpl.java =================================================================== --- trunk/Pojomatic/src/main/java/org/pojomatic/internal/PojomatorImpl.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/main/java/org/pojomatic/internal/PojomatorImpl.java 2009-04-06 04:29:10 UTC (rev 98) @@ -10,6 +10,7 @@ import org.pojomatic.PropertyElement; import org.pojomatic.annotations.PojoFormat; import org.pojomatic.annotations.PojomaticPolicy; +import org.pojomatic.annotations.Property; import org.pojomatic.annotations.PropertyFormat; import org.pojomatic.diff.Difference; import org.pojomatic.diff.DifferenceToNull; @@ -208,6 +209,7 @@ * </p> * * @throws NullPointerException if {@code instance} is null + * @see Property#name() */ public String doToString(T instance) { if (instance == null) { Modified: trunk/Pojomatic/src/main/java/org/pojomatic/internal/PropertyAccessor.java =================================================================== --- trunk/Pojomatic/src/main/java/org/pojomatic/internal/PropertyAccessor.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/main/java/org/pojomatic/internal/PropertyAccessor.java 2009-04-06 04:29:10 UTC (rev 98) @@ -1,13 +1,39 @@ package org.pojomatic.internal; +import java.beans.Introspector; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class PropertyAccessor extends AbstractPropertyElement<Method> { - public PropertyAccessor(Method element) { - super(element); + private final static String GET = "get", IS = "is"; + + public PropertyAccessor(Method method, String name) { + super(method, name.isEmpty() ? getName(method) : name); } + private static String getName(Method method) { + String methodName = method.getName(); + if (isPrefixedWith(methodName, GET)) { + return Introspector.decapitalize(methodName.substring(GET.length())); + } + else if (isBoolean(method.getReturnType()) && isPrefixedWith(methodName, IS)) { + return Introspector.decapitalize(methodName.substring(IS.length())); + } + else { + return methodName; + } + } + + private static boolean isBoolean(Class<?> clazz) { + return Boolean.class.equals(clazz) || Boolean.TYPE.equals(clazz); + } + + private static boolean isPrefixedWith(String name, String prefix) { + return name.length() > prefix.length() + && name.startsWith(prefix) + && Character.isUpperCase(name.charAt(prefix.length())); + } + @Override protected Object accessValue(Object instance) throws IllegalArgumentException, IllegalAccessException { Modified: trunk/Pojomatic/src/main/java/org/pojomatic/internal/PropertyField.java =================================================================== --- trunk/Pojomatic/src/main/java/org/pojomatic/internal/PropertyField.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/main/java/org/pojomatic/internal/PropertyField.java 2009-04-06 04:29:10 UTC (rev 98) @@ -3,8 +3,8 @@ import java.lang.reflect.Field; public class PropertyField extends AbstractPropertyElement<Field> { - public PropertyField(Field propertyField) { - super(propertyField); + public PropertyField(Field propertyField, String name) { + super(propertyField, name.isEmpty() ? propertyField.getName() : name); } @Override Modified: trunk/Pojomatic/src/test/java/org/pojomatic/TestUtils.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/TestUtils.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/test/java/org/pojomatic/TestUtils.java 2009-04-06 04:29:10 UTC (rev 98) @@ -6,11 +6,11 @@ public class TestUtils { public static PropertyElement field(Class<?> clazz, String fieldName) throws Exception { - return new PropertyField(clazz.getDeclaredField(fieldName)); + return new PropertyField(clazz.getDeclaredField(fieldName), ""); } public static PropertyElement method(Class<?> clazz, String methodName) throws Exception { - return new PropertyAccessor(clazz.getDeclaredMethod(methodName)); + return new PropertyAccessor(clazz.getDeclaredMethod(methodName), ""); } } Modified: trunk/Pojomatic/src/test/java/org/pojomatic/internal/PojomatorImplTest.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/internal/PojomatorImplTest.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/test/java/org/pojomatic/internal/PojomatorImplTest.java 2009-04-06 04:29:10 UTC (rev 98) @@ -33,10 +33,14 @@ private static Pojomator<StringArrayProperty> STRING_ARRAY_PROPERTY_POJOMATOR = makePojomatorImpl(StringArrayProperty.class); + private static final Pojomator<AccessCheckedProperties> ACCESS_CHECKED_PROPERTIES_POJOMATOR = + makePojomatorImpl(AccessCheckedProperties.class); + private static final List<Class<?>> PRIMATIVE_TYPES = Arrays.<Class<?>>asList( Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE); + @Test(expected=NullPointerException.class) public void testNullHashCode() { OBJECT_PROPERTY_POJOMATOR.doHashCode(null); } @@ -131,24 +135,22 @@ } @Test public void testShortCircuitEquals() { - final Pojomator<AccessCheckedProperties> pojomator = makePojomatorImpl(AccessCheckedProperties.class); - AccessCheckedProperties left = new AccessCheckedProperties(1,1); AccessCheckedProperties right = new AccessCheckedProperties(2,2); - assertFalse(pojomator.doEquals(left, right)); + assertFalse(ACCESS_CHECKED_PROPERTIES_POJOMATOR.doEquals(left, right)); assertFalse(left.getBCalled); assertFalse(right.getBCalled); - assertTrue(pojomator.doEquals(left, left)); + assertTrue(ACCESS_CHECKED_PROPERTIES_POJOMATOR.doEquals(left, left)); assertFalse(left.getBCalled); - assertFalse(pojomator.doEquals(left, null)); + assertFalse(ACCESS_CHECKED_PROPERTIES_POJOMATOR.doEquals(left, null)); assertFalse(left.getBCalled); - assertFalse(pojomator.doEquals(left, "hello")); + assertFalse(ACCESS_CHECKED_PROPERTIES_POJOMATOR.doEquals(left, "hello")); assertFalse(left.getBCalled); - assertTrue(pojomator.doEquals(left, new AccessCheckedProperties(1,1))); + assertTrue(ACCESS_CHECKED_PROPERTIES_POJOMATOR.doEquals(left, new AccessCheckedProperties(1,1))); assertTrue(left.getBCalled); } @@ -202,6 +204,12 @@ assertEquals("ObjectPairProperty{s: {ess}, t: {tee}}", actual); } + @Test public void testToStringNames() { + assertEquals( + "AccessCheckedProperties{a: {1}, b: {2}}", + ACCESS_CHECKED_PROPERTIES_POJOMATOR.doToString(new AccessCheckedProperties(1, 2))); + } + @Test public void testCustomFormatters() { assertEquals("PREFIXFormattedObject{s: {BEFOREx}}", makePojomatorImpl(FormattedObject.class).doToString(new FormattedObject("x"))); Modified: trunk/Pojomatic/src/test/java/org/pojomatic/internal/PropertyElementTest.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/internal/PropertyElementTest.java 2009-04-06 04:24:46 UTC (rev 97) +++ trunk/Pojomatic/src/test/java/org/pojomatic/internal/PropertyElementTest.java 2009-04-06 04:29:10 UTC (rev 98) @@ -2,6 +2,8 @@ import static org.junit.Assert.*; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -10,61 +12,103 @@ public class PropertyElementTest { + @Retention(RetentionPolicy.RUNTIME) @interface Expected { + String value(); + } + @Test(expected=NullPointerException.class) public void testGetValueNullField() throws Exception { - PropertyElement propertyElement = new PropertyField(getTestField()); + PropertyElement propertyElement = new PropertyField(getTestField(), ""); propertyElement.getValue(null); } @Test(expected=NullPointerException.class) public void testGetValueNullMethod() throws Exception { - PropertyElement propertyElement = new PropertyAccessor(getTestMethod()); + PropertyElement propertyElement = new PropertyAccessor(getTestMethod(), ""); propertyElement.getValue(null); } @Test public void testGetValueField() throws Exception { - PropertyElement propertyElement = new PropertyField(getTestField()); + PropertyElement propertyElement = new PropertyField(getTestField(), ""); assertEquals(testField, propertyElement.getValue(this)); } @Test public void testGetValueMethod() throws Exception { - PropertyElement propertyElement = - new PropertyAccessor(getTestMethod()); + PropertyElement propertyElement = new PropertyAccessor(getTestMethod(), ""); assertEquals(testAccessor(), propertyElement.getValue(this)); } @Test public void testEquals() throws Exception { - PropertyAccessor testMethodProperty = new PropertyAccessor(getTestMethod()); + PropertyAccessor testMethodProperty = new PropertyAccessor(getTestMethod(), ""); assertEquals(testMethodProperty, testMethodProperty); assertFalse(testMethodProperty.equals(null)); assertFalse(testMethodProperty.equals("someOtherClass")); - assertEquals(testMethodProperty, new PropertyAccessor(getTestMethod())); - final PropertyField testFieldProperty = new PropertyField(getTestField()); + assertEquals(testMethodProperty, new PropertyAccessor(getTestMethod(), "")); + final PropertyField testFieldProperty = new PropertyField(getTestField(), ""); assertFalse(testMethodProperty.equals(testFieldProperty)); assertFalse(testFieldProperty.equals(testMethodProperty)); } @Test public void testToString() throws Exception { - assertEquals(getTestMethod().toString(), new PropertyAccessor(getTestMethod()).toString()); + assertEquals(getTestMethod().toString(), new PropertyAccessor(getTestMethod(), "").toString()); } @Test public void testHashCode() throws Exception { - assertEquals(getTestMethod().hashCode(), new PropertyAccessor(getTestMethod()).hashCode()); + assertEquals(getTestMethod().hashCode(), new PropertyAccessor(getTestMethod(), "").hashCode()); } + @Test + public void testGetNameForField() throws Exception { + assertEquals("testField", new PropertyField(getTestField(), "").getName()); + assertEquals("foo", new PropertyField(getTestField(), "foo").getName()); + } + + @Test + public void testOverrideNameForAccessor() throws Exception { + assertEquals("bar", new PropertyAccessor(getTestMethod(), "bar").getName()); + } + + @Test + public void testGetNameForAccessor() throws Exception { + for (Method method: getClass().getDeclaredMethods()) { + Expected expected = method.getAnnotation(Expected.class); + if (expected != null) { + assertEquals( + "name for method " + method.getName(), + expected.value(), + new PropertyAccessor(method, "").getName()); + } + } + } + + // methods tested in testGetNameForAccessor + @Expected("foo") public Object getFoo() { return null; } + @Expected("URL") public Object getURL() { return null; } + @Expected("get") public Object get() { return null; } + @Expected("getter") public Object getter() { return null; } + @Expected("isString") public Object isString() { return null; } + @Expected("boolean") public Boolean isBoolean() { return null; } + @Expected("bool") public boolean isBool() { return false; } + @Expected("is") public boolean is() { return false; } + private Method getTestMethod() throws Exception { - return this.getClass().getMethod("testAccessor", (Class[])null); + return getMethod("testAccessor"); } + private Method getMethod(String name) throws Exception { + return this.getClass().getMethod(name, (Class[])null); + } + private Field getTestField() throws Exception { - return this.getClass().getDeclaredField("testField"); + return getClass().getDeclaredField("testField"); } + // test properties public Object testAccessor() { return "Test string"; } private final Object testField = new Object(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |