From 8d3ec50e875cc91b752017163abeb0da076b5acc Mon Sep 17 00:00:00 2001 From: Marten Deinum Date: Mon, 14 Mar 2016 15:54:50 +0100 Subject: [PATCH 1/6] Support proxied objects in ReflectionTestUtils This commit adds support for unwrapping proxies in the setField() and getField() methods in ReflectionTestUtils. Instead of always accessing fields directly on the supplied targetObject (which may be a proxy), AopTestUtils is now used to obtain the potential ultimateTargetObject which is then used for accessing fields. Issue: SPR-14050 --- .../test/util/ReflectionTestUtils.java | 12 ++++--- .../test/util/ReflectionTestUtilsTests.java | 34 +++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java index f40227fb8c8..65fe04fb846 100644 --- a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java +++ b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java @@ -159,8 +159,10 @@ public class ReflectionTestUtils { Assert.isTrue(targetObject != null || targetClass != null, "Either targetObject or targetClass for the field must be specified"); + Object ultimateTargetObject = AopTestUtils.getUltimateTargetObject(targetObject); + if (targetClass == null) { - targetClass = targetObject.getClass(); + targetClass = ultimateTargetObject.getClass(); } Field field = ReflectionUtils.findField(targetClass, name, type); @@ -176,7 +178,7 @@ public class ReflectionTestUtils { targetObject, targetClass, value)); } ReflectionUtils.makeAccessible(field); - ReflectionUtils.setField(field, targetObject, value); + ReflectionUtils.setField(field, ultimateTargetObject, value); } /** @@ -234,8 +236,10 @@ public class ReflectionTestUtils { Assert.isTrue(targetObject != null || targetClass != null, "Either targetObject or targetClass for the field must be specified"); + Object ultimateTargetObject = AopTestUtils.getUltimateTargetObject(targetObject); + if (targetClass == null) { - targetClass = targetObject.getClass(); + targetClass = ultimateTargetObject.getClass(); } Field field = ReflectionUtils.findField(targetClass, name); @@ -250,7 +254,7 @@ public class ReflectionTestUtils { targetObject, targetClass)); } ReflectionUtils.makeAccessible(field); - return ReflectionUtils.getField(field, targetObject); + return ReflectionUtils.getField(field, ultimateTargetObject); } /** diff --git a/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java b/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java index fa692ed9b12..572eea0169d 100644 --- a/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java +++ b/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java @@ -22,6 +22,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.aop.framework.ProxyCreatorSupport; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.AopUtils; import org.springframework.test.util.subpackage.Component; import org.springframework.test.util.subpackage.LegacyEntity; import org.springframework.test.util.subpackage.Person; @@ -359,4 +362,35 @@ public class ReflectionTestUtilsTests { invokeMethod(component, "configure", new Integer(42), "enigma", "baz", "quux"); } + @Test + public void setAndGetFieldOnProxiedInstance() throws Exception { + ProxyFactory pf = new ProxyFactory(this.person); + pf.setProxyTargetClass(true); + + Person proxyPerson = (Person) pf.getProxy(); + + setField(proxyPerson, "id", new Long(99), long.class); + setField(proxyPerson, "name", "Tom"); + setField(proxyPerson, "age", new Integer(42)); + setField(proxyPerson, "eyeColor", "blue", String.class); + setField(proxyPerson, "likesPets", Boolean.TRUE); + setField(proxyPerson, "favoriteNumber", PI, Number.class); + + assertEquals("ID (private field in a superclass)", 99, person.getId()); + assertEquals("name (protected field)", "Tom", person.getName()); + assertEquals("age (private field)", 42, person.getAge()); + assertEquals("eye color (package private field)", "blue", person.getEyeColor()); + assertEquals("'likes pets' flag (package private boolean field)", true, person.likesPets()); + assertEquals("'favorite number' (package field)", PI, person.getFavoriteNumber()); + + assertEquals(new Long(99), getField(proxyPerson, "id")); + assertEquals("Tom", getField(proxyPerson, "name")); + assertEquals(new Integer(42), getField(proxyPerson, "age")); + assertEquals("blue", getField(proxyPerson, "eyeColor")); + assertEquals(Boolean.TRUE, getField(proxyPerson, "likesPets")); + assertEquals(PI, getField(proxyPerson, "favoriteNumber")); + + + } + } From 7c7e7865bf456c782dc28d460bcd224f3bc31286 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 15 Mar 2016 19:13:40 +0100 Subject: [PATCH 2/6] Polishing --- .../test/util/AopTestUtils.java | 3 +- .../test/util/ReflectionTestUtils.java | 3 +- .../test/util/ReflectionTestUtilsTests.java | 66 +++++++++---------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/util/AopTestUtils.java b/spring-test/src/main/java/org/springframework/test/util/AopTestUtils.java index 4eda8a45ac2..7660ee2cef8 100644 --- a/spring-test/src/main/java/org/springframework/test/util/AopTestUtils.java +++ b/spring-test/src/main/java/org/springframework/test/util/AopTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ import org.springframework.util.Assert; * @since 4.2 * @see org.springframework.aop.support.AopUtils * @see org.springframework.aop.framework.AopProxyUtils + * @see ReflectionTestUtils */ public class AopTestUtils { diff --git a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java index 65fe04fb846..c41a487ef19 100644 --- a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java +++ b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +60,7 @@ import org.springframework.util.StringUtils; * @author Juergen Hoeller * @since 2.5 * @see ReflectionUtils + * @see AopTestUtils */ public class ReflectionTestUtils { diff --git a/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java b/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java index 572eea0169d..0504075fc85 100644 --- a/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java +++ b/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.springframework.aop.framework.ProxyCreatorSupport; import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.AopUtils; import org.springframework.test.util.subpackage.Component; import org.springframework.test.util.subpackage.LegacyEntity; import org.springframework.test.util.subpackage.Person; @@ -131,6 +129,37 @@ public class ReflectionTestUtilsTests { assertEquals(PI, getField(person, "favoriteNumber")); } + @Test + public void setFieldAndGetFieldOnCglibProxiedInstance() throws Exception { + ProxyFactory pf = new ProxyFactory(this.person); + pf.setProxyTargetClass(true); + Person proxyPerson = (Person) pf.getProxy(); + + // Set reflectively via Proxy + setField(proxyPerson, "id", new Long(99), long.class); + setField(proxyPerson, "name", "Tom"); + setField(proxyPerson, "age", new Integer(42)); + setField(proxyPerson, "eyeColor", "blue", String.class); + setField(proxyPerson, "likesPets", Boolean.TRUE); + setField(proxyPerson, "favoriteNumber", PI, Number.class); + + // Get directly from Target via getter methods + assertEquals("ID (private field in a superclass)", 99, this.person.getId()); + assertEquals("name (protected field)", "Tom", this.person.getName()); + assertEquals("age (private field)", 42, this.person.getAge()); + assertEquals("eye color (package private field)", "blue", this.person.getEyeColor()); + assertEquals("'likes pets' flag (package private boolean field)", true, this.person.likesPets()); + assertEquals("'favorite number' (package field)", PI, this.person.getFavoriteNumber()); + + // Get reflectively via Proxy + assertEquals(new Long(99), getField(proxyPerson, "id")); + assertEquals("Tom", getField(proxyPerson, "name")); + assertEquals(new Integer(42), getField(proxyPerson, "age")); + assertEquals("blue", getField(proxyPerson, "eyeColor")); + assertEquals(Boolean.TRUE, getField(proxyPerson, "likesPets")); + assertEquals(PI, getField(proxyPerson, "favoriteNumber")); + } + @Test public void setFieldWithNullValuesForNonPrimitives() throws Exception { // Fields must be non-null to start with @@ -362,35 +391,4 @@ public class ReflectionTestUtilsTests { invokeMethod(component, "configure", new Integer(42), "enigma", "baz", "quux"); } - @Test - public void setAndGetFieldOnProxiedInstance() throws Exception { - ProxyFactory pf = new ProxyFactory(this.person); - pf.setProxyTargetClass(true); - - Person proxyPerson = (Person) pf.getProxy(); - - setField(proxyPerson, "id", new Long(99), long.class); - setField(proxyPerson, "name", "Tom"); - setField(proxyPerson, "age", new Integer(42)); - setField(proxyPerson, "eyeColor", "blue", String.class); - setField(proxyPerson, "likesPets", Boolean.TRUE); - setField(proxyPerson, "favoriteNumber", PI, Number.class); - - assertEquals("ID (private field in a superclass)", 99, person.getId()); - assertEquals("name (protected field)", "Tom", person.getName()); - assertEquals("age (private field)", 42, person.getAge()); - assertEquals("eye color (package private field)", "blue", person.getEyeColor()); - assertEquals("'likes pets' flag (package private boolean field)", true, person.likesPets()); - assertEquals("'favorite number' (package field)", PI, person.getFavoriteNumber()); - - assertEquals(new Long(99), getField(proxyPerson, "id")); - assertEquals("Tom", getField(proxyPerson, "name")); - assertEquals(new Integer(42), getField(proxyPerson, "age")); - assertEquals("blue", getField(proxyPerson, "eyeColor")); - assertEquals(Boolean.TRUE, getField(proxyPerson, "likesPets")); - assertEquals(PI, getField(proxyPerson, "favoriteNumber")); - - - } - } From 2d565c7944fbb205ea093302deee336f41b11c29 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 15 Mar 2016 19:14:13 +0100 Subject: [PATCH 3/6] Fix bugs in ReflectionTestUtils related to proxies Issue: SPR-14050 --- .../org/springframework/test/util/ReflectionTestUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java index c41a487ef19..156d5c3960d 100644 --- a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java +++ b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java @@ -160,7 +160,8 @@ public class ReflectionTestUtils { Assert.isTrue(targetObject != null || targetClass != null, "Either targetObject or targetClass for the field must be specified"); - Object ultimateTargetObject = AopTestUtils.getUltimateTargetObject(targetObject); + Object ultimateTargetObject = (targetObject == null ? null + : AopTestUtils.getUltimateTargetObject(targetObject)); if (targetClass == null) { targetClass = ultimateTargetObject.getClass(); @@ -237,7 +238,8 @@ public class ReflectionTestUtils { Assert.isTrue(targetObject != null || targetClass != null, "Either targetObject or targetClass for the field must be specified"); - Object ultimateTargetObject = AopTestUtils.getUltimateTargetObject(targetObject); + Object ultimateTargetObject = (targetObject == null ? null + : AopTestUtils.getUltimateTargetObject(targetObject)); if (targetClass == null) { targetClass = ultimateTargetObject.getClass(); From b1ca18e0dc0579defdc7ccaa6bb862185412ac92 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 15 Mar 2016 19:15:38 +0100 Subject: [PATCH 4/6] Document proxy support in ReflectionTestUtils Issue: SPR-14050 --- .../org/springframework/test/util/ReflectionTestUtils.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java index 156d5c3960d..71fb0da9367 100644 --- a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java +++ b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java @@ -138,6 +138,9 @@ public class ReflectionTestUtils { * Set the {@linkplain Field field} with the given {@code name}/{@code type} * on the provided {@code targetObject}/{@code targetClass} to the supplied * {@code value}. + *

If the supplied {@code targetObject} is a proxy, it will + * be {@linkplain AopTestUtils#getUltimateTargetObject unwrapped} allowing + * the field to be set on the ultimate target of the proxy. *

This method traverses the class hierarchy in search of the desired * field. In addition, an attempt will be made to make non-{@code public} * fields accessible, thus allowing one to set {@code protected}, @@ -154,6 +157,7 @@ public class ReflectionTestUtils { * @see ReflectionUtils#findField(Class, String, Class) * @see ReflectionUtils#makeAccessible(Field) * @see ReflectionUtils#setField(Field, Object, Object) + * @see AopTestUtils#getUltimateTargetObject(Object) * @since 4.2 */ public static void setField(Object targetObject, Class targetClass, String name, Object value, Class type) { @@ -217,6 +221,9 @@ public class ReflectionTestUtils { /** * Get the value of the {@linkplain Field field} with the given {@code name} * from the provided {@code targetObject}/{@code targetClass}. + *

If the supplied {@code targetObject} is a proxy, it will + * be {@linkplain AopTestUtils#getUltimateTargetObject unwrapped} allowing + * the field to be retrieved from the ultimate target of the proxy. *

This method traverses the class hierarchy in search of the desired * field. In addition, an attempt will be made to make non-{@code public} * fields accessible, thus allowing one to get {@code protected}, From 7beff7b40a177445ae88c1eb9e890f34db34c863 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Wed, 16 Mar 2016 17:11:43 +0100 Subject: [PATCH 5/6] Polishing --- .../test/util/ReflectionTestUtils.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java index 71fb0da9367..378f6628482 100644 --- a/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java +++ b/spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java @@ -164,27 +164,26 @@ public class ReflectionTestUtils { Assert.isTrue(targetObject != null || targetClass != null, "Either targetObject or targetClass for the field must be specified"); - Object ultimateTargetObject = (targetObject == null ? null - : AopTestUtils.getUltimateTargetObject(targetObject)); + Object ultimateTarget = (targetObject != null ? AopTestUtils.getUltimateTargetObject(targetObject) : null); if (targetClass == null) { - targetClass = ultimateTargetObject.getClass(); + targetClass = ultimateTarget.getClass(); } Field field = ReflectionUtils.findField(targetClass, name, type); if (field == null) { throw new IllegalArgumentException(String.format( "Could not find field '%s' of type [%s] on target object [%s] or target class [%s]", name, type, - targetObject, targetClass)); + ultimateTarget, targetClass)); } if (logger.isDebugEnabled()) { logger.debug(String.format( "Setting field '%s' of type [%s] on target object [%s] or target class [%s] to value [%s]", name, type, - targetObject, targetClass, value)); + ultimateTarget, targetClass, value)); } ReflectionUtils.makeAccessible(field); - ReflectionUtils.setField(field, ultimateTargetObject, value); + ReflectionUtils.setField(field, ultimateTarget, value); } /** @@ -245,26 +244,25 @@ public class ReflectionTestUtils { Assert.isTrue(targetObject != null || targetClass != null, "Either targetObject or targetClass for the field must be specified"); - Object ultimateTargetObject = (targetObject == null ? null - : AopTestUtils.getUltimateTargetObject(targetObject)); + Object ultimateTarget = (targetObject != null ? AopTestUtils.getUltimateTargetObject(targetObject) : null); if (targetClass == null) { - targetClass = ultimateTargetObject.getClass(); + targetClass = ultimateTarget.getClass(); } Field field = ReflectionUtils.findField(targetClass, name); if (field == null) { throw new IllegalArgumentException( String.format("Could not find field '%s' on target object [%s] or target class [%s]", name, - targetObject, targetClass)); + ultimateTarget, targetClass)); } if (logger.isDebugEnabled()) { logger.debug(String.format("Getting field '%s' from target object [%s] or target class [%s]", name, - targetObject, targetClass)); + ultimateTarget, targetClass)); } ReflectionUtils.makeAccessible(field); - return ReflectionUtils.getField(field, ultimateTargetObject); + return ReflectionUtils.getField(field, ultimateTarget); } /** From d9025ddaa7f8a409e1d4fb417c6cd1b8aa79b318 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Wed, 16 Mar 2016 17:14:19 +0100 Subject: [PATCH 6/6] Fully test proxy support in ReflectionTestUtils This commit adds a test for JDK dynamic proxies and fleshes out the test for CGLIB proxies. Issue: SPR-14050 --- .../test/util/ReflectionTestUtilsTests.java | 85 ++++++++-------- .../util/subpackage/PersistentEntity.java | 7 +- .../test/util/subpackage/Person.java | 84 +++------------- .../test/util/subpackage/PersonEntity.java | 96 +++++++++++++++++++ 4 files changed, 159 insertions(+), 113 deletions(-) create mode 100644 spring-test/src/test/java/org/springframework/test/util/subpackage/PersonEntity.java diff --git a/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java b/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java index 0504075fc85..0216e362f75 100644 --- a/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java +++ b/spring-test/src/test/java/org/springframework/test/util/ReflectionTestUtilsTests.java @@ -23,9 +23,11 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.AopUtils; import org.springframework.test.util.subpackage.Component; import org.springframework.test.util.subpackage.LegacyEntity; import org.springframework.test.util.subpackage.Person; +import org.springframework.test.util.subpackage.PersonEntity; import org.springframework.test.util.subpackage.StaticFields; import static org.hamcrest.CoreMatchers.*; @@ -42,12 +44,12 @@ public class ReflectionTestUtilsTests { private static final Float PI = new Float((float) 22 / 7); - private final Person person = new Person(); + private final Person person = new PersonEntity(); private final Component component = new Component(); @Rule - public ExpectedException exception = ExpectedException.none(); + public final ExpectedException exception = ExpectedException.none(); @Before @@ -55,7 +57,6 @@ public class ReflectionTestUtilsTests { StaticFields.reset(); } - @Test public void setFieldWithNullTargetObject() throws Exception { exception.expect(IllegalArgumentException.class); @@ -107,6 +108,29 @@ public class ReflectionTestUtilsTests { @Test public void setFieldAndGetFieldForStandardUseCases() throws Exception { + assertSetFieldAndGetFieldBehavior(this.person); + } + + @Test + public void setFieldAndGetFieldViaJdkDynamicProxy() throws Exception { + ProxyFactory pf = new ProxyFactory(this.person); + pf.addInterface(Person.class); + Person proxy = (Person) pf.getProxy(); + assertTrue("Proxy is a JDK dynamic proxy", AopUtils.isJdkDynamicProxy(proxy)); + assertSetFieldAndGetFieldBehaviorForProxy(proxy, this.person); + } + + @Test + public void setFieldAndGetFieldViaCglibProxy() throws Exception { + ProxyFactory pf = new ProxyFactory(this.person); + pf.setProxyTargetClass(true); + Person proxy = (Person) pf.getProxy(); + assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy)); + assertSetFieldAndGetFieldBehaviorForProxy(proxy, this.person); + } + + private static void assertSetFieldAndGetFieldBehavior(Person person) { + // Set reflectively setField(person, "id", new Long(99), long.class); setField(person, "name", "Tom"); setField(person, "age", new Integer(42)); @@ -114,50 +138,33 @@ public class ReflectionTestUtilsTests { setField(person, "likesPets", Boolean.TRUE); setField(person, "favoriteNumber", PI, Number.class); - assertEquals("ID (private field in a superclass)", 99, person.getId()); - assertEquals("name (protected field)", "Tom", person.getName()); - assertEquals("age (private field)", 42, person.getAge()); - assertEquals("eye color (package private field)", "blue", person.getEyeColor()); - assertEquals("'likes pets' flag (package private boolean field)", true, person.likesPets()); - assertEquals("'favorite number' (package field)", PI, person.getFavoriteNumber()); - + // Get reflectively assertEquals(new Long(99), getField(person, "id")); assertEquals("Tom", getField(person, "name")); assertEquals(new Integer(42), getField(person, "age")); assertEquals("blue", getField(person, "eyeColor")); assertEquals(Boolean.TRUE, getField(person, "likesPets")); assertEquals(PI, getField(person, "favoriteNumber")); + + // Get directly + assertEquals("ID (private field in a superclass)", 99, person.getId()); + assertEquals("name (protected field)", "Tom", person.getName()); + assertEquals("age (private field)", 42, person.getAge()); + assertEquals("eye color (package private field)", "blue", person.getEyeColor()); + assertEquals("'likes pets' flag (package private boolean field)", true, person.likesPets()); + assertEquals("'favorite number' (package field)", PI, person.getFavoriteNumber()); } - @Test - public void setFieldAndGetFieldOnCglibProxiedInstance() throws Exception { - ProxyFactory pf = new ProxyFactory(this.person); - pf.setProxyTargetClass(true); - Person proxyPerson = (Person) pf.getProxy(); - - // Set reflectively via Proxy - setField(proxyPerson, "id", new Long(99), long.class); - setField(proxyPerson, "name", "Tom"); - setField(proxyPerson, "age", new Integer(42)); - setField(proxyPerson, "eyeColor", "blue", String.class); - setField(proxyPerson, "likesPets", Boolean.TRUE); - setField(proxyPerson, "favoriteNumber", PI, Number.class); - - // Get directly from Target via getter methods - assertEquals("ID (private field in a superclass)", 99, this.person.getId()); - assertEquals("name (protected field)", "Tom", this.person.getName()); - assertEquals("age (private field)", 42, this.person.getAge()); - assertEquals("eye color (package private field)", "blue", this.person.getEyeColor()); - assertEquals("'likes pets' flag (package private boolean field)", true, this.person.likesPets()); - assertEquals("'favorite number' (package field)", PI, this.person.getFavoriteNumber()); - - // Get reflectively via Proxy - assertEquals(new Long(99), getField(proxyPerson, "id")); - assertEquals("Tom", getField(proxyPerson, "name")); - assertEquals(new Integer(42), getField(proxyPerson, "age")); - assertEquals("blue", getField(proxyPerson, "eyeColor")); - assertEquals(Boolean.TRUE, getField(proxyPerson, "likesPets")); - assertEquals(PI, getField(proxyPerson, "favoriteNumber")); + private static void assertSetFieldAndGetFieldBehaviorForProxy(Person proxy, Person target) { + assertSetFieldAndGetFieldBehavior(proxy); + + // Get directly from Target + assertEquals("ID (private field in a superclass)", 99, target.getId()); + assertEquals("name (protected field)", "Tom", target.getName()); + assertEquals("age (private field)", 42, target.getAge()); + assertEquals("eye color (package private field)", "blue", target.getEyeColor()); + assertEquals("'likes pets' flag (package private boolean field)", true, target.likesPets()); + assertEquals("'favorite number' (package field)", PI, target.getFavoriteNumber()); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/util/subpackage/PersistentEntity.java b/spring-test/src/test/java/org/springframework/test/util/subpackage/PersistentEntity.java index 3ff3d91dfd7..4f34e2e85b0 100644 --- a/spring-test/src/test/java/org/springframework/test/util/subpackage/PersistentEntity.java +++ b/spring-test/src/test/java/org/springframework/test/util/subpackage/PersistentEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2011 the original author or authors. + * Copyright 2007-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,11 +28,12 @@ public abstract class PersistentEntity { private long id; - public final long getId() { + public long getId() { return this.id; } - protected final void setId(long id) { + protected void setId(long id) { this.id = id; } + } diff --git a/spring-test/src/test/java/org/springframework/test/util/subpackage/Person.java b/spring-test/src/test/java/org/springframework/test/util/subpackage/Person.java index b89f56167fd..20177ed098b 100644 --- a/spring-test/src/test/java/org/springframework/test/util/subpackage/Person.java +++ b/spring-test/src/test/java/org/springframework/test/util/subpackage/Person.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,85 +16,27 @@ package org.springframework.test.util.subpackage; -import org.springframework.core.style.ToStringCreator; - /** - * Concrete subclass of {@link PersistentEntity} representing a person - * entity; intended for use in unit tests. + * Interface representing a person entity; intended for use in unit tests. + * + *

The introduction of an interface is necessary in order to test support for + * JDK dynamic proxies. * * @author Sam Brannen - * @since 2.5 + * @since 4.3 */ -public class Person extends PersistentEntity { - - protected String name; - - private int age; - - String eyeColor; - - boolean likesPets = false; - - private Number favoriteNumber; - - - public final String getName() { - return this.name; - } - - @SuppressWarnings("unused") - private final void setName(final String name) { - this.name = name; - } - - public final int getAge() { - return this.age; - } - - protected final void setAge(final int age) { - this.age = age; - } - - public final String getEyeColor() { - return this.eyeColor; - } - - final void setEyeColor(final String eyeColor) { - this.eyeColor = eyeColor; - } - - public final boolean likesPets() { - return this.likesPets; - } - - protected final void setLikesPets(final boolean likesPets) { - this.likesPets = likesPets; - } - - public final Number getFavoriteNumber() { - return this.favoriteNumber; - } - - protected final void setFavoriteNumber(Number favoriteNumber) { - this.favoriteNumber = favoriteNumber; - } - - @Override - public String toString() { - return new ToStringCreator(this) +public interface Person { - .append("id", this.getId()) + long getId(); - .append("name", this.name) + String getName(); - .append("age", this.age) + int getAge(); - .append("eyeColor", this.eyeColor) + String getEyeColor(); - .append("likesPets", this.likesPets) + boolean likesPets(); - .append("favoriteNumber", this.favoriteNumber) + Number getFavoriteNumber(); - .toString(); - } } diff --git a/spring-test/src/test/java/org/springframework/test/util/subpackage/PersonEntity.java b/spring-test/src/test/java/org/springframework/test/util/subpackage/PersonEntity.java new file mode 100644 index 00000000000..1cdff47bec3 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/util/subpackage/PersonEntity.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * 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 org.springframework.test.util.subpackage; + +import org.springframework.core.style.ToStringCreator; + +/** + * Concrete subclass of {@link PersistentEntity} representing a person + * entity; intended for use in unit tests. + * + * @author Sam Brannen + * @since 2.5 + */ +public class PersonEntity extends PersistentEntity implements Person { + + protected String name; + + private int age; + + String eyeColor; + + boolean likesPets = false; + + private Number favoriteNumber; + + + public String getName() { + return this.name; + } + + @SuppressWarnings("unused") + private void setName(final String name) { + this.name = name; + } + + public int getAge() { + return this.age; + } + + protected void setAge(final int age) { + this.age = age; + } + + public String getEyeColor() { + return this.eyeColor; + } + + void setEyeColor(final String eyeColor) { + this.eyeColor = eyeColor; + } + + public boolean likesPets() { + return this.likesPets; + } + + protected void setLikesPets(final boolean likesPets) { + this.likesPets = likesPets; + } + + public Number getFavoriteNumber() { + return this.favoriteNumber; + } + + protected void setFavoriteNumber(Number favoriteNumber) { + this.favoriteNumber = favoriteNumber; + } + + @Override + public String toString() { + // @formatter:off + return new ToStringCreator(this) + .append("id", this.getId()) + .append("name", this.name) + .append("age", this.age) + .append("eyeColor", this.eyeColor) + .append("likesPets", this.likesPets) + .append("favoriteNumber", this.favoriteNumber) + .toString(); + // @formatter:on + } + +}