From: <iro...@us...> - 2009-08-16 17:17:32
|
Revision: 129 http://pojomatic.svn.sourceforge.net/pojomatic/?rev=129&view=rev Author: iroberts Date: 2009-08-16 17:17:24 +0000 (Sun, 16 Aug 2009) Log Message: ----------- Pojomatic will no longer add a method property multiple times if it is overridden (even if the overridden method is explicitely annotated). Modified Paths: -------------- trunk/Pojomatic/src/main/java/org/pojomatic/internal/ClassProperties.java trunk/Pojomatic/src/test/java/org/pojomatic/internal/ClassPropertiesTest.java Added Paths: ----------- trunk/Pojomatic/src/main/java/org/pojomatic/internal/OverridableMethods.java trunk/Pojomatic/src/test/java/org/pojomatic/internal/OverridableMethodsTest.java trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/ trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C1.java trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C3.java trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/ trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C2.java trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C4.java Modified: trunk/Pojomatic/src/main/java/org/pojomatic/internal/ClassProperties.java =================================================================== --- trunk/Pojomatic/src/main/java/org/pojomatic/internal/ClassProperties.java 2009-08-16 15:05:21 UTC (rev 128) +++ trunk/Pojomatic/src/main/java/org/pojomatic/internal/ClassProperties.java 2009-08-16 17:17:24 UTC (rev 129) @@ -48,18 +48,20 @@ * with Pojomatic. */ private ClassProperties(Class<?> pojoClass) throws IllegalArgumentException { - walkHierarchy(pojoClass); + walkHierarchy(pojoClass, makeOverridableMethods()); verifyPropertiesNotEmpty(pojoClass); } - private void walkHierarchy(Class<?> clazz) { + private void walkHierarchy( + Class<?> clazz, Map<PropertyRole, OverridableMethods> overridableMethods) { if (clazz != Object.class) { - walkHierarchy(clazz.getSuperclass()); - extractClassProperties(clazz); + walkHierarchy(clazz.getSuperclass(), overridableMethods); + extractClassProperties(clazz, overridableMethods); } } - private void extractClassProperties(Class<?> clazz) { + private void extractClassProperties( + Class<?> clazz, Map<PropertyRole, OverridableMethods> overridableMethods) { AutoProperty autoProperty = clazz.getAnnotation(AutoProperty.class); final DefaultPojomaticPolicy classPolicy = (autoProperty != null) ? autoProperty.policy() : null; @@ -67,11 +69,14 @@ (autoProperty != null) ? autoProperty.autoDetect() : null; extractFields(clazz, classPolicy, autoDetectPolicy); - extractMethods(clazz, classPolicy, autoDetectPolicy); + extractMethods(clazz, classPolicy, autoDetectPolicy, overridableMethods); } - private void extractMethods(Class<?> clazz, final DefaultPojomaticPolicy classPolicy, - final AutoDetectPolicy autoDetectPolicy) { + private void extractMethods( + Class<?> clazz, + final DefaultPojomaticPolicy classPolicy, + final AutoDetectPolicy autoDetectPolicy, + final Map<PropertyRole, OverridableMethods> overridableMethods) { for (Method method : clazz.getDeclaredMethods()) { Property property = method.getAnnotation(Property.class); if (isStatic(method)) { @@ -98,11 +103,14 @@ continue; } - /* add all methods that are explicitly annotated or auto-detected */ - if (propertyPolicy != null || - (AutoDetectPolicy.METHOD == autoDetectPolicy && !isStatic(method))) { - addPropertyToRoles( - new PropertyAccessor(method, getPropertyName(property)), classPolicy, propertyPolicy); + /* add all methods that are explicitly annotated or auto-detected, and not overriding already + * added methods */ + if (propertyPolicy != null || AutoDetectPolicy.METHOD == autoDetectPolicy) { + for (PropertyRole role : PropertyFilter.getRoles(propertyPolicy, classPolicy)) { + if(overridableMethods.get(role).checkAndMaybeAddMethod(method)) { + properties.get(role).add(new PropertyAccessor(method, getPropertyName(property))); + } + } } } } @@ -126,21 +134,13 @@ /* add all fields that are explicitly annotated or auto-detected */ if (propertyPolicy != null || AutoDetectPolicy.FIELD == autoDetectPolicy) { - addPropertyToRoles( - new PropertyField(field, getPropertyName(property)), classPolicy, propertyPolicy); + for (PropertyRole role : PropertyFilter.getRoles(propertyPolicy, classPolicy)) { + properties.get(role).add(new PropertyField(field, getPropertyName(property))); + } } } } - private void addPropertyToRoles( - PropertyElement propertyElement, - final DefaultPojomaticPolicy classPolicy, - final PojomaticPolicy propertyPolicy) { - for (PropertyRole role : PropertyFilter.getRoles(propertyPolicy, classPolicy)) { - properties.get(role).add(propertyElement); - } - } - private void verifyPropertiesNotEmpty(Class<?> pojoClass) { for (Collection<PropertyElement> propertyElements : properties.values()) { if (!propertyElements.isEmpty()) { @@ -205,4 +205,15 @@ } return properties; } + + private Map<PropertyRole, OverridableMethods> makeOverridableMethods() { + Map<PropertyRole, OverridableMethods> overrideableMethods = + new EnumMap<PropertyRole, OverridableMethods>(PropertyRole.class); + for (PropertyRole role : PropertyRole.values()) { + overrideableMethods.put(role, new OverridableMethods()); + } + return overrideableMethods; + + } + } Added: trunk/Pojomatic/src/main/java/org/pojomatic/internal/OverridableMethods.java =================================================================== --- trunk/Pojomatic/src/main/java/org/pojomatic/internal/OverridableMethods.java (rev 0) +++ trunk/Pojomatic/src/main/java/org/pojomatic/internal/OverridableMethods.java 2009-08-16 17:17:24 UTC (rev 129) @@ -0,0 +1,68 @@ +package org.pojomatic.internal; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Set; + +/** + * A mutable set of methods which can be overridden. All methods are assumed to take no arguments + * and either public, protected or package private. + */ +class OverridableMethods { + /** + * Check a method to see if it is not an override; if not, add it to the collection of methods + * @param method the method to check and maybe add. It is assumed the method is not private. + * @return {@code true} if the method is not an override + */ + boolean checkAndMaybeAddMethod(Method method) { + if (isPackagePrivate(method)) { + // This can only override another package private method + return packageMethods.add(new PackageMethod(method)); + } + else { + // If there is a public method already declared, then this is an override. Otherwise, + // we need to track it as a public override going forward, even if it is overriding a + // superclass method which was declared package private. + return publicOrProtectedMethods.add(method.getName()) + && !packageMethods.contains(new PackageMethod(method)); + } + } + + /** + * A bean to track the package and name of a package-private method + */ + private class PackageMethod { + PackageMethod(Method method) { + name = method.getName(); + pakage = method.getDeclaringClass().getPackage(); + } + + String name; + Package pakage; + @Override public int hashCode() { + return name.hashCode() * 31 + pakage.hashCode(); + } + + @Override public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj instanceof PackageMethod) { + PackageMethod other = (PackageMethod)obj; + return name.equals(other.name) && pakage.equals(other.pakage); + } + else { + return false; + } + } + } + + private Set<String> publicOrProtectedMethods = new HashSet<String>(); + private Set<PackageMethod> packageMethods = new HashSet<PackageMethod>(); + + private static boolean isPackagePrivate(Method method) { + return !(Modifier.isPublic(method.getModifiers()) + || Modifier.isProtected(method.getModifiers())); + } + +} Property changes on: trunk/Pojomatic/src/main/java/org/pojomatic/internal/OverridableMethods.java ___________________________________________________________________ Added: svn:mime-type + text/plain Modified: trunk/Pojomatic/src/test/java/org/pojomatic/internal/ClassPropertiesTest.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/internal/ClassPropertiesTest.java 2009-08-16 15:05:21 UTC (rev 128) +++ trunk/Pojomatic/src/test/java/org/pojomatic/internal/ClassPropertiesTest.java 2009-08-16 17:17:24 UTC (rev 129) @@ -125,15 +125,26 @@ assertEquals(Collections.EMPTY_SET, asSet(parentClassProperties.getHashCodeProperties())); assertEquals(Collections.EMPTY_SET, asSet(parentClassProperties.getToStringProperties())); - ClassProperties childClassProperties = ClassProperties.createInstance(ChildAutoPojo.class); + ClassProperties childClassProperties = ClassProperties.createInstance(ChildAutoFieldPojo.class); Set<PropertyElement> expectedChild = asSet( - TestUtils.field(ChildAutoPojo.class, "other")); + TestUtils.field(ChildAutoFieldPojo.class, "other")); assertEquals(expectedParent, asSet(childClassProperties.getEqualsProperties())); assertEquals(Collections.EMPTY_SET, asSet(childClassProperties.getHashCodeProperties())); assertEquals(expectedChild, asSet(childClassProperties.getToStringProperties())); } @Test + public void testAutoInheritanceWithOverride() throws Exception { + ClassProperties childClassProperties = ClassProperties.createInstance(ChildAutoMethodPojo.class); + Set<PropertyElement> expected = asSet( + TestUtils.method(ParentPojo.class, "getFoo"), + TestUtils.method(ChildAutoMethodPojo.class, "getBar")); + assertEquals(expected, asSet(childClassProperties.getEqualsProperties())); + assertEquals(expected, asSet(childClassProperties.getHashCodeProperties())); + assertEquals(expected, asSet(childClassProperties.getToStringProperties())); + } + + @Test public void testAutoInheritanceAnnotatedParent() throws Exception { Set<PropertyElement> expectedParent = asSet(TestUtils.method(ParentPojo.class, "getFoo")); ClassProperties parentClassProperties = ClassProperties.createInstance(ParentPojo.class); @@ -144,7 +155,6 @@ ClassProperties childClassProperties = ClassProperties.createInstance(ChildExtendsAnnotatedPojo.class); Set<PropertyElement> expectedChild = asSet( TestUtils.method(ParentPojo.class, "getFoo"), - TestUtils.method(ChildExtendsAnnotatedPojo.class, "getFoo"), TestUtils.method(ChildExtendsAnnotatedPojo.class, "getMyString")); assertEquals(expectedChild, asSet(childClassProperties.getEqualsProperties())); assertEquals(expectedChild, asSet(childClassProperties.getHashCodeProperties())); @@ -296,6 +306,12 @@ } @AutoProperty(autoDetect=AutoDetectPolicy.METHOD) + public static class ChildAutoMethodPojo extends ParentPojo { + @Override public int getFoo() { return 2; } + public int getBar() { return 2; } + } + + @AutoProperty(autoDetect=AutoDetectPolicy.METHOD) public static class ChildExtendsAnnotatedPojo extends ParentPojo { @Override public int getFoo() { return 0; } @@ -309,7 +325,7 @@ } @AutoProperty(autoDetect=AutoDetectPolicy.FIELD, policy=DefaultPojomaticPolicy.TO_STRING) - public static class ChildAutoPojo extends ParentAutoPojo { + public static class ChildAutoFieldPojo extends ParentAutoPojo { public String other; @Override public int getFoo() { return 2; } Added: trunk/Pojomatic/src/test/java/org/pojomatic/internal/OverridableMethodsTest.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/internal/OverridableMethodsTest.java (rev 0) +++ trunk/Pojomatic/src/test/java/org/pojomatic/internal/OverridableMethodsTest.java 2009-08-16 17:17:24 UTC (rev 129) @@ -0,0 +1,49 @@ +package org.pojomatic.internal; + +import static org.junit.Assert.*; + +import java.lang.reflect.Method; + +import org.junit.Test; +import org.pojomatic.internal.a.C1; +import org.pojomatic.internal.a.C3; +import org.pojomatic.internal.b.C2; +import org.pojomatic.internal.b.C4; + + +public class OverridableMethodsTest { + + @Test public void testPackagePrivate() throws Exception { + checkMethod("packagePrivate", true, true, false, false); + } + + @Test public void testPackagePrivateToProtected() throws Exception { + checkMethod("packagePrivateOverriddenProtected", true, true, false, false); + } + + @Test public void testPackagePrivateToPublic() throws Exception { + checkMethod("packagePrivateOverriddenPublic", true, true, false, false); + } + + @Test public void testProtected() throws Exception { + checkMethod("protectedMethod", true, false, false, false); + } + + @Test public void testPublic() throws Exception { + checkMethod("publicMethod", true, false, false, false); + } + + private void checkMethod( + String methodName, boolean c1Add, boolean c2Add, boolean c3Add, boolean c4Add) + throws Exception { + OverridableMethods overridableMethods = new OverridableMethods(); + assertEquals(c1Add, overridableMethods.checkAndMaybeAddMethod(method(C1.class, methodName))); + assertEquals(c2Add, overridableMethods.checkAndMaybeAddMethod(method(C2.class, methodName))); + assertEquals(c3Add, overridableMethods.checkAndMaybeAddMethod(method(C3.class, methodName))); + assertEquals(c4Add, overridableMethods.checkAndMaybeAddMethod(method(C4.class, methodName))); + } + + private static Method method(Class<?> clazz, String name) throws Exception { + return clazz.getDeclaredMethod(name); + } +} Property changes on: trunk/Pojomatic/src/test/java/org/pojomatic/internal/OverridableMethodsTest.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C1.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C1.java (rev 0) +++ trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C1.java 2009-08-16 17:17:24 UTC (rev 129) @@ -0,0 +1,9 @@ +package org.pojomatic.internal.a; + +public class C1 { + int packagePrivate() { return 1; } + int packagePrivateOverriddenProtected() { return 1; } + int packagePrivateOverriddenPublic() { return 1; } + protected int protectedMethod() { return 1; } + public int publicMethod() { return 1; } +} Property changes on: trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C1.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C3.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C3.java (rev 0) +++ trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C3.java 2009-08-16 17:17:24 UTC (rev 129) @@ -0,0 +1,12 @@ +package org.pojomatic.internal.a; + +import org.pojomatic.internal.b.C2; + +@SuppressWarnings("all") +public class C3 extends C2 { + int packagePrivate() { return 3; } + protected int packagePrivateOverriddenProtected() { return 3; } + public int packagePrivateOverriddenPublic() { return 3; } + protected int protectedMethod() { return 3; } + public int publicMethod() { return 3; } +} Property changes on: trunk/Pojomatic/src/test/java/org/pojomatic/internal/a/C3.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C2.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C2.java (rev 0) +++ trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C2.java 2009-08-16 17:17:24 UTC (rev 129) @@ -0,0 +1,12 @@ +package org.pojomatic.internal.b; + +import org.pojomatic.internal.a.C1; + +@SuppressWarnings("all") +public class C2 extends C1 { + int packagePrivate() { return 1; } + protected int packagePrivateOverriddenProtected() { return 2; } + public int packagePrivateOverriddenPublic() { return 2; } + protected int protectedMethod() { return 2; } + public int publicMethod() { return 2; } +} Property changes on: trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C2.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C4.java =================================================================== --- trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C4.java (rev 0) +++ trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C4.java 2009-08-16 17:17:24 UTC (rev 129) @@ -0,0 +1,12 @@ +package org.pojomatic.internal.b; + +import org.pojomatic.internal.a.C3; + +@SuppressWarnings("all") +public class C4 extends C3 { + int packagePrivate() { return 4; } + protected int packagePrivateOverriddenProtected() { return 4; } + public int packagePrivateOverriddenPublic() { return 4; } + protected int protectedMethod() { return 4; } + public int publicMethod() { return 4; } +} Property changes on: trunk/Pojomatic/src/test/java/org/pojomatic/internal/b/C4.java ___________________________________________________________________ Added: svn:mime-type + text/plain This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |