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(); + private static void assertSetFieldAndGetFieldBehaviorForProxy(Person proxy, Person target) { + assertSetFieldAndGetFieldBehavior(proxy); - // 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")); + // 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 { +public interface Person { - protected String name; + long getId(); - private int age; + String getName(); - String eyeColor; + int getAge(); - boolean likesPets = false; + String getEyeColor(); - private Number favoriteNumber; + boolean likesPets(); + Number getFavoriteNumber(); - 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) - - .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(); - } } 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 + } + +}