package com.cedarsoftware.util; import org.junit.Assert; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Calendar; import java.util.Collection; import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * @author John DeRegnaucourt (john@cedarsoftware.com) * <br> * Copyright (c) Cedar Software LLC * <br><br> * 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 * <br><br> * http://www.apache.org/licenses/LICENSE-2.0 * <br><br> * 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. */ public class TestReflectionUtils { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited public @interface ControllerClass { } @ControllerClass static class Foo { } static class Bar extends Foo { } @ControllerClass static interface Baz { } static interface Qux extends Baz { } static class Beta implements Qux { } static class Alpha extends Beta { } static interface Blart { } static class Bogus implements Blart { } public interface AAA { } public interface BBB extends AAA { } public class CCC implements BBB, AAA { } @Test public void testConstructorIsPrivate() throws Exception { Constructor<ReflectionUtils> con = ReflectionUtils.class.getDeclaredConstructor(); Assert.assertEquals(Modifier.PRIVATE, con.getModifiers() & Modifier.PRIVATE); con.setAccessible(true); Assert.assertNotNull(con.newInstance()); } @Test public void testClassAnnotation() { Annotation a = ReflectionUtils.getClassAnnotation(Bar.class, ControllerClass.class); assertNotNull(a); assertTrue(a instanceof ControllerClass); a = ReflectionUtils.getClassAnnotation(Alpha.class, ControllerClass.class); assertNotNull(a); assertTrue(a instanceof ControllerClass); a = ReflectionUtils.getClassAnnotation(Bogus.class, ControllerClass.class); assertNull(a); a = ReflectionUtils.getClassAnnotation(CCC.class, ControllerClass.class); assertNull(a); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ControllerMethod { String allow(); } static class Foo1 { @ControllerMethod(allow = "false") public void yelp() { } } static class Bar1 extends Foo1 { } static interface Baz1 { @ControllerMethod(allow = "false") void yelp(); } static interface Qux1 extends Baz1 { } static class Beta1 implements Qux1 { public void yelp() { } } static class Alpha1 extends Beta1 { } static interface Blart1 { void yelp(); } static class Bogus1 implements Blart1 { public void yelp() { } } @Test public void testMethodAnnotation() throws Exception { Method m = ReflectionUtils.getMethod(Bar1.class, "yelp"); Annotation a = ReflectionUtils.getMethodAnnotation(m, ControllerMethod.class); assertNotNull(a); assertTrue(a instanceof ControllerMethod); assertEquals("false", ((ControllerMethod) a).allow()); m = ReflectionUtils.getMethod(Alpha1.class, "yelp"); a = ReflectionUtils.getMethodAnnotation(m, ControllerMethod.class); assertNotNull(a); assertTrue(a instanceof ControllerMethod); m = ReflectionUtils.getMethod(Bogus1.class, "yelp"); a = ReflectionUtils.getMethodAnnotation(m, ControllerMethod.class); assertNull(a); } @Test(expected=ThreadDeath.class) public void testGetDeclaredFields() throws Exception { Class c = Parent.class; Field f = c.getDeclaredField("foo"); Collection<Field> fields = mock(Collection.class); when(fields.add(f)).thenThrow(new ThreadDeath()); ReflectionUtils.getDeclaredFields(Parent.class, fields); } @Test public void testDeepDeclaredFields() throws Exception { Calendar c = Calendar.getInstance(); Collection<Field> fields = ReflectionUtils.getDeepDeclaredFields(c.getClass()); assertTrue(fields.size() > 0); boolean miss = true; boolean found = false; for (Field field : fields) { if ("firstDayOfWeek".equals(field.getName())) { found = true; break; } if ("blart".equals(field.getName())) { miss = false; } } assertTrue(found); assertTrue(miss); } @Test public void testDeepDeclaredFieldMap() throws Exception { Calendar c = Calendar.getInstance(); Map<String, Field> fields = ReflectionUtils.getDeepDeclaredFieldMap(c.getClass()); assertTrue(fields.size() > 0); assertTrue(fields.containsKey("firstDayOfWeek")); assertFalse(fields.containsKey("blart")); Map<String, Field> test2 = ReflectionUtils.getDeepDeclaredFieldMap(Child.class); assertEquals(2, test2.size()); assertTrue(test2.containsKey("com.cedarsoftware.util.TestReflectionUtils$Parent.foo")); assertFalse(test2.containsKey("com.cedarsoftware.util.TestReflectionUtils$Child.foo")); } @Test public void testGetClassName() throws Exception { assertEquals("null", ReflectionUtils.getClassName((Object)null)); assertEquals("java.lang.String", ReflectionUtils.getClassName("item")); } @Test public void testGetClassAnnotationsWithNull() throws Exception { assertNull(ReflectionUtils.getClassAnnotation(null, null)); } private class Parent { private String foo; } private class Child extends Parent { private String foo; } }