/* * Copyright 2002-2007 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.util; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.rmi.ConnectException; import java.rmi.RemoteException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import junit.framework.TestCase; import org.springframework.beans.TestBean; import org.springframework.test.AssertThrows; /** * <p> * JUnit 3.8 based unit tests for {@link ReflectionUtils}. * </p> * * @author Rob Harrop * @author Juergen Hoeller * @author Sam Brannen */ public class ReflectionUtilsTests extends TestCase { public void testFindField() { Field field; field = ReflectionUtils.findField(TestBeanSubclassWithPublicField.class, "publicField", String.class); assertNotNull(field); assertEquals("publicField", field.getName()); assertEquals(String.class, field.getType()); assertTrue("Field should be public.", Modifier.isPublic(field.getModifiers())); field = ReflectionUtils.findField(TestBeanSubclassWithNewField.class, "prot", String.class); assertNotNull(field); assertEquals("prot", field.getName()); assertEquals(String.class, field.getType()); assertTrue("Field should be protected.", Modifier.isProtected(field.getModifiers())); field = ReflectionUtils.findField(TestBeanSubclassWithNewField.class, "name", String.class); assertNotNull(field); assertEquals("name", field.getName()); assertEquals(String.class, field.getType()); assertTrue("Field should be private.", Modifier.isPrivate(field.getModifiers())); } public void testSetField() { final TestBeanSubclassWithNewField testBean = new TestBeanSubclassWithNewField(); final Field field = ReflectionUtils.findField(TestBeanSubclassWithNewField.class, "name", String.class); new AssertThrows(IllegalStateException.class, "Calling setField() with on a private field without making it accessible should throw an IllegalStateException.") { public void test() throws Exception { ReflectionUtils.setField(field, testBean, "FooBar"); } }.runTest(); ReflectionUtils.makeAccessible(field); ReflectionUtils.setField(field, testBean, "FooBar"); assertNotNull(testBean.getName()); assertEquals("FooBar", testBean.getName()); ReflectionUtils.setField(field, testBean, null); assertNull(testBean.getName()); } public void testInvokeMethod() throws Exception { String rob = "Rob Harrop"; String juergen = "Juergen Hoeller"; TestBean bean = new TestBean(); bean.setName(rob); Method getName = TestBean.class.getMethod("getName", (Class[]) null); Method setName = TestBean.class.getMethod("setName", new Class[] { String.class }); Object name = ReflectionUtils.invokeMethod(getName, bean); assertEquals("Incorrect name returned", rob, name); ReflectionUtils.invokeMethod(setName, bean, new Object[] { juergen }); assertEquals("Incorrect name set", juergen, bean.getName()); } public void testDeclaresException() throws Exception { Method remoteExMethod = A.class.getDeclaredMethod("foo", new Class[] {Integer.class}); assertTrue(ReflectionUtils.declaresException(remoteExMethod, RemoteException.class)); assertTrue(ReflectionUtils.declaresException(remoteExMethod, ConnectException.class)); assertFalse(ReflectionUtils.declaresException(remoteExMethod, NoSuchMethodException.class)); assertFalse(ReflectionUtils.declaresException(remoteExMethod, Exception.class)); Method illegalExMethod = B.class.getDeclaredMethod("bar", new Class[] {String.class}); assertTrue(ReflectionUtils.declaresException(illegalExMethod, IllegalArgumentException.class)); assertTrue(ReflectionUtils.declaresException(illegalExMethod, NumberFormatException.class)); assertFalse(ReflectionUtils.declaresException(illegalExMethod, IllegalStateException.class)); assertFalse(ReflectionUtils.declaresException(illegalExMethod, Exception.class)); } public void testCopySrcToDestinationOfIncorrectClass() { TestBean src = new TestBean(); String dest = new String(); try { ReflectionUtils.shallowCopyFieldState(src, dest); fail(); } catch (IllegalArgumentException ex) { // Ok } } public void testRejectsNullSrc() { TestBean src = null; String dest = new String(); try { ReflectionUtils.shallowCopyFieldState(src, dest); fail(); } catch (IllegalArgumentException ex) { // Ok } } public void testRejectsNullDest() { TestBean src = new TestBean(); String dest = null; try { ReflectionUtils.shallowCopyFieldState(src, dest); fail(); } catch (IllegalArgumentException ex) { // Ok } } public void testValidCopy() { TestBean src = new TestBean(); TestBean dest = new TestBean(); testValidCopy(src, dest); } public void testValidCopyOnSubTypeWithNewField() { TestBeanSubclassWithNewField src = new TestBeanSubclassWithNewField(); TestBeanSubclassWithNewField dest = new TestBeanSubclassWithNewField(); src.magic = 11; // Will check inherited fields are copied testValidCopy(src, dest); // Check subclass fields were copied assertEquals(src.magic, dest.magic); assertEquals(src.prot, dest.prot); } public void testValidCopyToSubType() { TestBean src = new TestBean(); TestBeanSubclassWithNewField dest = new TestBeanSubclassWithNewField(); dest.magic = 11; testValidCopy(src, dest); // Should have left this one alone assertEquals(11, dest.magic); } public void testValidCopyToSubTypeWithFinalField() { TestBeanSubclassWithFinalField src = new TestBeanSubclassWithFinalField(); TestBeanSubclassWithFinalField dest = new TestBeanSubclassWithFinalField(); // Check that this doesn't fail due to attempt to assign final testValidCopy(src, dest); } private void testValidCopy(TestBean src, TestBean dest) { src.setName("freddie"); src.setAge(15); src.setSpouse(new TestBean()); assertFalse(src.getAge() == dest.getAge()); ReflectionUtils.shallowCopyFieldState(src, dest); assertEquals(src.getAge(), dest.getAge()); assertEquals(src.getSpouse(), dest.getSpouse()); assertEquals(src.getDoctor(), dest.getDoctor()); } static class ListSavingMethodCallback implements ReflectionUtils.MethodCallback { private List methodNames = new LinkedList(); private List methods = new LinkedList(); public void doWith(Method m) throws IllegalArgumentException, IllegalAccessException { this.methodNames.add(m.getName()); this.methods.add(m); } public List getMethodNames() { return this.methodNames; } public List getMethods() { return this.methods; } }; public void testDoWithProtectedMethods() { ListSavingMethodCallback mc = new ListSavingMethodCallback(); ReflectionUtils.doWithMethods(TestBean.class, mc, new ReflectionUtils.MethodFilter() { public boolean matches(Method m) { return Modifier.isProtected(m.getModifiers()); } }); assertFalse(mc.getMethodNames().isEmpty()); assertTrue("Must find protected method on Object", mc.getMethodNames().contains("clone")); assertTrue("Must find protected method on Object", mc.getMethodNames().contains("finalize")); assertFalse("Public, not protected", mc.getMethodNames().contains("hashCode")); assertFalse("Public, not protected", mc.getMethodNames().contains("absquatulate")); } public static class TestBeanSubclass extends TestBean { public void absquatulate() { throw new UnsupportedOperationException(); } } public void testDuplicatesFound() { ListSavingMethodCallback mc = new ListSavingMethodCallback(); ReflectionUtils.doWithMethods(TestBeanSubclass.class, mc); int absquatulateCount = 0; for (Iterator it = mc.getMethodNames().iterator(); it.hasNext();) { String name = (String) it.next(); if (name.equals("absquatulate")) { ++absquatulateCount; } } assertEquals("Found 2 absquatulates", 2, absquatulateCount); } public void testFindMethod() throws Exception { assertNotNull(ReflectionUtils.findMethod(B.class, "bar", new Class[]{String.class})); assertNotNull(ReflectionUtils.findMethod(B.class, "foo", new Class[]{Integer.class})); } public static class TestBeanSubclassWithPublicField extends TestBean { public String publicField = "foo"; } public static class TestBeanSubclassWithNewField extends TestBean { private int magic; protected String prot = "foo"; } public static class TestBeanSubclassWithFinalField extends TestBean { private final String foo = "will break naive copy that doesn't exclude statics"; } private static class A { private void foo(Integer i) throws RemoteException {} } private static class B extends A { void bar(String s) throws IllegalArgumentException {} } }