This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 9a7244898192302d6293c5d2944e2492c6a83a1c
Author: JamesBognar <[email protected]>
AuthorDate: Sun Apr 21 21:11:17 2019 -0400

    New org.apache.juneau.reflect package and @Name annotation.
---
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../java/org/apache/juneau/PojoExamplesTest.java   |   4 +-
 ...ructorInfoTest.java => AnnotationInfoTest.java} |  81 ++--
 .../apache/juneau/reflection/ClassInfoTest.java    | 158 ++++++--
 .../juneau/reflection/ConstructorInfoTest.java     | 111 ++++--
 .../juneau/reflection/ExecutableInfoTest.java      | 180 +++++++--
 .../apache/juneau/reflection/FieldInfoTest.java    | 353 ++++++++++++++++++
 .../apache/juneau/reflection/MethodInfoTest.java   | 406 +++++++++++++++-----
 .../apache/juneau/reflection/ParamInfoTest.java    | 409 +++++++++++++++++++++
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../src/main/java/org/apache/juneau/BeanMeta.java  |  35 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java |  12 +-
 .../main/java/org/apache/juneau/UriContext.java    |   4 +-
 .../apache/juneau/annotation/BeanConstructor.java  |  16 +-
 .../org/apache/juneau/annotation/BeanProperty.java |   2 +
 .../AnnotationInfo.java => annotation/Name.java}   | 123 +++----
 .../juneau/httppart/HttpPartSchemaBuilder.java     |   2 +-
 .../httppart/bean/RequestBeanPropertyMeta.java     |   2 +-
 .../juneau/httppart/bean/ResponseBeanMeta.java     |   2 +-
 .../org/apache/juneau/internal/ClassUtils.java     |   5 +-
 .../org/apache/juneau/reflect/AnnotationInfo.java  |   2 +-
 .../java/org/apache/juneau/reflect/ClassInfo.java  |  69 +++-
 .../org/apache/juneau/reflect/ExecutableInfo.java  |   5 +
 .../java/org/apache/juneau/reflect/FieldInfo.java  |  59 ++-
 .../java/org/apache/juneau/reflect/MethodInfo.java |  76 ++--
 .../java/org/apache/juneau/reflect/ParamInfo.java  |  99 ++---
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 juneau-doc/docs/ReleaseNotes/8.0.1.html            |   2 +
 .../10.Transforms/08.BeanAnnotation.html           |   2 +-
 .../10.Transforms/09.BeanPropertyAnnotation.html   |  11 +-
 .../10.BeanConstructorAnnotation.html              |  16 +-
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../org/apache/juneau/examples/core/pojo/Pojo.java |   6 +-
 .../juneau/examples/core/pojo/PojoComplex.java     |   4 +-
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 juneau-releng/juneau-all/.project                  |   6 -
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../.settings/org.eclipse.jdt.core.prefs           |   3 +-
 .../org/apache/juneau/rest/RestJavaMethod.java     |   2 +-
 .../org/apache/juneau/rest/SwaggerGenerator.java   |  16 +-
 45 files changed, 1819 insertions(+), 497 deletions(-)

diff --git a/juneau-core/juneau-core-test/.settings/org.eclipse.jdt.core.prefs 
b/juneau-core/juneau-core-test/.settings/org.eclipse.jdt.core.prefs
index 4b04196..bb79aba 100644
--- a/juneau-core/juneau-core-test/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-core/juneau-core-test/.settings/org.eclipse.jdt.core.prefs
@@ -1,6 +1,6 @@
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -10,6 +10,7 @@ org.eclipse.jdt.core.compiler.debug.sourceFile=generate
 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PojoExamplesTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PojoExamplesTest.java
index 2e4db72..d0bd98f 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PojoExamplesTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PojoExamplesTest.java
@@ -204,12 +204,12 @@ public class PojoExamplesTest {
                try {
                        bs.getClassMeta(F1.class);
                } catch (Exception e) {
-                       assertContains(e.getMessage(), "@Example used on 
invalid method 'org.apache.juneau.PojoExamplesTest$F1.example(String)'");
+                       assertContains(e.getMessage(), "@Example used on 
invalid method 'example(String)'");
                }
                try {
                        bs.getClassMeta(F2.class);
                } catch (Exception e) {
-                       assertContains(e.getMessage(), "@Example used on 
invalid method 'org.apache.juneau.PojoExamplesTest$F2.example()'");
+                       assertContains(e.getMessage(), "@Example used on 
invalid method 'example()'");
                }
                try {
                        bs.getClassMeta(F3.class);
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/AnnotationInfoTest.java
similarity index 53%
copy from 
juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
copy to 
juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/AnnotationInfoTest.java
index 32ac2cd..3d6bf13 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/AnnotationInfoTest.java
@@ -12,73 +12,37 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.reflection;
 
-import static org.apache.juneau.reflect.ConstructorInfo.*;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
 import static org.junit.Assert.*;
 
-import java.lang.reflect.*;
-import java.util.*;
+import java.lang.annotation.*;
 import java.util.function.*;
-import java.util.stream.*;
 
 import org.apache.juneau.reflect.*;
 import org.junit.*;
 
-public class ConstructorInfoTest {
+public class AnnotationInfoTest {
 
        private static void check(String expected, Object o) {
-               if (o instanceof List) {
-                       List<?> l = (List<?>)o;
-                       String actual = l
-                               .stream()
-                               .map(TO_STRING)
-                               .collect(Collectors.joining(","));
-                       assertEquals(expected, actual);
-               } else if (o instanceof Iterable) {
-                       String actual = 
StreamSupport.stream(((Iterable<?>)o).spliterator(), false)
-                               .map(TO_STRING)
-                               .collect(Collectors.joining(","));
-                       assertEquals(expected, actual);
-               } else {
-                       assertEquals(expected, TO_STRING.apply(o));
-               }
+               assertEquals(expected, TO_STRING.apply(o));
        }
 
        private static final Function<Object,String> TO_STRING = new 
Function<Object,String>() {
                @Override
                public String apply(Object t) {
-                       if (t == null)
-                               return null;
-                       if (t instanceof Class)
-                               return ((Class<?>)t).getSimpleName();
-                       if (t instanceof Constructor) {
-                               Constructor<?> x = (Constructor<?>)t;
-                               return x.getDeclaringClass().getSimpleName() + 
'(' + argTypes(x.getParameterTypes()) + ')';
-                       }
-//                     if (t instanceof Package)
-//                             return ((Package)t).getName();
+                       if (t instanceof A)
+                               return "@A(" + ((A)t).value() + ")";
                        if (t instanceof ClassInfo)
                                return ((ClassInfo)t).getSimpleName();
-//                     if (t instanceof MethodInfo)
-//                             return 
((MethodInfo)t).getDeclaringClass().getSimpleName() + '.' + 
((MethodInfo)t).getLabel();
-//                     if (t instanceof ConstructorInfo)
-//                             return ((ConstructorInfo)t).getLabel();
-//                     if (t instanceof FieldInfo)
-//                             return 
((FieldInfo)t).getDeclaringClass().getSimpleName() + '.' + 
((FieldInfo)t).getLabel();
-//                     if (t instanceof AnnotationInfo)
-//                             return 
apply(((AnnotationInfo<?>)t).getAnnotation());
                        return t.toString();
                }
        };
 
-       private static String argTypes(Class<?>[] t) {
-               return Arrays.asList(t).stream().map(x -> 
x.getSimpleName()).collect(Collectors.joining(","));
-       }
-
-       private static ConstructorInfo ofc(Class<?> c, Class<?>...pt) {
+       private static ClassInfo of(Class<?> c) {
                try {
-                       return of(c.getConstructor(pt));
-               } catch (NoSuchMethodException | SecurityException e) {
-                       e.printStackTrace();
+                       return ClassInfo.of(c);
+               } catch (SecurityException e) {
                        fail(e.getLocalizedMessage());
                }
                return null;
@@ -88,20 +52,25 @@ public class ConstructorInfoTest {
        // Instantiation.
        
//-----------------------------------------------------------------------------------------------------------------
 
-       static class A {
-               public A() {}
+       @Documented
+       @Target(TYPE)
+       @Retention(RUNTIME)
+       @Inherited
+       public static @interface A {
+               int value();
        }
-       ConstructorInfo a = ofc(A.class);
+
+       @A(1)
+       static class B {}
+       static ClassInfo b = of(B.class);
 
        @Test
-       public void of_noDeclaringClass() throws Exception {
-               check("A()", a.inner());
+       public void getClassOn() {
+               check("B", b.getAnnotationInfos(A.class).get(0).getClassOn());
        }
 
        @Test
-       public void getDeclaringClass() throws Exception {
-               check("A", a.getDeclaringClass());
+       public void getAnnotation() {
+               check("@A(1)", 
b.getAnnotationInfos(A.class).get(0).getAnnotation());
        }
-
-
-}
+}
\ No newline at end of file
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
index 60cbbfa..640b1c0 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
@@ -101,8 +101,8 @@ public class ClassInfoTest {
        public class A2 extends Value<A1>{};
        public class A3 extends Value<Map<String,List<String>>>{};
        public class A4 extends Value<Map<String,String[][]>>{};
-       public Type aType, pType, pTypeDimensional, pTypeGeneric, 
pTypeGenericArg;
-       {
+       public static Type aType, pType, pTypeDimensional, pTypeGeneric, 
pTypeGenericArg;
+       static {
                aType = 
((ParameterizedType)A2.class.getGenericSuperclass()).getActualTypeArguments()[0];
                pType = 
((ParameterizedType)A3.class.getGenericSuperclass()).getActualTypeArguments()[0];
                pTypeDimensional = 
((ParameterizedType)A4.class.getGenericSuperclass()).getActualTypeArguments()[0];
@@ -111,8 +111,8 @@ public class ClassInfoTest {
                pTypeGenericArg = 
((ParameterizedType)pTypeGeneric).getActualTypeArguments()[1];
        }
 
-       public ClassInfo aTypeInfo=of(aType), pTypeInfo=of(pType), 
pTypeDimensionalInfo=of(pTypeDimensional), pTypeGenericInfo=of(pTypeGeneric), 
pTypeGenericArgInfo=of(pTypeGenericArg);
-       public ClassInfo aClass=of(AClass.class), 
aInterface=of(AInterface.class);
+       static ClassInfo aTypeInfo=of(aType), pTypeInfo=of(pType), 
pTypeDimensionalInfo=of(pTypeDimensional), pTypeGenericInfo=of(pTypeGeneric), 
pTypeGenericArgInfo=of(pTypeGenericArg);
+       static ClassInfo aClass=of(AClass.class), 
aInterface=of(AInterface.class);
 
        @Test
        public void ofType() {
@@ -161,7 +161,7 @@ public class ClassInfoTest {
        static class BC2 extends BC1 implements BI3 {}
        static class BC3 extends BC2 {}
 
-       ClassInfo bi1=of(BI1.class), bi2=of(BI2.class), bi3=of(BI3.class), 
bi4=of(BI4.class), bc1=of(BC1.class), bc2=of(BC2.class), bc3=of(BC3.class), 
object=of(Object.class);
+       static ClassInfo bi1=of(BI1.class), bi2=of(BI2.class), 
bi3=of(BI3.class), bi4=of(BI4.class), bc1=of(BC1.class), bc2=of(BC2.class), 
bc3=of(BC3.class), object=of(Object.class);
 
        @Test
        public void getDeclaredInterfaces() {
@@ -289,7 +289,7 @@ public class ClassInfoTest {
                public void c3a() {}
                protected void c3b() {}
        }
-       ClassInfo cc3 = of(CC3.class), ci2 = of(CI2.class);
+       static ClassInfo cc3 = of(CC3.class), ci2 = of(CI2.class);
 
        @Test
        public void getPublicMethods() throws Exception {
@@ -350,6 +350,46 @@ public class ClassInfoTest {
                check("", pTypeGenericArgInfo.getDeclaredMethods());
        }
 
+       static class C2 {
+               public void a1() {}
+               public void a2(int x){}
+               void b1() {}
+               void b2(int x){}
+       }
+       static ClassInfo c2 = ClassInfo.of(C2.class);
+
+       @Test
+       public void getPublicMethod_noArgs() {
+               check("C2.a1()", c2.getPublicMethod("a1"));
+               check(null, c2.getPublicMethod("a2"));
+               check(null, c2.getPublicMethod("b1"));
+               check(null, c2.getPublicMethod("b2"));
+       }
+
+       @Test
+       public void getPublicMethod_withArgs() {
+               check(null, c2.getPublicMethod("a1", int.class));
+               check("C2.a2(int)", c2.getPublicMethod("a2", int.class));
+               check(null, c2.getPublicMethod("b1", int.class));
+               check(null, c2.getPublicMethod("b2", int.class));
+       }
+
+       @Test
+       public void getMethod_noArgs() {
+               check("C2.a1()", c2.getMethod("a1"));
+               check(null, c2.getMethod("a2"));
+               check("C2.b1()", c2.getMethod("b1"));
+               check(null, c2.getMethod("b2"));
+       }
+
+       @Test
+       public void getMethod_withArgs() {
+               check(null, c2.getMethod("a1", int.class));
+               check("C2.a2(int)", c2.getMethod("a2", int.class));
+               check(null, c2.getMethod("b1", int.class));
+               check("C2.b2(int)", c2.getMethod("b2", int.class));
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Special methods
        
//-----------------------------------------------------------------------------------------------------------------
@@ -379,7 +419,7 @@ public class ClassInfoTest {
        static class DA8 {
                public static DA8 create2(String s1) {return null;}
        }
-       ClassInfo da1=of(DA1.class), da2=of(DA2.class), da3=of(DA3.class), 
da4=of(DA4.class), da5=of(DA5.class), da6=of(DA6.class), da7=of(DA7.class), 
da8=of(DA8.class);
+       static ClassInfo da1=of(DA1.class), da2=of(DA2.class), 
da3=of(DA3.class), da4=of(DA4.class), da5=of(DA5.class), da6=of(DA6.class), 
da7=of(DA7.class), da8=of(DA8.class);
 
        @Test
        public void getFromStringMethod() throws Exception {
@@ -434,7 +474,7 @@ public class ClassInfoTest {
        static class DB11 {
                public static DB11 fromFoo(DBx x) {return null;}
        }
-       ClassInfo db1=of(DB1.class), db2=of(DB2.class), db3=of(DB3.class), 
db4=of(DB4.class), db5=of(DB5.class), db6=of(DB6.class), db7=of(DB7.class), 
db8=of(DB8.class), db9=of(DB9.class), db10=of(DB10.class), db11=of(DB11.class);
+       static ClassInfo db1=of(DB1.class), db2=of(DB2.class), 
db3=of(DB3.class), db4=of(DB4.class), db5=of(DB5.class), db6=of(DB6.class), 
db7=of(DB7.class), db8=of(DB8.class), db9=of(DB9.class), db10=of(DB10.class), 
db11=of(DB11.class);
 
        @Test
        public void getStaticCreateMethod() throws Exception {
@@ -473,7 +513,7 @@ public class ClassInfoTest {
        static class DC5 {
                public static DCx createFoo() {return null;}
        }
-       ClassInfo dc1=of(DC1.class), dc2=of(DC2.class), dc3=of(DC3.class), 
dc4=of(DC4.class), dc5=of(DC5.class);
+       static ClassInfo dc1=of(DC1.class), dc2=of(DC2.class), 
dc3=of(DC3.class), dc4=of(DC4.class), dc5=of(DC5.class);
 
        @Test
        public void getBuilderCreateMethod() throws Exception {
@@ -500,7 +540,7 @@ public class ClassInfoTest {
        static class DD5 {
                public DDx build(String x) {return null;}
        }
-       ClassInfo dd1=of(DD1.class), dd2=of(DD2.class), dd3=of(DD3.class), 
dd4=of(DD4.class), dd5=of(DD5.class);
+       static ClassInfo dd1=of(DD1.class), dd2=of(DD2.class), 
dd3=of(DD3.class), dd4=of(DD4.class), dd5=of(DD5.class);
 
        @Test
        public void getBuilderBuildMethod() throws Exception {
@@ -539,7 +579,7 @@ public class ClassInfoTest {
        class E6 {
                public E6(String a) {}
        }
-       ClassInfo e1=of(E1.class), e2=of(E2.class), e3=of(E3.class), 
e4=of(E4.class), e5=of(E5.class), e6=of(E6.class);
+       static ClassInfo e1=of(E1.class), e2=of(E2.class), e3=of(E3.class), 
e4=of(E4.class), e5=of(E5.class), e6=of(E6.class);
 
        @Test
        public void getPublicConstructors() {
@@ -636,6 +676,13 @@ public class ClassInfoTest {
                check("E5()", e5.getConstructor(Visibility.PUBLIC));
        }
 
+       @Test
+       public void getDeclaredConstructor() {
+               check("E1()", e1.getDeclaredConstructor());
+               check("E1(int)", e1.getDeclaredConstructor(int.class));
+               check(null, e1.getDeclaredConstructor(Object.class));
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Fields
        
//-----------------------------------------------------------------------------------------------------------------
@@ -650,7 +697,7 @@ public class ClassInfoTest {
                @Deprecated int f2c;
                protected int f2d;
        }
-       ClassInfo f1=of(F1.class), f2=of(F2.class);
+       static ClassInfo f1=of(F1.class), f2=of(F2.class);
 
        @Test
        public void getPublicFields() {
@@ -719,6 +766,26 @@ public class ClassInfoTest {
                check("F1.f1a,F1.f1b,F2.f1a,F2.f2b,F2.f2c,F2.f2d", 
f2.getAllFieldsParentFirst());
        }
 
+       static class F3 {
+               public int a1;
+               int a2;
+       }
+       static ClassInfo f3=of(F3.class);
+
+       @Test
+       public void getPublicField() {
+               check("F3.a1", f3.getPublicField("a1"));
+               check(null, f3.getPublicField("a2"));
+               check(null, f3.getPublicField("a3"));
+       }
+
+       @Test
+       public void getDeclaredField() {
+               check("F3.a1", f3.getDeclaredField("a1"));
+               check("F3.a2", f3.getDeclaredField("a2"));
+               check(null, f3.getDeclaredField("a3"));
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Annotations
        
//-----------------------------------------------------------------------------------------------------------------
@@ -742,7 +809,7 @@ public class ClassInfoTest {
 
        static class G5 implements GI3 {}
 
-       ClassInfo g3=of(G3.class), g4=of(G4.class), g5=of(G5.class);
+       static ClassInfo g3=of(G3.class), g4=of(G4.class), g5=of(G5.class);
 
        @Test
        public void getAnnotation() {
@@ -795,6 +862,11 @@ public class ClassInfoTest {
        }
 
        @Test
+       public void getDeclaredAnnotation_null() {
+               check(null, g3.getDeclaredAnnotation(null));
+       }
+
+       @Test
        public void getDeclaredAnnotation_twice() {
                check("@A(7)", g3.getDeclaredAnnotation(A.class));
                check("@A(7)", g3.getDeclaredAnnotation(A.class));
@@ -858,7 +930,7 @@ public class ClassInfoTest {
        public abstract class H_AbstractPublic {}
        @Deprecated public class H_PublicDeprecated {}
 
-       ClassInfo hPublic=of(H_Public.class), hPackage=of(H_Package.class), 
hProtected=of(H_Protected.class), hPrivate=of(H_Private.class), 
hPublicMember=of(H_PublicMember.class), 
hAbstractPublic=of(H_AbstractPublic.class), 
hPublicDeprecated=of(H_PublicDeprecated.class);
+       static ClassInfo hPublic=of(H_Public.class), 
hPackage=of(H_Package.class), hProtected=of(H_Protected.class), 
hPrivate=of(H_Private.class), hPublicMember=of(H_PublicMember.class), 
hAbstractPublic=of(H_AbstractPublic.class), 
hPublicDeprecated=of(H_PublicDeprecated.class);
 
        @Test
        public void isDeprecated() {
@@ -1165,7 +1237,7 @@ public class ClassInfoTest {
        abstract class H2_Abstract {}
        class H2_NotAbstract {}
 
-       ClassInfo h2a=of(H2a.class), h2b=of(H2b.class), 
h2Deprecated=of(H2_Deprecated.class), 
h2NotDeprecated=of(H2_NotDeprecated.class), h2Public=of(H2_Public.class), 
h2NotPublic=of(H2_NotPublic.class), h2Static=of(H2_Static.class), 
h2NotStatic=of(H2_NotStatic.class), h2Member=of(H2_Member.class), 
h2StaticMember=of(H2_StaticMember.class), h2Abstract=of(H2_Abstract.class), 
h2NotAbstract=of(H2_NotAbstract.class);
+       static ClassInfo h2a=of(H2a.class), h2b=of(H2b.class), 
h2Deprecated=of(H2_Deprecated.class), 
h2NotDeprecated=of(H2_NotDeprecated.class), h2Public=of(H2_Public.class), 
h2NotPublic=of(H2_NotPublic.class), h2Static=of(H2_Static.class), 
h2NotStatic=of(H2_NotStatic.class), h2Member=of(H2_Member.class), 
h2StaticMember=of(H2_StaticMember.class), h2Abstract=of(H2_Abstract.class), 
h2NotAbstract=of(H2_NotAbstract.class);
 
        @Test
        public void isAll() {
@@ -1399,9 +1471,9 @@ public class ClassInfoTest {
        // Primitive wrappers
        
//-----------------------------------------------------------------------------------------------------------------
 
-       List<Class<?>> primitives = 
AList.create(boolean.class,byte.class,short.class,char.class,int.class,long.class,float.class,double.class);
-       List<Class<?>> primitiveWrappers = 
AList.create(Boolean.class,Byte.class,Short.class,Character.class,Integer.class,Long.class,Float.class,Double.class);
-       List<Object> primitiveDefaults = 
AList.create(false,(byte)0,(short)0,(char)0,0,0l,0f,0d);
+       static List<Class<?>> primitives = 
AList.create(boolean.class,byte.class,short.class,char.class,int.class,long.class,float.class,double.class);
+       static List<Class<?>> primitiveWrappers = 
AList.create(Boolean.class,Byte.class,Short.class,Character.class,Integer.class,Long.class,Float.class,Double.class);
+       static List<Object> primitiveDefaults = 
AList.create(false,(byte)0,(short)0,(char)0,0,0l,0f,0d);
 
        @Test
        public void hasPrimitiveWrapper() {
@@ -1466,6 +1538,7 @@ public class ClassInfoTest {
        @Test
        public void getWrapperInfoIfPrimitive_onType() {
                assertEquals(aTypeInfo.getWrapperInfoIfPrimitive().innerType(), 
aType);
+               check("V", pTypeGenericArgInfo.getWrapperInfoIfPrimitive());
        }
 
        @Test
@@ -1487,7 +1560,7 @@ public class ClassInfoTest {
        public class J1 {}
        public static class J2 {}
 
-       ClassInfo j1=of(J1.class), j2=of(J2.class), j1_3d=of(J1[][].class), 
j2_3d=of(J2[][].class);
+       static ClassInfo j1=of(J1.class), j2=of(J2.class), 
j1_3d=of(J1[][].class), j2_3d=of(J2[][].class);
 
        @Test
        public void getFullName_simple() {
@@ -1700,6 +1773,14 @@ public class ClassInfoTest {
                assertEquals("LocalClass", 
of(LocalClass.class).getSimpleName());
        }
 
+       @Test
+       public void getName() {
+               assertEquals("org.apache.juneau.reflection.AClass", 
aClass.getName());
+               assertEquals("java.util.AbstractMap", 
pTypeGenericInfo.getName());
+               assertEquals("V", pTypeGenericArgInfo.getName());
+       }
+
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Hierarchy
        
//-----------------------------------------------------------------------------------------------------------------
@@ -1708,7 +1789,7 @@ public class ClassInfoTest {
        public static class KB implements KA {}
        public static class KC extends KB {}
 
-       public ClassInfo ka=of(KA.class), kb=of(KB.class), kc=of(KC.class);
+       static ClassInfo ka=of(KA.class), kb=of(KB.class), kc=of(KC.class);
 
 
        @Test
@@ -1840,6 +1921,39 @@ public class ClassInfoTest {
        }
 
        @Test
+       public void is_ClassInfo() {
+               assertTrue(ka.is(of(KA.class)));
+               assertFalse(ka.is(of(KB.class)));
+               assertFalse(ka.is(of(KC.class)));
+               assertFalse(kb.is(of(KA.class)));
+               assertTrue(kb.is(of(KB.class)));
+               assertFalse(kb.is(of(KC.class)));
+               assertFalse(kc.is(of(KA.class)));
+               assertFalse(kc.is(of(KB.class)));
+               assertTrue(kc.is(of(KC.class)));
+       }
+
+       @Test
+       public void is_ClassInfo_genType() {
+               assertFalse(pTypeGenericArgInfo.is(of(KA.class)));
+       }
+
+       @Test
+       public void isAnyType() {
+               assertTrue(ka.isAny(KA.class));
+               assertTrue(ka.isAny(KA.class, KB.class));
+               assertFalse(ka.isAny(KB.class));
+               assertFalse(ka.isAny(KC.class));
+               assertFalse(kb.isAny(KA.class));
+               assertTrue(kb.isAny(KB.class));
+               assertFalse(kb.isAny(KC.class));
+               assertFalse(kc.isAny(KA.class));
+               assertFalse(kc.isAny(KB.class));
+               assertTrue(kc.isAny(KC.class));
+       }
+
+
+       @Test
        public void is_type() {
                assertFalse(aTypeInfo.is(KA.class));
                assertFalse(pTypeInfo.is(KA.class));
@@ -1918,7 +2032,7 @@ public class ClassInfoTest {
 
        public static class LA {}
 
-       ClassInfo la=of(LA.class);
+       static ClassInfo la=of(LA.class);
 
        @Test
        public void newInstance() {
@@ -1998,7 +2112,7 @@ public class ClassInfoTest {
        }
 
 
-       ClassInfo ma=of(MA.class), mb=of(MB.class), mc=of(MC.class), 
md=of(MD.class), me=of(ME.class), mf=of(MF.class), mg=of(MG.class), 
mh=of(MH.class), mi=of(MI.class), mj=of(MJ.class), ml=of(ML.class), 
mn=of(MM.MN.class);
+       static ClassInfo ma=of(MA.class), mb=of(MB.class), mc=of(MC.class), 
md=of(MD.class), me=of(ME.class), mf=of(MF.class), mg=of(MG.class), 
mh=of(MH.class), mi=of(MI.class), mj=of(MJ.class), ml=of(ML.class), 
mn=of(MM.MN.class);
 
        @Test
        public void getParameterType_simpleMap() {
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
index 32ac2cd..9712a30 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ConstructorInfoTest.java
@@ -20,27 +20,14 @@ import java.util.*;
 import java.util.function.*;
 import java.util.stream.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.reflect.*;
 import org.junit.*;
 
 public class ConstructorInfoTest {
 
        private static void check(String expected, Object o) {
-               if (o instanceof List) {
-                       List<?> l = (List<?>)o;
-                       String actual = l
-                               .stream()
-                               .map(TO_STRING)
-                               .collect(Collectors.joining(","));
-                       assertEquals(expected, actual);
-               } else if (o instanceof Iterable) {
-                       String actual = 
StreamSupport.stream(((Iterable<?>)o).spliterator(), false)
-                               .map(TO_STRING)
-                               .collect(Collectors.joining(","));
-                       assertEquals(expected, actual);
-               } else {
-                       assertEquals(expected, TO_STRING.apply(o));
-               }
+               assertEquals(expected, TO_STRING.apply(o));
        }
 
        private static final Function<Object,String> TO_STRING = new 
Function<Object,String>() {
@@ -48,37 +35,22 @@ public class ConstructorInfoTest {
                public String apply(Object t) {
                        if (t == null)
                                return null;
-                       if (t instanceof Class)
-                               return ((Class<?>)t).getSimpleName();
-                       if (t instanceof Constructor) {
-                               Constructor<?> x = (Constructor<?>)t;
-                               return x.getDeclaringClass().getSimpleName() + 
'(' + argTypes(x.getParameterTypes()) + ')';
-                       }
-//                     if (t instanceof Package)
-//                             return ((Package)t).getName();
+                       if (t instanceof Iterable)
+                               return 
StreamSupport.stream(((Iterable<?>)t).spliterator(), 
false).map(this).collect(Collectors.joining(","));
                        if (t instanceof ClassInfo)
                                return ((ClassInfo)t).getSimpleName();
-//                     if (t instanceof MethodInfo)
-//                             return 
((MethodInfo)t).getDeclaringClass().getSimpleName() + '.' + 
((MethodInfo)t).getLabel();
-//                     if (t instanceof ConstructorInfo)
-//                             return ((ConstructorInfo)t).getLabel();
-//                     if (t instanceof FieldInfo)
-//                             return 
((FieldInfo)t).getDeclaringClass().getSimpleName() + '.' + 
((FieldInfo)t).getLabel();
-//                     if (t instanceof AnnotationInfo)
-//                             return 
apply(((AnnotationInfo<?>)t).getAnnotation());
+                       if (t instanceof ConstructorInfo)
+                               return ((ConstructorInfo)t).getShortName();
+                       if (t instanceof Constructor)
+                               return 
ConstructorInfo.of((Constructor<?>)t).getShortName();
                        return t.toString();
                }
        };
 
-       private static String argTypes(Class<?>[] t) {
-               return Arrays.asList(t).stream().map(x -> 
x.getSimpleName()).collect(Collectors.joining(","));
-       }
-
        private static ConstructorInfo ofc(Class<?> c, Class<?>...pt) {
                try {
                        return of(c.getConstructor(pt));
                } catch (NoSuchMethodException | SecurityException e) {
-                       e.printStackTrace();
                        fail(e.getLocalizedMessage());
                }
                return null;
@@ -91,7 +63,12 @@ public class ConstructorInfoTest {
        static class A {
                public A() {}
        }
-       ConstructorInfo a = ofc(A.class);
+       static ConstructorInfo a = ofc(A.class);
+
+       @Test
+       public void of_withDeclaringClass() throws Exception {
+               check("A()", ConstructorInfo.of(ClassInfo.of(A.class), 
a.inner()));
+       }
 
        @Test
        public void of_noDeclaringClass() throws Exception {
@@ -103,5 +80,63 @@ public class ConstructorInfoTest {
                check("A", a.getDeclaringClass());
        }
 
+       @Test
+       public void of_null() throws Exception {
+               check(null, ConstructorInfo.of(null));
+               check(null, ConstructorInfo.of(null, null));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Other methods
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       public static class B {
+               private String f;
+               public B() {}
+               public B(String f) {
+                       this.f = f;
+               }
+               public B(String f, String f2) {
+                       this.f = f;
+               }
+               protected B(int f) {}
+               @Override
+               public String toString() {
+                       return f;
+               }
+       }
+       static ClassInfo b = ClassInfo.of(B.class);
+       static ConstructorInfo
+               b_c1 = b.getPublicConstructor(),
+               b_c2 = b.getPublicConstructor(String.class),
+               b_c3 = b.getDeclaredConstructor(int.class),
+               b_c4 = b.getPublicConstructor(String.class, String.class);
 
-}
+
+       @Test
+       public void invoke() {
+               try {
+                       assertEquals(null, b_c1.invoke().toString());
+                       assertEquals("foo", b_c2.invoke("foo").toString());
+               } catch (Exception e) {
+                       fail(e.getLocalizedMessage());
+               }
+       }
+
+       @Test
+       public void makeAccessible() {
+               b_c3.makeAccessible(Visibility.PROTECTED);
+               try {
+                       assertEquals(null, b_c3.invoke(123).toString());
+               } catch (Exception e) {
+                       fail(e.getLocalizedMessage());
+               }
+       }
+
+       @Test
+       public void compareTo() {
+               Set<ConstructorInfo> s = new TreeSet<>(Arrays.asList(b_c1, 
b_c2, b_c3, b_c4, a));
+               check("A(),B(),B(int),B(String),B(String,String)", s);
+
+       }
+}
\ No newline at end of file
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
index b2f4817..0284bdb 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
@@ -14,6 +14,8 @@ package org.apache.juneau.reflection;
 
 import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
+import static org.apache.juneau.reflect.ReflectFlags.*;
+
 import static org.junit.Assert.*;
 
 import java.io.*;
@@ -22,6 +24,7 @@ import java.util.*;
 import java.util.function.*;
 import java.util.stream.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
 import org.junit.*;
@@ -39,26 +42,16 @@ public class ExecutableInfoTest {
                                return null;
                        if (t instanceof List)
                                return 
((List<?>)t).stream().map(this).collect(Collectors.joining(","));
-                       if (t instanceof Iterable)
-                               return 
StreamSupport.stream(((Iterable<?>)t).spliterator(), 
false).map(this).collect(Collectors.joining(","));
                        if (t.getClass().isArray())
                                return 
StreamSupport.stream(ArrayUtils.toList(t, Object.class).spliterator(), 
false).map(this).collect(Collectors.joining(","));
                        if (t instanceof Annotation)
                                return 
t.toString().replaceAll("\\@[^\\$]*\\$(.*)", "@$1");
                        if (t instanceof Class)
                                return ((Class<?>)t).getSimpleName();
-                       if (t instanceof Package)
-                               return ((Package)t).getName();
                        if (t instanceof ClassInfo)
                                return ((ClassInfo)t).getSimpleName();
-                       if (t instanceof MethodInfo)
-                               return 
((MethodInfo)t).getDeclaringClass().getSimpleName() + '.' + 
((MethodInfo)t).getShortName();
                        if (t instanceof ConstructorInfo)
                                return ((ConstructorInfo)t).getShortName();
-                       if (t instanceof FieldInfo)
-                               return 
((FieldInfo)t).getDeclaringClass().getSimpleName() + '.' + 
((FieldInfo)t).getName();
-                       if (t instanceof AnnotationInfo)
-                               return 
apply(((AnnotationInfo<?>)t).getAnnotation());
                        if (t instanceof ParamInfo)
                                return apply(((ParamInfo)t).toString());
                        return t.toString();
@@ -381,71 +374,214 @@ public class ExecutableInfoTest {
        // Characteristics
        
//-----------------------------------------------------------------------------------------------------------------
 
+       static abstract class E {
+               @Deprecated public void deprecated() {}
+               public void notDeprecated() {}
+               public void hasParams(int foo) {}
+               public void hasNoParams() {}
+               public void isPublic() {}
+               protected void isNotPublic() {}
+               public static void isStatic() {}
+               public void isNotStatic() {}
+               public abstract void isAbstract();
+               public void isNotAbstract() {}
+       }
+       static ClassInfo e = ClassInfo.of(E.class);
+       static ExecutableInfo
+               e_deprecated = e.getPublicMethod("deprecated"),
+               e_notDeprecated = e.getPublicMethod("notDeprecated"),
+               e_hasParams = e.getPublicMethod("hasParams", int.class),
+               e_hasNoParams = e.getPublicMethod("hasNoParams"),
+               e_isPublic = e.getPublicMethod("isPublic"),
+               e_isNotPublic = e.getMethod("isNotPublic"),
+               e_isStatic = e.getPublicMethod("isStatic"),
+               e_isNotStatic = e.getPublicMethod("isNotStatic"),
+               e_isAbstract = e.getPublicMethod("isAbstract"),
+               e_isNotAbstract = e.getPublicMethod("isNotAbstract")
+       ;
+
        @Test
        public void isAll() {
+               assertTrue(e_deprecated.isAll(DEPRECATED));
+               assertTrue(e_notDeprecated.isAll(NOT_DEPRECATED));
+               assertTrue(e_hasParams.isAll(HAS_PARAMS));
+               assertTrue(e_hasNoParams.isAll(HAS_NO_PARAMS));
+               assertTrue(e_isPublic.isAll(PUBLIC));
+               assertTrue(e_isNotPublic.isAll(NOT_PUBLIC));
+               assertTrue(e_isStatic.isAll(STATIC));
+               assertTrue(e_isNotStatic.isAll(NOT_STATIC));
+               assertTrue(e_isAbstract.isAll(ABSTRACT));
+               assertTrue(e_isNotAbstract.isAll(NOT_ABSTRACT));
+
+               assertFalse(e_deprecated.isAll(NOT_DEPRECATED));
+               assertFalse(e_notDeprecated.isAll(DEPRECATED));
+               assertFalse(e_hasParams.isAll(HAS_NO_PARAMS));
+               assertFalse(e_hasNoParams.isAll(HAS_PARAMS));
+               assertFalse(e_isPublic.isAll(NOT_PUBLIC));
+               assertFalse(e_isNotPublic.isAll(PUBLIC));
+               assertFalse(e_isStatic.isAll(NOT_STATIC));
+               assertFalse(e_isNotStatic.isAll(STATIC));
+               assertFalse(e_isAbstract.isAll(NOT_ABSTRACT));
+               assertFalse(e_isNotAbstract.isAll(ABSTRACT));
+       }
+
+       @Test
+       public void isAll_invalidFlag() {
+               try {
+                       e_deprecated.isAll(TRANSIENT);
+               } catch (RuntimeException e) {
+                       assertEquals("Invalid flag for executable: TRANSIENT", 
e.getLocalizedMessage());
+               }
        }
 
        @Test
        public void isAny() {
+               assertTrue(e_deprecated.isAny(DEPRECATED));
+               assertTrue(e_notDeprecated.isAny(NOT_DEPRECATED));
+               assertTrue(e_hasParams.isAny(HAS_PARAMS));
+               assertTrue(e_hasNoParams.isAny(HAS_NO_PARAMS));
+               assertTrue(e_isPublic.isAny(PUBLIC));
+               assertTrue(e_isNotPublic.isAny(NOT_PUBLIC));
+               assertTrue(e_isStatic.isAny(STATIC));
+               assertTrue(e_isNotStatic.isAny(NOT_STATIC));
+               assertTrue(e_isAbstract.isAny(ABSTRACT));
+               assertTrue(e_isNotAbstract.isAny(NOT_ABSTRACT));
+
+               assertFalse(e_deprecated.isAny(NOT_DEPRECATED));
+               assertFalse(e_notDeprecated.isAny(DEPRECATED));
+               assertFalse(e_hasParams.isAny(HAS_NO_PARAMS));
+               assertFalse(e_hasNoParams.isAny(HAS_PARAMS));
+               assertFalse(e_isPublic.isAny(NOT_PUBLIC));
+               assertFalse(e_isNotPublic.isAny(PUBLIC));
+               assertFalse(e_isStatic.isAny(NOT_STATIC));
+               assertFalse(e_isNotStatic.isAny(STATIC));
+               assertFalse(e_isAbstract.isAny(NOT_ABSTRACT));
+               assertFalse(e_isNotAbstract.isAny(ABSTRACT));
+       }
+
+       @Test
+       public void isAny_invalidFlag() {
+               try {
+                       e_deprecated.isAny(TRANSIENT);
+               } catch (RuntimeException e) {
+                       assertEquals("Invalid flag for executable: TRANSIENT", 
e.getLocalizedMessage());
+               }
        }
 
        @Test
        public void hasArgs() {
+               assertTrue(e_hasParams.hasArgs(int.class));
+               assertFalse(e_hasParams.hasArgs());
+               assertFalse(e_hasParams.hasArgs(long.class));
+               assertTrue(e_hasNoParams.hasArgs());
+               assertFalse(e_hasNoParams.hasArgs(long.class));
        }
 
        @Test
        public void hasFuzzyArgs() {
+               assertTrue(e_hasParams.hasFuzzyArgs(int.class));
+               assertTrue(e_hasParams.hasFuzzyArgs(int.class, long.class));
+               assertFalse(e_hasParams.hasFuzzyArgs(long.class));
+               assertTrue(e_hasNoParams.hasFuzzyArgs());
+               assertTrue(e_hasNoParams.hasFuzzyArgs(long.class));
        }
 
        @Test
        public void isDeprecated() {
+               assertTrue(e_deprecated.isDeprecated());
+               assertFalse(e_notDeprecated.isDeprecated());
        }
 
        @Test
        public void isNotDeprecated() {
+               assertFalse(e_deprecated.isNotDeprecated());
+               assertTrue(e_notDeprecated.isNotDeprecated());
        }
 
        @Test
        public void isAbstract() {
+               assertTrue(e_isAbstract.isAbstract());
+               assertFalse(e_isNotAbstract.isAbstract());
        }
 
        @Test
        public void isNotAbstract() {
+               assertFalse(e_isAbstract.isNotAbstract());
+               assertTrue(e_isNotAbstract.isNotAbstract());
        }
 
        @Test
        public void isPublic() {
+               assertTrue(e_isPublic.isPublic());
+               assertFalse(e_isNotPublic.isPublic());
        }
 
        @Test
        public void isNotPublic() {
+               assertFalse(e_isPublic.isNotPublic());
+               assertTrue(e_isNotPublic.isNotPublic());
        }
 
        @Test
        public void isStatic() {
+               assertTrue(e_isStatic.isStatic());
+               assertFalse(e_isNotStatic.isStatic());
        }
 
        @Test
        public void isNotStatic() {
+               assertFalse(e_isStatic.isNotStatic());
+               assertTrue(e_isNotStatic.isNotStatic());
        }
 
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Visibility
+       
//-----------------------------------------------------------------------------------------------------------------
 
+       static abstract class F {
+               public void isPublic() {}
+               protected void isProtected() {}
+               @SuppressWarnings("unused")
+               private void isPrivate() {}
+               void isDefault() {}
+       }
+       static ClassInfo f = ClassInfo.of(F.class);
+       static ExecutableInfo
+               f_isPublic = f.getPublicMethod("isPublic"),
+               f_isProtected = f.getMethod("isProtected"),
+               f_isPrivate = f.getMethod("isPrivate"),
+               f_isDefault = f.getMethod("isDefault");
 
+       @Test
+       public void setAccessible() {
+               f_isPublic.setAccessible();
+               f_isProtected.setAccessible();
+               f_isPrivate.setAccessible();
+               f_isDefault.setAccessible();
+       }
 
+       @Test
+       public void isVisible() {
+               assertTrue(f_isPublic.isVisible(Visibility.PUBLIC));
+               assertTrue(f_isPublic.isVisible(Visibility.PROTECTED));
+               assertTrue(f_isPublic.isVisible(Visibility.PRIVATE));
+               assertTrue(f_isPublic.isVisible(Visibility.DEFAULT));
 
+               assertFalse(f_isProtected.isVisible(Visibility.PUBLIC));
+               assertTrue(f_isProtected.isVisible(Visibility.PROTECTED));
+               assertTrue(f_isProtected.isVisible(Visibility.PRIVATE));
+               assertTrue(f_isProtected.isVisible(Visibility.DEFAULT));
 
+               assertFalse(f_isPrivate.isVisible(Visibility.PUBLIC));
+               assertFalse(f_isPrivate.isVisible(Visibility.PROTECTED));
+               assertTrue(f_isPrivate.isVisible(Visibility.PRIVATE));
+               assertFalse(f_isPrivate.isVisible(Visibility.DEFAULT));
 
-
-
-
-
-
-
-
-
-
-
-
+               assertFalse(f_isDefault.isVisible(Visibility.PUBLIC));
+               assertFalse(f_isDefault.isVisible(Visibility.PROTECTED));
+               assertTrue(f_isDefault.isVisible(Visibility.PRIVATE));
+               assertTrue(f_isDefault.isVisible(Visibility.DEFAULT));
+       }
 
        
//-----------------------------------------------------------------------------------------------------------------
        // Labels
@@ -459,7 +595,7 @@ public class ExecutableInfoTest {
                public void foo(String foo){}
                public void foo(Map<String,Object> foo){}
        }
-       ClassInfo x = ClassInfo.of(X.class);
+       static ClassInfo x = ClassInfo.of(X.class);
 
        @Test
        public void getFullName_method() {
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/FieldInfoTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/FieldInfoTest.java
index 8967082..509386e 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/FieldInfoTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/FieldInfoTest.java
@@ -12,6 +12,359 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.reflection;
 
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+import static org.apache.juneau.reflect.ReflectFlags.*;
+import static org.junit.Assert.*;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.function.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.reflect.*;
+import org.junit.*;
+
 public class FieldInfoTest {
 
+       @Documented
+       @Target(FIELD)
+       @Retention(RUNTIME)
+       @Inherited
+       public static @interface A {
+               String value();
+       }
+
+       @Documented
+       @Target(FIELD)
+       @Retention(RUNTIME)
+       @Inherited
+       public static @interface AX {
+               String value();
+       }
+
+       private static void check(String expected, Object o) {
+               assertEquals(expected, TO_STRING.apply(o));
+       }
+
+       private static final Function<Object,String> TO_STRING = new 
Function<Object,String>() {
+               @Override
+               public String apply(Object t) {
+                       if (t == null)
+                               return null;
+                       if (t instanceof A)
+                               return "@A(" + ((A)t).value() + ")";
+                       if (t instanceof ClassInfo)
+                               return ((ClassInfo)t).getSimpleName();
+                       if (t instanceof FieldInfo)
+                               return ((FieldInfo)t).getName();
+                       if (t instanceof Field)
+                               return ((Field)t).getName();
+                       return t.toString();
+               }
+       };
+
+       private static FieldInfo off(Class<?> c, String name) {
+               try {
+                       return FieldInfo.of(c.getDeclaredField(name));
+               } catch (SecurityException | NoSuchFieldException e) {
+                       fail(e.getLocalizedMessage());
+               }
+               return null;
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Instantiation.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       static class A1 {
+               public int f1;
+       }
+       FieldInfo a1_f1 = off(A1.class, "f1");
+
+       @Test
+       public void of_withClass() {
+               check("f1", FieldInfo.of(ClassInfo.of(A1.class), 
a1_f1.inner()));
+       }
+
+       @Test
+       public void of_withoutClass() {
+               check("f1", FieldInfo.of(a1_f1.inner()));
+       }
+
+       @Test
+       public void of_null() {
+               check(null, FieldInfo.of(null));
+               check(null, FieldInfo.of(null, null));
+       }
+
+       @Test
+       public void getDeclaringClass() {
+               check("A1", a1_f1.getDeclaringClass());
+               check("A1", a1_f1.getDeclaringClass());
+       }
+
+       @Test
+       public void inner() {
+               check("f1", a1_f1.inner());
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Annotations
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       public static class B {
+               @A("a1") public int a1;
+               public int a2;
+       }
+
+       FieldInfo
+               b_a1 = off(B.class, "a1"),
+               b_a2 = off(B.class, "a2");
+
+       @Test
+       public void getAnnotation() {
+               check("@A(a1)", b_a1.getAnnotation(A.class));
+               check(null, b_a2.getAnnotation(A.class));
+       }
+
+       @Test
+       public void getAnnotation_null() {
+               check(null, b_a1.getAnnotation(null));
+       }
+
+       @Test
+       public void hasAnnotation_true() {
+               assertTrue(b_a1.hasAnnotation(A.class));
+       }
+
+       @Test
+       public void hasAnnotation_false() {
+               assertFalse(b_a2.hasAnnotation(A.class));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Characteristics
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       static abstract class C {
+               @Deprecated public int deprecated;
+               public int notDeprecated;
+               public int isPublic;
+               protected int isNotPublic;
+               public static int isStatic;
+               public int isNotStatic;
+               public transient int isTransient;
+               public int isNotTransient;
+       }
+       static ClassInfo c = ClassInfo.of(C.class);
+       static FieldInfo
+               c_deprecated = c.getPublicField("deprecated"),
+               c_notDeprecated = c.getPublicField("notDeprecated"),
+               c_isPublic = c.getPublicField("isPublic"),
+               c_isNotPublic = c.getDeclaredField("isNotPublic"),
+               c_isStatic = c.getPublicField("isStatic"),
+               c_isNotStatic = c.getPublicField("isNotStatic"),
+               c_isTransient = c.getPublicField("isTransient"),
+               c_isNotTransient = c.getPublicField("isNotTransient")
+       ;
+
+       @Test
+       public void isAll() {
+               assertTrue(c_deprecated.isAll(DEPRECATED));
+               assertTrue(c_notDeprecated.isAll(NOT_DEPRECATED));
+               assertTrue(c_isPublic.isAll(PUBLIC));
+               assertTrue(c_isNotPublic.isAll(NOT_PUBLIC));
+               assertTrue(c_isStatic.isAll(STATIC));
+               assertTrue(c_isNotStatic.isAll(NOT_STATIC));
+               assertTrue(c_isTransient.isAll(TRANSIENT));
+               assertTrue(c_isNotTransient.isAll(NOT_TRANSIENT));
+
+               assertFalse(c_deprecated.isAll(NOT_DEPRECATED));
+               assertFalse(c_notDeprecated.isAll(DEPRECATED));
+               assertFalse(c_isPublic.isAll(NOT_PUBLIC));
+               assertFalse(c_isNotPublic.isAll(PUBLIC));
+               assertFalse(c_isStatic.isAll(NOT_STATIC));
+               assertFalse(c_isNotStatic.isAll(STATIC));
+               assertFalse(c_isTransient.isAll(NOT_TRANSIENT));
+               assertFalse(c_isNotTransient.isAll(TRANSIENT));
+       }
+
+       @Test
+       public void isAll_invalidFlag() {
+               try {
+                       c_deprecated.isAll(HAS_PARAMS);
+               } catch (RuntimeException e) {
+                       assertEquals("Invalid flag for field: HAS_PARAMS", 
e.getLocalizedMessage());
+               }
+       }
+
+       @Test
+       public void isAny() {
+               assertTrue(c_deprecated.isAny(DEPRECATED));
+               assertTrue(c_notDeprecated.isAny(NOT_DEPRECATED));
+               assertTrue(c_isPublic.isAny(PUBLIC));
+               assertTrue(c_isNotPublic.isAny(NOT_PUBLIC));
+               assertTrue(c_isStatic.isAny(STATIC));
+               assertTrue(c_isNotStatic.isAny(NOT_STATIC));
+               assertTrue(c_isTransient.isAny(TRANSIENT));
+               assertTrue(c_isNotTransient.isAny(NOT_TRANSIENT));
+
+               assertFalse(c_deprecated.isAny(NOT_DEPRECATED));
+               assertFalse(c_notDeprecated.isAny(DEPRECATED));
+               assertFalse(c_isPublic.isAny(NOT_PUBLIC));
+               assertFalse(c_isNotPublic.isAny(PUBLIC));
+               assertFalse(c_isStatic.isAny(NOT_STATIC));
+               assertFalse(c_isNotStatic.isAny(STATIC));
+               assertFalse(c_isTransient.isAny(NOT_TRANSIENT));
+               assertFalse(c_isNotTransient.isAny(TRANSIENT));
+       }
+
+       @Test
+       public void isAny_invalidFlag() {
+               try {
+                       c_deprecated.isAny(HAS_PARAMS);
+               } catch (RuntimeException e) {
+                       assertEquals("Invalid flag for field: HAS_PARAMS", 
e.getLocalizedMessage());
+               }
+       }
+
+       @Test
+       public void isDeprecated() {
+               assertTrue(c_deprecated.isDeprecated());
+               assertFalse(c_notDeprecated.isDeprecated());
+       }
+
+       @Test
+       public void isNotDeprecated() {
+               assertFalse(c_deprecated.isNotDeprecated());
+               assertTrue(c_notDeprecated.isNotDeprecated());
+       }
+
+       @Test
+       public void isTransient() {
+               assertTrue(c_isTransient.isTransient());
+               assertFalse(c_isNotTransient.isTransient());
+       }
+
+       @Test
+       public void isNotTransient() {
+               assertFalse(c_isTransient.isNotTransient());
+               assertTrue(c_isNotTransient.isNotTransient());
+       }
+
+       @Test
+       public void isPublic() {
+               assertTrue(c_isPublic.isPublic());
+               assertFalse(c_isNotPublic.isPublic());
+       }
+
+       @Test
+       public void isNotPublic() {
+               assertFalse(c_isPublic.isNotPublic());
+               assertTrue(c_isNotPublic.isNotPublic());
+       }
+
+       @Test
+       public void isStatic() {
+               assertTrue(c_isStatic.isStatic());
+               assertFalse(c_isNotStatic.isStatic());
+       }
+
+       @Test
+       public void isNotStatic() {
+               assertFalse(c_isStatic.isNotStatic());
+               assertTrue(c_isNotStatic.isNotStatic());
+       }
+
+       @Test
+       public void hasName() {
+               assertTrue(b_a1.hasName("a1"));
+               assertFalse(b_a1.hasName("a2"));
+       }
+
+       @Test
+       public void hasName_null() {
+               assertFalse(b_a1.hasName(null));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Visibility
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       static abstract class D {
+               public int isPublic;
+               protected int isProtected;
+               @SuppressWarnings("unused")
+               private int isPrivate;
+               int isDefault;
+       }
+       static ClassInfo d = ClassInfo.of(D.class);
+       static FieldInfo
+               d_isPublic = d.getPublicField("isPublic"),
+               d_isProtected = d.getDeclaredField("isProtected"),
+               d_isPrivate = d.getDeclaredField("isPrivate"),
+               d_isDefault = d.getDeclaredField("isDefault");
+
+       @Test
+       public void setAccessible() {
+               d_isPublic.setAccessible();
+               d_isProtected.setAccessible();
+               d_isPrivate.setAccessible();
+               d_isDefault.setAccessible();
+       }
+
+       @Test
+       public void isVisible() {
+               assertTrue(d_isPublic.isVisible(Visibility.PUBLIC));
+               assertTrue(d_isPublic.isVisible(Visibility.PROTECTED));
+               assertTrue(d_isPublic.isVisible(Visibility.PRIVATE));
+               assertTrue(d_isPublic.isVisible(Visibility.DEFAULT));
+
+               assertFalse(d_isProtected.isVisible(Visibility.PUBLIC));
+               assertTrue(d_isProtected.isVisible(Visibility.PROTECTED));
+               assertTrue(d_isProtected.isVisible(Visibility.PRIVATE));
+               assertTrue(d_isProtected.isVisible(Visibility.DEFAULT));
+
+               assertFalse(d_isPrivate.isVisible(Visibility.PUBLIC));
+               assertFalse(d_isPrivate.isVisible(Visibility.PROTECTED));
+               assertTrue(d_isPrivate.isVisible(Visibility.PRIVATE));
+               assertFalse(d_isPrivate.isVisible(Visibility.DEFAULT));
+
+               assertFalse(d_isDefault.isVisible(Visibility.PUBLIC));
+               assertFalse(d_isDefault.isVisible(Visibility.PROTECTED));
+               assertTrue(d_isDefault.isVisible(Visibility.PRIVATE));
+               assertTrue(d_isDefault.isVisible(Visibility.DEFAULT));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Other methods.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       static class E {
+               public int a1;
+               int a2;
+       }
+
+       static ClassInfo e = ClassInfo.of(E.class);
+       static FieldInfo
+               e_a1 = e.getPublicField("a1"),
+               e_a2 = e.getDeclaredField("a2");
+
+       @Test
+       public void getType() {
+               check("int", e_a1.getType());
+               check("int", e_a2.getType());
+       }
+
+       @Test
+       public void getType_twice() {
+               check("int", e_a1.getType());
+               check("int", e_a1.getType());
+       }
+
+       @Test
+       public void toString2() {
+               assertEquals("org.apache.juneau.reflection.FieldInfoTest$E.a1", 
e_a1.toString());
+       }
 }
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/MethodInfoTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/MethodInfoTest.java
index 1f11fba..88ebecf 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/MethodInfoTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/MethodInfoTest.java
@@ -14,136 +14,110 @@ package org.apache.juneau.reflection;
 
 import static java.lang.annotation.ElementType.*;
 import static java.lang.annotation.RetentionPolicy.*;
-import static org.apache.juneau.testutils.TestUtils.*;
 import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
 
 import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
 
-import org.apache.juneau.*;
 import org.apache.juneau.reflect.*;
 import org.junit.*;
 
 public class MethodInfoTest {
 
-       
//====================================================================================================
-       // getMethodAnnotation
-       
//====================================================================================================
-       @Test
-       public void getMethodAnnotations() throws Exception {
-               assertEquals("a1", 
MethodInfo.of(CI3.class.getMethod("a1")).getAnnotation(TestAnnotation.class).value());
-               assertEquals("a2b", 
MethodInfo.of(CI3.class.getMethod("a2")).getAnnotation(TestAnnotation.class).value());
-               assertEquals("a3", MethodInfo.of(CI3.class.getMethod("a3", 
CharSequence.class)).getAnnotation(TestAnnotation.class).value());
-               assertEquals("a4", 
MethodInfo.of(CI3.class.getMethod("a4")).getAnnotation(TestAnnotation.class).value());
-       }
-
-       public static interface CI1 {
-               @TestAnnotation("a1")
-               void a1();
-               @TestAnnotation("a2a")
-               void a2();
-               @TestAnnotation("a3")
-               void a3(CharSequence foo);
-
-               void a4();
-       }
-
-       public static class CI2 implements CI1 {
-               @Override
-               public void a1() {}
-               @Override
-               @TestAnnotation("a2b")
-               public void a2() {}
-               @Override
-               public void a3(CharSequence s) {}
-               @Override
-               public void a4() {}
-       }
-
-       public static class CI3 extends CI2 {
-               @Override
-               public void a1() {}
-               @Override public void a2() {}
-               @Override
-               @TestAnnotation("a4")
-               public void a4() {}
-       }
-
+       @Documented
        @Target(METHOD)
        @Retention(RUNTIME)
-       public @interface TestAnnotation {
-               String value() default "";
+       @Inherited
+       public static @interface A {
+               String value();
        }
 
-       
//====================================================================================================
-       // getAnnotations()
-       
//====================================================================================================
-
-       @Target({PARAMETER,TYPE})
+       @Documented
+       @Target(METHOD)
        @Retention(RUNTIME)
-       public static @interface HI1 {
-               public String value();
+       @Inherited
+       public static @interface AX {
+               String value();
        }
 
-       public static interface HA {
-               public void doX(@HI1("0") HA01 x);
+       private static void check(String expected, Object o) {
+               assertEquals(expected, TO_STRING.apply(o));
        }
 
-       @HI1("1") public static class HA01 extends HA02 {}
-       @HI1("2") public static class HA02 implements HA03, HA04 {}
-       @HI1("3") public static interface HA03 {}
-       @HI1("4") public static interface HA04 {}
+       private static final Function<Object,String> TO_STRING = new 
Function<Object,String>() {
+               @Override
+               public String apply(Object t) {
+                       if (t == null)
+                               return null;
+                       if (t instanceof MethodInfo)
+                               return 
((MethodInfo)t).getDeclaringClass().getSimpleName() + '.' + 
((MethodInfo)t).getShortName();
+                       if (t instanceof Method)
+                               return 
((Method)t).getDeclaringClass().getSimpleName() + '.' + 
MethodInfo.of((Method)t).getShortName();
+                       if (t instanceof List)
+                               return 
((List<?>)t).stream().map(this).collect(Collectors.joining(","));
+                       if (t instanceof A)
+                               return "@A(" + ((A)t).value() + ")";
+                       if (t instanceof ClassInfo)
+                               return ((ClassInfo)t).getSimpleName();
+                       return t.toString();
+               }
+       };
 
-       @Test
-       public void getAnnotationsOnParameter() throws Exception {
-               ObjectList l = new ObjectList();
-               ParamInfo mpi = MethodInfo.of(HA.class.getMethod("doX", 
HA01.class)).getParam(0);
-               for (HI1 ia : mpi.getAnnotations(HI1.class)) {
-                       l.add(ia.value());
+       private static MethodInfo ofm(Class<?> c, String name, Class<?>...pt) {
+               try {
+                       return MethodInfo.of(c.getDeclaredMethod(name, pt));
+               } catch (NoSuchMethodException | SecurityException e) {
+                       fail(e.getLocalizedMessage());
                }
-               assertEquals("['0','1','2','3','4']", l.toString());
+               return null;
        }
 
-       @Target({PARAMETER,TYPE})
-       @Retention(RUNTIME)
-       @Inherited
-       public static @interface HI2 {
-               public String value();
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Instantiation.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       public static class A1 {
+               public void m() {}
        }
+       static MethodInfo a_m = ofm(A1.class, "m");
 
-       public static interface HB {
-               public void doX(@HI2("0") HB01 x);
+       @Test
+       public void of_withDeclaringClass() {
+               check("A1.m()", a_m);
+               check("A1.m()", MethodInfo.of(ClassInfo.of(A1.class), 
a_m.inner()));
        }
 
-       @HI2("1") public static class HB01 extends HB02 {}
-       @HI2("2") public static class HB02 implements HB03, HB04 {}
-       @HI2("3") public static interface HB03 {}
-       @HI2("4") public static interface HB04 {}
+       @Test
+       public void of_withoutDeclaringClass() {
+               MethodInfo mi = MethodInfo.of(a_m.inner());
+               check("A1.m()", mi);
+       }
 
        @Test
-       public void getAnnotationsOnParameterInherited() throws Exception {
-               ObjectList l = new ObjectList();
-               ParamInfo mpi = MethodInfo.of(HB.class.getMethod("doX", 
HB01.class)).getParam(0);
-               for (HI2 ib : mpi.getAnnotations(HI2.class)) {
-                       l.add(ib.value());
-               }
-               assertEquals("['0','1','2','3','4']", l.toString());
+       public void of_null() {
+               check(null, MethodInfo.of(null));
+               check(null, MethodInfo.of(null, null));
        }
 
-       
//====================================================================================================
-       // findMatchingMethods()
-       
//====================================================================================================
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Matching methods.
+       
//-----------------------------------------------------------------------------------------------------------------
 
-       public static interface I1 {
+       public static interface B1 {
                public int foo(int x);
                public int foo(String x);
                public int foo();
        }
-       public static class I2 {
+       public static class B2 {
                public int foo(int x) { return 0; }
                public int foo(String x) {return 0;}
                public int foo() {return 0;}
        }
-       public static class I3 extends I2 implements I1 {
+       public static class B3 extends B2 implements B1 {
                @Override
                public int foo(int x) {return 0;}
                @Override
@@ -154,7 +128,253 @@ public class MethodInfoTest {
 
        @Test
        public void findMatchingMethods() throws Exception {
-               MethodInfo mi = MethodInfo.of(I3.class.getMethod("foo", 
int.class));
-               assertObjectEquals("['public int 
org.apache.juneau.reflection.MethodInfoTest$I3.foo(int)','public int 
org.apache.juneau.reflection.MethodInfoTest$I2.foo(int)','public abstract int 
org.apache.juneau.reflection.MethodInfoTest$I1.foo(int)']", mi.getMatching());
+               MethodInfo mi = MethodInfo.of(B3.class.getMethod("foo", 
int.class));
+               check("B3.foo(int),B2.foo(int),B1.foo(int)", mi.getMatching());
+       }
+
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Annotations
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       public static interface C1 {
+               @A("a1") void a1();
+               @A("a2a") void a2();
+               @A("a3") void a3(CharSequence foo);
+               void a4();
+               void a5();
+       }
+
+       public static class C2 implements C1 {
+               @Override public void a1() {}
+               @Override @A("a2b") public void a2() {}
+               @Override public void a3(CharSequence s) {}
+               @Override public void a4() {}
+               @Override public void a5() {}
+       }
+
+       public static class C3 extends C2 {
+               @Override public void a1() {}
+               @Override public void a2() {}
+               @Override public void a3(CharSequence foo) {}
+               @Override @A("a4") public void a4() {}
+               @Override public void a5() {}
+       }
+
+       static MethodInfo
+               c_a1 = ofm(C3.class, "a1"),
+               c_a2 = ofm(C3.class, "a2"),
+               c_a3 = ofm(C3.class, "a3", CharSequence.class),
+               c_a4 = ofm(C3.class, "a4"),
+               c_a5 = ofm(C3.class, "a5");
+
+       @Test
+       public void getAnnotations() {
+               check("@A(a1)", c_a1.getAnnotations(A.class));
+               check("@A(a2b),@A(a2a)", c_a2.getAnnotations(A.class));
+               check("@A(a3)", c_a3.getAnnotations(A.class));
+               check("@A(a4)", c_a4.getAnnotations(A.class));
+               check("", c_a5.getAnnotations(A.class));
+       }
+
+       @Test
+       public void getAnnotations_notExistent() {
+               check("", c_a1.getAnnotations(AX.class));
+               check("", c_a2.getAnnotations(AX.class));
+               check("", c_a3.getAnnotations(AX.class));
+               check("", c_a4.getAnnotations(AX.class));
+               check("", c_a5.getAnnotations(AX.class));
+       }
+
+       @Test
+       public void getAnnotationsParentFirst() {
+               check("@A(a1)", c_a1.getAnnotationsParentFirst(A.class));
+               check("@A(a2a),@A(a2b)", 
c_a2.getAnnotationsParentFirst(A.class));
+               check("@A(a3)", c_a3.getAnnotationsParentFirst(A.class));
+               check("@A(a4)", c_a4.getAnnotationsParentFirst(A.class));
+               check("", c_a5.getAnnotationsParentFirst(A.class));
+       }
+
+       @Test
+       public void appendAnnotations() {
+               check("@A(a1)", c_a1.appendAnnotations(new ArrayList<>(), 
A.class));
+               check("@A(a2b),@A(a2a)", c_a2.appendAnnotations(new 
ArrayList<>(), A.class));
+               check("@A(a3)", c_a3.appendAnnotations(new ArrayList<>(), 
A.class));
+               check("@A(a4)", c_a4.appendAnnotations(new ArrayList<>(), 
A.class));
+               check("", c_a5.appendAnnotations(new ArrayList<>(), A.class));
+       }
+
+       @Test
+       public void appendAnnotationsParentFirst() {
+               check("@A(a1)", c_a1.appendAnnotationsParentFirst(new 
ArrayList<>(), A.class));
+               check("@A(a2a),@A(a2b)", c_a2.appendAnnotationsParentFirst(new 
ArrayList<>(), A.class));
+               check("@A(a3)", c_a3.appendAnnotationsParentFirst(new 
ArrayList<>(), A.class));
+               check("@A(a4)", c_a4.appendAnnotationsParentFirst(new 
ArrayList<>(), A.class));
+               check("", c_a5.appendAnnotationsParentFirst(new ArrayList<>(), 
A.class));
+       }
+
+       @Test
+       public void getAnnotation() {
+               check("@A(a1)", c_a1.getAnnotation(A.class));
+               check("@A(a2b)", c_a2.getAnnotation(A.class));
+               check("@A(a3)", c_a3.getAnnotation(A.class));
+               check("@A(a4)", c_a4.getAnnotation(A.class));
+               check(null, c_a5.getAnnotation(A.class));
+       }
+
+       @Test
+       public void getAnnotationAny() {
+               check("@A(a1)", c_a1.getAnnotation(AX.class, A.class));
+               check("@A(a2b)", c_a2.getAnnotation(AX.class, A.class));
+               check("@A(a3)", c_a3.getAnnotation(AX.class, A.class));
+               check("@A(a4)", c_a4.getAnnotation(AX.class, A.class));
+               check(null, c_a5.getAnnotation(AX.class, A.class));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Return type.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       public static class D {
+               public void a1() {}
+               public Integer a2() {return null;}
+       }
+       static MethodInfo
+               d_a1 = ofm(D.class, "a1"),
+               d_a2 = ofm(D.class, "a2");
+
+       @Test
+       public void getReturnType() {
+               check("void", d_a1.getReturnType());
+               check("Integer", d_a2.getReturnType());
+       }
+
+       @Test
+       public void hasReturnType() {
+               assertTrue(d_a1.hasReturnType(void.class));
+               assertFalse(d_a1.hasReturnType(Integer.class));
+               assertTrue(d_a2.hasReturnType(Integer.class));
+               assertFalse(d_a2.hasReturnType(Number.class));
+       }
+
+       @Test
+       public void hasReturnTypeParent() {
+               assertTrue(d_a1.hasReturnTypeParent(void.class));
+               assertFalse(d_a1.hasReturnTypeParent(Integer.class));
+               assertTrue(d_a2.hasReturnTypeParent(Integer.class));
+               assertTrue(d_a2.hasReturnTypeParent(Number.class));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Other methods
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       public static class E {
+               private String f;
+               public void a1(CharSequence foo) {
+                       f = foo == null ? null : foo.toString();
+               }
+               public void a2(int f1, int f2) {}
+               public void a3() {}
+       }
+       static MethodInfo
+               e_a1 = ofm(E.class, "a1", CharSequence.class),
+               e_a2 = ofm(E.class, "a2", int.class, int.class),
+               e_a3 = ofm(E.class, "a3");
+
+       @Test
+       public void invoke() {
+               try {
+                       E e = new E();
+                       e_a1.invoke(e, "foo");
+                       assertEquals("foo", e.f);
+                       e_a1.invoke(e, (CharSequence)null);
+                       assertNull(e.f);
+               } catch (Exception e) {
+                       fail(e.getLocalizedMessage());
+               }
+       }
+
+       @Test
+       public void invokeFuzzy() {
+               try {
+                       E e = new E();
+                       e_a1.invokeFuzzy(e, "foo", 123);
+                       assertEquals("foo", e.f);
+                       e_a1.invokeFuzzy(e, 123, "bar");
+                       assertEquals("bar", e.f);
+               } catch (Exception e) {
+                       fail(e.getLocalizedMessage());
+               }
+       }
+
+       @Test
+       public void getSignature() {
+               assertEquals("a1(java.lang.CharSequence)", e_a1.getSignature());
+               assertEquals("a2(int,int)", e_a2.getSignature());
+               assertEquals("a3", e_a3.getSignature());
+       }
+
+       @Test
+       public void argsOnlyOfType() {
+               assertTrue(e_a1.argsOnlyOfType(CharSequence.class));
+               assertTrue(e_a1.argsOnlyOfType(CharSequence.class, Map.class));
+               assertFalse(e_a1.argsOnlyOfType());
+       }
+
+       public static class F {
+               public void isA() {}
+               public void is() {}
+               public void getA() {}
+               public void get() {}
+               public void setA() {}
+               public void set() {}
+               public void foo() {}
+       }
+       static MethodInfo
+               f_isA = ofm(F.class, "isA"),
+               f_is = ofm(F.class, "is"),
+               f_getA = ofm(F.class, "getA"),
+               f_get = ofm(F.class, "get"),
+               f_setA = ofm(F.class, "setA"),
+               f_set = ofm(F.class, "set"),
+               f_foo = ofm(F.class, "foo");
+
+       @Test
+       public void getPropertyName() {
+               assertEquals("a", f_isA.getPropertyName());
+               assertEquals("is", f_is.getPropertyName());
+               assertEquals("a", f_getA.getPropertyName());
+               assertEquals("get", f_get.getPropertyName());
+               assertEquals("a", f_setA.getPropertyName());
+               assertEquals("set", f_set.getPropertyName());
+               assertEquals("foo", f_foo.getPropertyName());
+       }
+
+       @Test
+       public void isBridge() {
+               assertFalse(f_foo.isBridge());
+       }
+
+       public static class G {
+               public void a1() {}
+               public void a1(int a1) {}
+               public void a1(int a1, int a2) {}
+               public void a1(String a1) {}
+               public void a2() {}
+               public void a3() {}
+       }
+       static MethodInfo
+               g_a1a = ofm(G.class, "a1"),
+               g_a1b = ofm(G.class, "a1", int.class),
+               g_a1c = ofm(G.class, "a1", int.class, int.class),
+               g_a1d = ofm(G.class, "a1", String.class),
+               g_a2 = ofm(G.class, "a2"),
+               g_a3 = ofm(G.class, "a3");
+
+       @Test
+       public void compareTo() {
+               Set<MethodInfo> s = new TreeSet<>(Arrays.asList(g_a1a, g_a1b, 
g_a1c, g_a1d, g_a2, g_a3));
+               check("[a1(), a1(int), a1(String), a1(int,int), a2(), a3()]", 
s);
        }
 }
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ParamInfoTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ParamInfoTest.java
new file mode 100644
index 0000000..8a531f4
--- /dev/null
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/reflection/ParamInfoTest.java
@@ -0,0 +1,409 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you 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.apache.juneau.reflection;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+import static org.junit.Assert.*;
+
+import java.lang.annotation.*;
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.reflect.*;
+import org.junit.*;
+
+/**
+ * ParamInfo tests.
+ */
+public class ParamInfoTest {
+
+       @Documented
+       @Target(METHOD)
+       @Retention(RUNTIME)
+       @Inherited
+       public static @interface A {
+               String value();
+       }
+
+       @Documented
+       @Target(METHOD)
+       @Retention(RUNTIME)
+       @Inherited
+       public static @interface AX {
+               String value();
+       }
+
+       private static void check(String expected, Object o) {
+               assertEquals(expected, TO_STRING.apply(o));
+       }
+
+       private static final Function<Object,String> TO_STRING = new 
Function<Object,String>() {
+               @Override
+               public String apply(Object t) {
+                       if (t == null)
+                               return null;
+                       if (t instanceof List)
+                               return 
((List<?>)t).stream().map(this).collect(Collectors.joining(","));
+                       if (t.getClass().isArray())
+                               return 
StreamSupport.stream(ArrayUtils.toList(t, Object.class).spliterator(), 
false).map(this).collect(Collectors.joining(","));
+                       if (t instanceof MethodInfo)
+                               return 
((MethodInfo)t).getDeclaringClass().getSimpleName() + '.' + 
((MethodInfo)t).getShortName();
+                       if (t instanceof CA)
+                               return "@CA(" + ((CA)t).value() + ")";
+                       if (t instanceof DA)
+                               return "@DA(" + ((DA)t).value() + ")";
+                       if (t instanceof ClassInfo)
+                               return ((ClassInfo)t).getSimpleName();
+                       return t.toString();
+               }
+       };
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Instantiation.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       static class B {
+               public B(int a, String b) {}
+               public void a1(int a, String b) {}
+               void a2(int a, String b) {}
+       }
+
+       static ClassInfo b = ClassInfo.of(B.class);
+       static ParamInfo
+               b_b_a = b.getPublicConstructor(int.class, 
String.class).getParam(0),
+               b_b_b = b.getPublicConstructor(int.class, 
String.class).getParam(1),
+               b_a1_a = b.getMethod("a1", int.class, String.class).getParam(0),
+               b_a1_b = b.getMethod("a1", int.class, String.class).getParam(1),
+               b_a2_a = b.getMethod("a2", int.class, String.class).getParam(0),
+               b_a2_b = b.getMethod("a2", int.class, String.class).getParam(1);
+
+
+       @Test
+       public void getIndex() {
+               assertEquals(0, b_b_a.getIndex());
+               assertEquals(1, b_b_b.getIndex());
+               assertEquals(0, b_a1_a.getIndex());
+               assertEquals(1, b_a1_b.getIndex());
+               assertEquals(0, b_a2_a.getIndex());
+               assertEquals(1, b_a2_b.getIndex());
+       }
+
+       @Test
+       public void getMethod() {
+               check("B.a1(int,String)", b_a1_a.getMethod());
+               check("B.a1(int,String)", b_a1_b.getMethod());
+               check("B.a2(int,String)", b_a2_a.getMethod());
+               check("B.a2(int,String)", b_a2_b.getMethod());
+       }
+
+       @Test
+       public void getMethod_onConstrutor() {
+               check(null, b_b_a.getMethod());
+               check(null, b_b_b.getMethod());
+       }
+
+       @Test
+       public void getConstructor() {
+               check("B(int,String)", b_b_a.getConstructor());
+               check("B(int,String)", b_b_b.getConstructor());
+       }
+
+       @Test
+       public void getConstructor_onMethod() {
+               check(null, b_a1_a.getConstructor());
+               check(null, b_a1_b.getConstructor());
+               check(null, b_a2_a.getConstructor());
+               check(null, b_a2_b.getConstructor());
+       }
+
+       @Test
+       public void getParameterType() {
+               check("int", b_b_a.getParameterType());
+               check("String", b_b_b.getParameterType());
+               check("int", b_a1_a.getParameterType());
+               check("String", b_a1_b.getParameterType());
+               check("int", b_a2_a.getParameterType());
+               check("String", b_a2_b.getParameterType());
+
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Annotations.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Target({PARAMETER,TYPE})
+       @Retention(RUNTIME)
+       public static @interface CA {
+               public String value();
+       }
+       @CA("1") public static class C1 extends C2 {}
+       @CA("2") public static class C2 implements C3, C4 {}
+       @CA("3") public static interface C3 {}
+       @CA("4") public static interface C4 {}
+
+       public static interface CB {
+               public void a1(@CA("5") C1 x);
+               public void a2(@CA("5") C1 x);
+       }
+       public static class CC implements CB {
+               public CC(@CA("9") C1 x) {}
+               @Override
+               public void a1(C1 x) {}
+               @Override
+               public void a2(@CA("6") C1 x) {}
+       }
+       static ClassInfo
+               cb = ClassInfo.of(CB.class),
+               cc = ClassInfo.of(CC.class);
+       static ParamInfo
+               cc_cc = cc.getPublicConstructor(C1.class).getParam(0),
+               cb_a1 = cb.getMethod("a1", C1.class).getParam(0),
+               cb_a2 = cb.getMethod("a2", C1.class).getParam(0),
+               cc_a1 = cc.getMethod("a1", C1.class).getParam(0),
+               cc_a2 = cc.getMethod("a2", C1.class).getParam(0);
+
+       @Test
+       public void getDeclaredAnnotations() throws Exception {
+               check("@CA(5)", cb_a1.getDeclaredAnnotations());
+               check("@CA(5)", cb_a2.getDeclaredAnnotations());
+               check("", cc_a1.getDeclaredAnnotations());
+               check("@CA(6)", cc_a2.getDeclaredAnnotations());
+       }
+
+       @Test
+       public void getDeclaredAnnotations_constructor() throws Exception {
+               check("@CA(9)", cc_cc.getDeclaredAnnotations());
+       }
+
+       @Test
+       public void getDeclaredAnnotation() throws Exception {
+               check("@CA(5)", cb_a1.getDeclaredAnnotation(CA.class));
+               check("@CA(5)", cb_a2.getDeclaredAnnotation(CA.class));
+               check(null, cc_a1.getDeclaredAnnotation(CA.class));
+               check("@CA(6)", cc_a2.getDeclaredAnnotation(CA.class));
+       }
+
+       @Test
+       public void getDeclaredAnnotation_constructor() throws Exception {
+               check("@CA(9)", cc_cc.getDeclaredAnnotation(CA.class));
+       }
+
+       @Test
+       public void getDeclaredAnnotation_notFound() throws Exception {
+               check(null, cb_a1.getDeclaredAnnotation(DA.class));
+       }
+
+       @Test
+       public void getDeclaredAnnotation_notFound_constructor() throws 
Exception {
+               check(null, cc_cc.getDeclaredAnnotation(DA.class));
+       }
+
+       @Test
+       public void getDeclaredAnnotation_null() throws Exception {
+               check(null, cb_a1.getDeclaredAnnotation(null));
+       }
+
+       @Test
+       public void getDeclaredAnnotation_null_constructor() throws Exception {
+               check(null, cc_cc.getDeclaredAnnotation(null));
+       }
+
+       @Test
+       public void getAnnotations() throws Exception {
+               check("@CA(5),@CA(1),@CA(2),@CA(3),@CA(4)", 
cb_a1.getAnnotations(CA.class));
+               check("@CA(5),@CA(1),@CA(2),@CA(3),@CA(4)", 
cb_a2.getAnnotations(CA.class));
+               check("@CA(5),@CA(1),@CA(2),@CA(3),@CA(4)", 
cc_a1.getAnnotations(CA.class));
+               check("@CA(6),@CA(5),@CA(1),@CA(2),@CA(3),@CA(4)", 
cc_a2.getAnnotations(CA.class));
+       }
+
+       @Test
+       public void getAnnotations_notFound() throws Exception {
+               check("", cb_a1.getAnnotations(DA.class));
+       }
+
+       @Test
+       public void getAnnotations_constructor() throws Exception {
+               check("@CA(9),@CA(1),@CA(2),@CA(3),@CA(4)", 
cc_cc.getAnnotations(CA.class));
+       }
+
+       @Test
+       public void getAnnotations_notFound_constructor() throws Exception {
+               check("", cc_cc.getAnnotations(DA.class));
+       }
+
+       @Test
+       public void getAnnotationsParentFirst() throws Exception {
+               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", 
cb_a1.getAnnotationsParentFirst(CA.class));
+               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", 
cb_a2.getAnnotationsParentFirst(CA.class));
+               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", 
cc_a1.getAnnotationsParentFirst(CA.class));
+               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5),@CA(6)", 
cc_a2.getAnnotationsParentFirst(CA.class));
+       }
+
+       @Test
+       public void getAnnotationsParentFirst_notFound() throws Exception {
+               check("", cb_a1.getAnnotationsParentFirst(DA.class));
+       }
+
+       @Test
+       public void getAnnotationsParentFirst_constructor() throws Exception {
+               check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(9)", 
cc_cc.getAnnotationsParentFirst(CA.class));
+       }
+
+       @Test
+       public void getAnnotationsParentFirst_notFound_constructor() throws 
Exception {
+               check("", cc_cc.getAnnotationsParentFirst(DA.class));
+       }
+
+       @Test
+       public void getAnnotation() throws Exception {
+               check("@CA(5)", cb_a1.getAnnotation(CA.class));
+               check("@CA(5)", cb_a2.getAnnotation(CA.class));
+               check("@CA(5)", cc_a1.getAnnotation(CA.class));
+               check("@CA(6)", cc_a2.getAnnotation(CA.class));
+       }
+
+       @Test
+       public void getAnnotation_notFound() throws Exception {
+               check(null, cb_a1.getAnnotation(DA.class));
+       }
+
+       @Test
+       public void getAnnotation_constructor() throws Exception {
+               check("@CA(9)", cc_cc.getAnnotation(CA.class));
+       }
+
+       @Test
+       public void getAnnotation_notFound_constructor() throws Exception {
+               check(null, cc_cc.getAnnotation(DA.class));
+       }
+
+       @Test
+       public void getAnnotation_twice() throws Exception {
+               check("@CA(5)", cb_a1.getAnnotation(CA.class));
+               check("@CA(5)", cb_a1.getAnnotation(CA.class));
+       }
+
+       @Test
+       public void getAnnotation_twice_constructor() throws Exception {
+               check("@CA(9)", cc_cc.getAnnotation(CA.class));
+               check("@CA(9)", cc_cc.getAnnotation(CA.class));
+       }
+
+       @Test
+       public void hasAnnotation() throws Exception {
+               assertTrue(cb_a1.hasAnnotation(CA.class));
+               assertTrue(cb_a2.hasAnnotation(CA.class));
+               assertTrue(cc_a1.hasAnnotation(CA.class));
+               assertTrue(cc_a2.hasAnnotation(CA.class));
+               assertFalse(cb_a1.hasAnnotation(DA.class));
+       }
+
+       @Test
+       public void hasAnnotation_constructor() throws Exception {
+               assertTrue(cc_cc.hasAnnotation(CA.class));
+               assertFalse(cc_cc.hasAnnotation(DA.class));
+       }
+
+       @Target({PARAMETER,TYPE})
+       @Retention(RUNTIME)
+       @Inherited
+       public static @interface DA {
+               public String value();
+       }
+       @DA("1") public static class D1 extends D2 {}
+       @DA("2") public static class D2 implements D3, D4 {}
+       @DA("3") public static interface D3 {}
+       @DA("4") public static interface D4 {}
+
+       public static interface DB {
+               public void a1(@DA("0") D1 x);
+       }
+       public static class DC implements DB {
+               @Override
+               public void a1(@DA("5") D1 x) {}
+       }
+
+       static ClassInfo
+               db = ClassInfo.of(DB.class),
+               dc = ClassInfo.of(DC.class);
+       static ParamInfo
+               db_a1 = db.getMethod("a1", D1.class).getParam(0),
+               dc_a1 = dc.getMethod("a1", D1.class).getParam(0);
+
+       @Test
+       public void getAnnotations_inherited() throws Exception {
+               check("@DA(0),@DA(1),@DA(2),@DA(3),@DA(4)", 
db_a1.getAnnotations(DA.class));
+               check("@DA(5),@DA(0),@DA(1),@DA(2),@DA(3),@DA(4)", 
dc_a1.getAnnotations(DA.class));
+       }
+
+       @Test
+       public void getAnnotations_inherited_notFound() throws Exception {
+               check("", db_a1.getAnnotations(CA.class));
+       }
+
+       @Test
+       public void getAnnotationsParentFirst_inherited() throws Exception {
+               check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0)", 
db_a1.getAnnotationsParentFirst(DA.class));
+               check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0),@DA(5)", 
dc_a1.getAnnotationsParentFirst(DA.class));
+       }
+
+       @Test
+       public void getAnnotationsParentFirst_inherited_notFound() throws 
Exception {
+               check("", db_a1.getAnnotationsParentFirst(CA.class));
+       }
+
+       @Test
+       public void getAnnotation_inherited() throws Exception {
+               check("@DA(0)", db_a1.getAnnotation(DA.class));
+               check("@DA(5)", dc_a1.getAnnotation(DA.class));
+       }
+
+       @Test
+       public void getAnnotation_inherited_notFound() throws Exception {
+               check(null, db_a1.getAnnotation(CA.class));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Other methods.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       static class E {
+               public void a1(int a, @Name("b") int b) {}
+       }
+
+       static ClassInfo e = ClassInfo.of(E.class);
+       static ParamInfo
+               e_a1_a = e.getMethod("a1", int.class, int.class).getParam(0),
+               e_a1_b = e.getMethod("a1", int.class, int.class).getParam(1);
+
+       @Test
+       public void hasName() {
+               e_a1_a.hasName();  // This might be true or false based on the 
JVM compiler used.
+               assertTrue(e_a1_b.hasName());
+       }
+
+       @Test
+       public void getName() {
+               e_a1_a.getName();  // This might be null or a value based on 
the JVM compiler used.
+               assertEquals("b", e_a1_b.getName());
+       }
+
+       @Test
+       public void toString2() {
+               assertEquals("a1[1]", e_a1_b.toString());
+       }
+}
diff --git a/juneau-core/juneau-dto/.settings/org.eclipse.jdt.core.prefs 
b/juneau-core/juneau-dto/.settings/org.eclipse.jdt.core.prefs
index 1a5f6d5..dbc47bf 100644
--- a/juneau-core/juneau-dto/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-core/juneau-dto/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-core/juneau-marshall-rdf/.settings/org.eclipse.jdt.core.prefs 
b/juneau-core/juneau-marshall-rdf/.settings/org.eclipse.jdt.core.prefs
index 1a5f6d5..dbc47bf 100644
--- a/juneau-core/juneau-marshall-rdf/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-core/juneau-marshall-rdf/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git a/juneau-core/juneau-marshall/.settings/org.eclipse.jdt.core.prefs 
b/juneau-core/juneau-marshall/.settings/org.eclipse.jdt.core.prefs
index 4a82b56..d16a260 100644
--- a/juneau-core/juneau-marshall/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-core/juneau-marshall/.settings/org.eclipse.jdt.core.prefs
@@ -9,7 +9,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul
 org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -122,6 +122,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index a7e70a9..9dcaeef 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -224,8 +224,18 @@ public class BeanMeta<T> {
                                                        throw new 
BeanRuntimeException(c, "Multiple instances of '@BeanConstructor' found.");
                                                constructor = x;
                                                constructorArgs = 
split(x.getAnnotation(BeanConstructor.class).properties());
-                                               if (constructorArgs.length != 
x.getParamCount())
-                                                       throw new 
BeanRuntimeException(c, "Number of properties defined in '@BeanConstructor' 
annotation does not match number of parameters in constructor.");
+                                               if (constructorArgs.length != 
x.getParamCount()) {
+                                                       if 
(constructorArgs.length != 0)
+                                                               throw new 
BeanRuntimeException(c, "Number of properties defined in '@BeanConstructor' 
annotation does not match number of parameters in constructor.");
+                                                       constructorArgs = new 
String[x.getParamCount()];
+                                                       int i = 0;
+                                                       for (ParamInfo pi : 
x.getParams()) {
+                                                               String pn = 
pi.getName();
+                                                               if (pn == null)
+                                                                       throw 
new BeanRuntimeException(c, "Could not find name for parameter #{0} of 
constructor ''{1}''", i, x.getFullName());
+                                                               
constructorArgs[i++] = pn;
+                                                       }
+                                               }
                                                constructor.setAccessible();
                                        }
                                }
@@ -477,7 +487,8 @@ public class BeanMeta<T> {
                 */
                private String findPropertyName(Field f, Set<String> 
fixedBeanProps) {
                        BeanProperty bp = f.getAnnotation(BeanProperty.class);
-                       String name = bpName(bp);
+                       Name n = f.getAnnotation(Name.class);
+                       String name = bpName(bp, n);
                        if (isNotEmpty(name)) {
                                if (fixedBeanProps.isEmpty() || 
fixedBeanProps.contains(name))
                                        return name;
@@ -615,7 +626,8 @@ public class BeanMeta<T> {
                                        continue;
 
                                BeanProperty bp = 
m.getAnnotation(BeanProperty.class);
-                               if (! (m.isVisible(v) || bp != null))
+                               Name n2 = m.getAnnotation(Name.class);
+                               if (! (m.isVisible(v) || bp != null || n2 != 
null))
                                        continue;
 
                                String n = m.getSimpleName();
@@ -623,7 +635,7 @@ public class BeanMeta<T> {
                                List<ClassInfo> pt = m.getParamTypes();
                                ClassInfo rt = m.getReturnType();
                                MethodType methodType = UNKNOWN;
-                               String bpName = bpName(bp);
+                               String bpName = bpName(bp, n2);
 
                                if (! (isEmpty(bpName) || filterProps.isEmpty() 
|| filterProps.contains(bpName)))
                                        throw new BeanRuntimeException(c, 
"Found @BeanProperty(\"{0}\") but name was not found in @Bean(properties)", 
bpName);
@@ -714,11 +726,12 @@ public class BeanMeta<T> {
                        for (FieldInfo f : c2.getDeclaredFields()) {
                                if (f.isAny(STATIC, TRANSIENT))
                                        continue;
-                               if (f.isAnnotationPresent(BeanIgnore.class))
+                               if (f.hasAnnotation(BeanIgnore.class))
                                        continue;
 
                                BeanProperty bp = 
f.getAnnotation(BeanProperty.class);
-                               String bpName = bpName(bp);
+                               Name n = f.getAnnotation(Name.class);
+                               String bpName = bpName(bp, n);
 
                                if (! (v.isVisible(f.inner()) || bp != null))
                                        continue;
@@ -737,7 +750,7 @@ public class BeanMeta<T> {
                        for (FieldInfo f : c2.getDeclaredFields()) {
                                if (f.isAny(STATIC, TRANSIENT))
                                        continue;
-                               if (f.isAnnotationPresent(BeanIgnore.class))
+                               if (f.hasAnnotation(BeanIgnore.class))
                                        continue;
                                if (f.hasName(name))
                                        return f.inner();
@@ -897,7 +910,11 @@ public class BeanMeta<T> {
                }
        }
 
-       static final String bpName(BeanProperty bp) {
+       static final String bpName(BeanProperty bp, Name n) {
+               if (bp == null && n == null)
+                       return null;
+               if (n != null)
+                       return n.value();
                if (bp == null)
                        return null;
                if (! bp.name().isEmpty())
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index bc985d0..8f7365c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -519,25 +519,25 @@ public final class ClassMeta<T> implements Type {
                        }
 
                        for (FieldInfo f : ci.getAllFieldsParentFirst()) {
-                               if 
(f.isAnnotationPresent(ParentProperty.class)) {
+                               if (f.hasAnnotation(ParentProperty.class)) {
                                        if (f.isStatic())
                                                throw new 
ClassMetaRuntimeException("@ParentProperty used on invalid field ''{0}''.  Must 
be static.", f);
-                                       f.setAccessible(false);
+                                       f.setAccessible();
                                        parentPropertyMethod = new 
Setter.FieldSetter(f.inner());
                                }
-                               if (f.isAnnotationPresent(NameProperty.class)) {
+                               if (f.hasAnnotation(NameProperty.class)) {
                                        if (f.isStatic())
                                                throw new 
ClassMetaRuntimeException("@NameProperty used on invalid field ''{0}''.  Must 
be static.", f);
-                                       f.setAccessible(false);
+                                       f.setAccessible();
                                        namePropertyMethod = new 
Setter.FieldSetter(f.inner());
                                }
                        }
 
                        for (FieldInfo f : ci.getDeclaredFields()) {
-                               if (f.isAnnotationPresent(Example.class)) {
+                               if (f.hasAnnotation(Example.class)) {
                                        if (! (f.isStatic() && 
ci.isParentOf(f.getType().inner())))
                                                throw new 
ClassMetaRuntimeException("@Example used on invalid field ''{0}''.  Must be 
static and an instance of the type.", f);
-                                       f.setAccessible(false);
+                                       f.setAccessible();
                                        exampleField = f.inner();
                                }
                        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/UriContext.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/UriContext.java
index ba5f503..6779244 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/UriContext.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/UriContext.java
@@ -68,8 +68,8 @@ public class UriContext {
         * @param pathInfo
         *      The path info (e.g. <js>"/path-info"</js>, or 
<js>"path-info"</js>)
         */
-       
@BeanConstructor(properties="authority,contextRoot,servletPath,pathInfo")
-       public UriContext(String authority, String contextRoot, String 
servletPath, String pathInfo) {
+       @BeanConstructor
+       public UriContext(@Name("authority") String authority, 
@Name("contextRoot") String contextRoot, @Name("servletPath") String 
servletPath, @Name("pathInfo") String pathInfo) {
                this.authority = nullIfEmpty(trimSlashes(authority));
                this.contextRoot = nullIfEmpty(trimSlashes(contextRoot));
                this.servletPath = nullIfEmpty(trimSlashes(servletPath));
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConstructor.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConstructor.java
index cded7e1..60ad50d 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConstructor.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConstructor.java
@@ -56,14 +56,14 @@ public @interface BeanConstructor {
        /**
         * The names of the properties of the constructor arguments.
         * <p>
-        *      The {@link org.apache.juneau.annotation.BeanConstructor 
@BeanConstructor} annotation is used to 
+        *      The {@link org.apache.juneau.annotation.BeanConstructor 
@BeanConstructor} annotation is used to
         *      map constructor arguments to property names on bean with 
read-only properties.
-        *      <br>Since method parameter names are lost during compilation, 
this annotation essentially redefines 
+        *      <br>Since method parameter names are lost during compilation, 
this annotation essentially redefines
         *      them so that they are available at runtime.
         *      </p>
         *      <p>
         *      The definition of a read-only bean is a bean with properties 
with only getters, like shown below:
-        *      </p>    
+        *      </p>
         *      <p class='bpcode w800'>
         *              <jc>// Our read-only bean.</jc>
         *              <jk>public class</jk> Person {
@@ -86,7 +86,7 @@ public @interface BeanConstructor {
         *                      <jk>public int</jk> getAge() {
         *                              <jk>return</jk> <jf>age</jf>;
         *                      }
-        *              }                       
+        *              }
         *      </p>
         *      <p class='bpcode w800'>
         *              <jc>// Parsing into a read-only bean.</jc>
@@ -95,7 +95,11 @@ public @interface BeanConstructor {
         *              String name = p.getName();  <jc>// "John Smith"</jc>
         *              <jk>int</jk> age = p.getAge();   <jc>// 45</jc>
         *      </p>
-       */
-       
+        * <p>
+        *      Note that the {@link Name @Name} annotation can also be used to 
identify bean property names on constructor
+        *      arguments.  If neither this annotation or {@link Name @Name} is 
used, then we try to get the property names
+        *      from the parameter names if they are available in the bytecode.
+        * </p>
+        */
        String properties() default "";
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanProperty.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanProperty.java
index 84a5b9d..42cf6b6 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanProperty.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanProperty.java
@@ -143,6 +143,8 @@ public @interface BeanProperty {
         *              Note that if you're not interested in these additional 
properties, you can also use the
         *              {@link BeanContext#BEAN_ignoreUnknownBeanProperties} 
setting to ignore values that don't fit into existing
         *              properties.
+        *      <li class='info'>
+        *              Note that the {@link Name @Name} annotation can also be 
used for identifying a property name.
         * </ul>
         */
        String name() default "";
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Name.java
similarity index 54%
copy from 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
copy to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Name.java
index 499578b..5e1c411 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Name.java
@@ -1,66 +1,57 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you 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.apache.juneau.reflect;
-
-import java.lang.annotation.*;
-
-/**
- * Represents an annotation instance on a class and the class it was found on.
- *
- * @param <T> The annotation type.
- */
-public class AnnotationInfo<T extends Annotation> {
-
-       private ClassInfo c;
-       private T a;
-
-       /**
-        * Constructor.
-        *
-        * @param c The class where the annotation was found.
-        * @param a The annotation found.
-        */
-       public AnnotationInfo(ClassInfo c, T a) {
-               this.c = c;
-               this.a = a;
-       }
-
-       /**
-        * Convenience constructor.
-        *
-        * @param c The class where the annotation was found.
-        * @param a The annotation found.
-        * @return A new {@link AnnotationInfo} object.
-        */
-       public static <T extends Annotation> AnnotationInfo<T> of(ClassInfo c, 
T a) {
-               return new AnnotationInfo<>(c, a);
-       }
-
-       /**
-        * Returns the class where the annotation was found.
-        *
-        * @return the class where the annotation was found.
-        */
-       public ClassInfo getClassOn() {
-               return c;
-       }
-
-       /**
-        * Returns the annotation found.
-        *
-        * @return The annotation found.
-        */
-       public T getAnnotation() {
-               return a;
-       }
-}
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you 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.apache.juneau.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation that can be used on method parameters to identify their name.
+ *
+ * <p>
+ * Can be used in the following locations:
+ * <ul>
+ *     <li>In place of 
<code><ja>@BeanProperty</ja>(name=<js>"foo"</js>)</code> when just the name is 
specified.
+ *     <li>On constructor and method arguments when the parameter names are 
not in the compiled bytecode.
+ * </ul>
+ *
+ * <h5 class='figure'>Examples:</h5>
+ * <p class='bcode w800'>
+ *     <jc>// Identifying bean property names.
+ *     // The field name can be anything.</jc>
+ *     <jk>public class</jk> MyBean {
+ *
+ *             <jc>// Same as @BeanProperty(properties="bar")</jc>
+ *             <jk>public</jk> MyBean(@Name("bar") <jk>int</jk> foo) {}
+ *
+ *             <ja>@Name</ja>(<js>"bar"</js>) <jc>// Same as 
@BeanProperty(name="bar")</jc>
+ *             <jk>public int</jk> foo;
+ *
+ *             <ja>@Name</ja>(<js>"*"</js>) <jc>// Same as 
@BeanProperty(name="*")</jc>
+ *             <jk>public</jk> Map&lt;String,Object&gt; extraStuff = 
<jk>new</jk> LinkedHashMap&lt;String,Object&gt;();
+ *     }
+ * </p>
+ */
+@Documented
+@Target({PARAMETER,METHOD,FIELD})
+@Retention(RUNTIME)
+@Inherited
+public @interface Name {
+
+       /**
+        * The bean property or parameter name.
+        */
+       String value();
+}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
index 6503d4e..a70d27d 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
@@ -67,7 +67,7 @@ public class HttpPartSchemaBuilder {
 
        HttpPartSchemaBuilder apply(Class<? extends Annotation> c, ParamInfo 
mpi) {
                apply(c, mpi.getParameterType().innerType());
-               for (Annotation a : mpi.getParameterAnnotations())
+               for (Annotation a : mpi.getDeclaredAnnotations())
                        if (c.isInstance(a))
                                apply(a);
                return this;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanPropertyMeta.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanPropertyMeta.java
index fc34ad2..c08948b 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanPropertyMeta.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanPropertyMeta.java
@@ -29,7 +29,7 @@ public class RequestBeanPropertyMeta {
 
        static RequestBeanPropertyMeta.Builder create(HttpPartType partType, 
Class<? extends Annotation> c, MethodInfo m) {
                HttpPartSchemaBuilder sb = 
HttpPartSchema.create().name(m.getPropertyName());
-               for (Annotation a : m.getAnnotations(c, true))
+               for (Annotation a : m.getAnnotationsParentFirst(c))
                        sb.apply(a);
                return new 
Builder().partType(partType).schema(sb.build()).getter(m.inner());
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/ResponseBeanMeta.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/ResponseBeanMeta.java
index 9b5ce6a..2f23850 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/ResponseBeanMeta.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/ResponseBeanMeta.java
@@ -71,7 +71,7 @@ public class ResponseBeanMeta {
                        return null;
                Builder b = new Builder(ps);
                b.apply(m.getReturnType().resolved().innerType());
-               for (Response r : m.getAnnotations(Response.class, true))
+               for (Response r : m.getAnnotationsParentFirst(Response.class))
                        b.apply(r);
                return b.build();
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
index a915537..5138591 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -131,9 +131,10 @@ public final class ClassUtils {
        public static int fuzzyArgsMatch(Class<?>[] paramTypes, Class<?>... 
argTypes) {
                int matches = 0;
                outer: for (Class<?> p : paramTypes) {
-                       p = getClassInfo(p).getWrapperIfPrimitive();
+                       ClassInfo pi = 
getClassInfo(p).getWrapperInfoIfPrimitive();
                        for (Class<?> a : argTypes) {
-                               if (getClassInfo(p).isParentOf(a)) {
+                               ClassInfo ai = 
getClassInfo(a).getWrapperInfoIfPrimitive();
+                               if (pi.isParentOf(ai.inner())) {
                                        matches++;
                                        continue outer;
                                }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
index 499578b..f427275 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
@@ -30,7 +30,7 @@ public class AnnotationInfo<T extends Annotation> {
         * @param c The class where the annotation was found.
         * @param a The annotation found.
         */
-       public AnnotationInfo(ClassInfo c, T a) {
+       protected AnnotationInfo(ClassInfo c, T a) {
                this.c = c;
                this.a = a;
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
index df50bea..04c7870 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
@@ -327,6 +327,21 @@ public final class ClassInfo {
        }
 
        /**
+        * Returns the method with the specified method name and argument types.
+        *
+        * @param name The method name (e.g. <js>"toString"</js>).
+        * @param args The exact argument types.
+        * @return
+        *  The method with the specified method name and argument types, or 
<jk>null</jk> if not found.
+        */
+       public MethodInfo getMethod(String name, Class<?>...args) {
+               for (MethodInfo mi : getAllMethods())
+                       if (mi.hasName(name) && mi.hasArgs(args))
+                               return mi;
+               return null;
+       }
+
+       /**
         * Returns all methods declared on this class.
         *
         * @return
@@ -506,6 +521,20 @@ public final class ClassInfo {
        }
 
        /**
+        * Returns the declared constructor with the specified argument types.
+        *
+        * @param args The exact argument types.
+        * @return
+        *  The declared constructor with the specified argument types, or 
<jk>null</jk> if not found.
+        */
+       public ConstructorInfo getDeclaredConstructor(Class<?>...args) {
+               for (ConstructorInfo ci : getDeclaredConstructors())
+                       if (ci.hasArgs(args))
+                               return ci;
+               return null;
+       }
+
+       /**
         * Same as {@link #getPublicConstructor(Class...)} but allows for 
inexact arg type matching.
         *
         * <p>
@@ -720,6 +749,33 @@ public final class ClassInfo {
                return m;
        }
 
+
+       /**
+        * Returns the public field with the specified name.
+        *
+        * @param name The field name.
+        * @return The public field, or <jk>null</jk> if not found.
+        */
+       public FieldInfo getPublicField(String name) {
+               for (FieldInfo f : getPublicFields())
+                       if (f.getName().equals(name))
+                               return f;
+               return null;
+       }
+
+       /**
+        * Returns the declared field with the specified name.
+        *
+        * @param name The field name.
+        * @return The declared field, or <jk>null</jk> if not found.
+        */
+       public FieldInfo getDeclaredField(String name) {
+               for (FieldInfo f : getDeclaredFields())
+                       if (f.getName().equals(name))
+                               return f;
+               return null;
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Annotations
        
//-----------------------------------------------------------------------------------------------------------------
@@ -774,6 +830,8 @@ public final class ClassInfo {
         */
        @SuppressWarnings("unchecked")
        public <T extends Annotation> T getDeclaredAnnotation(Class<T> a) {
+               if (a == null)
+                       return null;
                Optional<Annotation> o = declaredAnnotationMap().get(a);
                if (o == null) {
                        o = Optional.ofNullable(findDeclaredAnnotation(a));
@@ -995,10 +1053,9 @@ public final class ClassInfo {
 
        @SuppressWarnings("unchecked")
        private <T extends Annotation> T findDeclaredAnnotation(Class<T> a) {
-               if (c != null)
-                       for (Annotation a2 : c.getDeclaredAnnotations())
-                               if (a2.annotationType() == a)
-                                       return (T)a2;
+               for (Annotation a2 : c.getDeclaredAnnotations())
+                       if (a2.annotationType() == a)
+                               return (T)a2;
                return null;
        }
 
@@ -1654,7 +1711,9 @@ public final class ClassInfo {
         * @return <jk>true</jk> if the specified class is the same as this one.
         */
        public boolean is(ClassInfo c) {
-               return this.c != null && this.c.equals(c.inner());
+               if (this.c != null)
+                       return this.c.equals(c.inner());
+               return t.equals(c.t);
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
index 06b93e0..0753487 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
@@ -721,4 +721,9 @@ public abstract class ExecutableInfo {
        public final String getSimpleName() {
                return isConstructor ? e.getDeclaringClass().getSimpleName() : 
e.getName();
        }
+
+       @Override
+       public String toString() {
+               return getShortName();
+       }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/FieldInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/FieldInfo.java
index 3913e27..055641a 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/FieldInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/FieldInfo.java
@@ -98,9 +98,21 @@ public final class FieldInfo implements 
Comparable<FieldInfo> {
         * @return The annotation, or <jk>null</jk> if not found.
         */
        public <T extends Annotation> T getAnnotation(Class<T> a) {
+               if (a == null)
+                       return null;
                return f.getAnnotation(a);
        }
 
+       /**
+        * Returns <jk>true</jk> if the specified annotation is present.
+        *
+        * @param a The annotation to check for.
+        * @return <jk>true</jk> if the specified annotation is present.
+        */
+       public boolean hasAnnotation(Class<? extends Annotation> a) {
+               return f.isAnnotationPresent(a);
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Characteristics
        
//-----------------------------------------------------------------------------------------------------------------
@@ -122,10 +134,6 @@ public final class FieldInfo implements 
Comparable<FieldInfo> {
                                        if (isDeprecated())
                                                return false;
                                        break;
-                               case HAS_PARAMS:
-                                       break;
-                               case HAS_NO_PARAMS:
-                                       break;
                                case PUBLIC:
                                        if (isNotPublic())
                                                return false;
@@ -287,49 +295,40 @@ public final class FieldInfo implements 
Comparable<FieldInfo> {
                return f.getName().equals(name);
        }
 
-       /**
-        * Identifies if the specified visibility matches this field.
-        *
-        * @param v The visibility to validate against.
-        * @return <jk>true</jk> if this visibility matches the modifier 
attribute of this field.
-        */
-       public boolean isVisible(Visibility v) {
-               return v.isVisible(f);
-       }
-
        
//-----------------------------------------------------------------------------------------------------------------
-       // Annotations.
+       // Visibility
        
//-----------------------------------------------------------------------------------------------------------------
 
        /**
-        * Returns <jk>true</jk> if the specified annotation is present.
-        *
-        * @param a The annotation to check for.
-        * @return <jk>true</jk> if the specified annotation is present.
-        */
-       public boolean isAnnotationPresent(Class<? extends Annotation> a) {
-               return f.isAnnotationPresent(a);
-       }
-
-       /**
         * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and 
quietly ignores security exceptions.
         *
-        * @param ignoreExceptions Ignore {@link SecurityException 
SecurityExceptions} and just return <jk>false</jk> if thrown.
         * @return <jk>true</jk> if call was successful.
         */
-       public boolean setAccessible(boolean ignoreExceptions) {
+       public boolean setAccessible() {
                try {
                        if (! (f.isAccessible()))
                                f.setAccessible(true);
                        return true;
                } catch (SecurityException e) {
-                       if (ignoreExceptions)
-                               return false;
-                       throw new ClassMetaRuntimeException("Could not set 
accessibility to true on field ''{0}''", f);
+                       return false;
                }
        }
 
        /**
+        * Identifies if the specified visibility matches this field.
+        *
+        * @param v The visibility to validate against.
+        * @return <jk>true</jk> if this visibility matches the modifier 
attribute of this field.
+        */
+       public boolean isVisible(Visibility v) {
+               return v.isVisible(f);
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Other methods.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       /**
         * Returns the type of this field.
         *
         * @return The type of this field.
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
index 11d098e..62c8ad1 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
@@ -127,24 +127,23 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
         *      A list of all matching annotations found in child-to-parent 
order, or an empty list if none found.
         */
        public <T extends Annotation> List<T> getAnnotations(Class<T> a) {
-               return getAnnotations(a, false);
+               return appendAnnotations(new ArrayList<>(), a, false);
        }
 
        /**
-        * Identical to {@link #getAnnotations(Class)} but optionally returns 
the list in reverse (parent-to-child) order.
+        * Identical to {@link #getAnnotations(Class)} but returns the list in 
reverse (parent-to-child) order.
         *
         * @param a
         *      The annotation to search for.
-        * @param parentFirst If <jk>true</jk>, results are in parent-to-child 
order.
         * @return
         *      A list of all matching annotations found or an empty list if 
none found.
         */
-       public <T extends Annotation> List<T> getAnnotations(Class<T> a, 
boolean parentFirst) {
-               return appendAnnotations(new ArrayList<>(), a, parentFirst);
+       public <T extends Annotation> List<T> 
getAnnotationsParentFirst(Class<T> a) {
+               return appendAnnotations(new ArrayList<>(), a, true);
        }
 
        /**
-        * Finds and appends the specified annotation on the specified method 
and methods onsuperclasses/interfaces to the specified
+        * Finds and appends the specified annotation on the specified method 
and methods on superclasses/interfaces to the specified
         * list.
         *
         * <p>
@@ -164,11 +163,14 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
         *
         * @param l The list of annotations.
         * @param a The annotation.
-        * @param parentFirst If <jk>true</jk>, results are ordered in 
parent-to-child order.
         * @return The same list.
         */
+       public <T extends Annotation> List<T> 
appendAnnotationsParentFirst(List<T> l, Class<T> a) {
+               return appendAnnotations(l, a, true);
+       }
+
        @SuppressWarnings("unchecked")
-       public <T extends Annotation> List<T> appendAnnotations(List<T> l, 
Class<T> a, boolean parentFirst) {
+       private <T extends Annotation> List<T> appendAnnotations(List<T> l, 
Class<T> a, boolean parentFirst) {
                List<Method> methods = getMatching();
                for (Method m2 : iterable(methods, parentFirst))
                        for (Annotation a2 :  m2.getAnnotations())
@@ -209,6 +211,17 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
        
//-----------------------------------------------------------------------------------------------------------------
 
        /**
+        * Returns the generic return type of this method as a {@link 
ClassInfo} object.
+        *
+        * @return The generic return type of this method.
+        */
+       public ClassInfo getReturnType() {
+               if (returnType == null)
+                       returnType = ClassInfo.of(m.getReturnType(), 
m.getGenericReturnType());
+               return returnType;
+       }
+
+       /**
         * Returns <jk>true</jk> if this method has this return type.
         *
         * @param c The return type to test for.
@@ -322,9 +335,9 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
         *  <jc>// Example method:</jc>
         *      <jk>public void</jk> foo(String bar, Integer baz);
         *
-        *      isArgsOnlyOfType(fooMethod, String.<jk>class</jk>, 
Integer.<jk>class</jk>);  <jc>// True.</jc>
-        *      isArgsOnlyOfType(fooMethod, String.<jk>class</jk>, 
Integer.<jk>class</jk>, Map.<jk>class</jk>);  <jc>// True.</jc>
-        *      isArgsOnlyOfType(fooMethod, String.<jk>class</jk>);  <jc>// 
False.</jc>
+        *      argsOnlyOfType(fooMethod, String.<jk>class</jk>, 
Integer.<jk>class</jk>);  <jc>// True.</jc>
+        *      argsOnlyOfType(fooMethod, String.<jk>class</jk>, 
Integer.<jk>class</jk>, Map.<jk>class</jk>);  <jc>// True.</jc>
+        *      argsOnlyOfType(fooMethod, String.<jk>class</jk>);  <jc>// 
False.</jc>
         * </p>
         *
         * @param args The valid class types (exact) for the arguments.
@@ -342,29 +355,6 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
                return true;
        }
 
-       @Override
-       public String toString() {
-               StringBuilder sb = new 
StringBuilder(m.getDeclaringClass().getName() + "." + m.getName() + "(");
-               for (int i = 0; i < rawParamTypes().length; i++) {
-                       if (i > 0)
-                               sb.append(",");
-                       sb.append(rawParamTypes()[i].getSimpleName());
-               }
-               sb.append(")");
-               return sb.toString();
-       }
-
-       /**
-        * Returns the generic return type of this method as a {@link 
ClassInfo} object.
-        *
-        * @return The generic return type of this method.
-        */
-       public ClassInfo getReturnType() {
-               if (returnType == null)
-                       returnType = ClassInfo.of(m.getReturnType(), 
m.getGenericReturnType());
-               return returnType;
-       }
-
        /**
         * Returns <jk>true</jk> if this method is a bridge method.
         *
@@ -387,22 +377,4 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
                }
                return i;
        }
-
-       /**
-        * Returns a readable representation of this method.
-        *
-        * @return A readable representation of this method.
-        */
-       public Object getReadableName() {
-               StringBuilder sb = new StringBuilder(128);
-               
sb.append(m.getDeclaringClass().getName()).append('.').append(m.getName()).append('(');
-               List<ParamInfo> mpis = getParams();
-               for (int i = 0; i < mpis.size(); i++) {
-                       if (i > 0)
-                               sb.append(',');
-                       mpis.get(i).getParameterType().appendFullName(sb);
-               }
-               sb.append(')');
-               return sb.toString();
-       }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
index 57d3066..bc0c6e5 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
@@ -30,7 +30,7 @@ public final class ParamInfo {
        private final ExecutableInfo eInfo;
        private final Parameter p;
        private final int index;
-       private Map<Class<?>,Optional<Annotation>> annotationMap = new 
ConcurrentHashMap<>();
+       private volatile Map<Class<?>,Optional<Annotation>> annotationMap;
 
        
//-----------------------------------------------------------------------------------------------------------------
        // Instantiation.
@@ -61,19 +61,19 @@ public final class ParamInfo {
        /**
         * Returns the method that this parameter belongs to.
         *
-        * @return The method that this parameter belongs to.
+        * @return The method that this parameter belongs to, or <jk>null</jk> 
if it belongs to a constructor.
         */
        public MethodInfo getMethod() {
-               return (MethodInfo)eInfo;
+               return eInfo.isConstructor() ? null : (MethodInfo)eInfo;
        }
 
        /**
-        * Returns the method that this parameter belongs to.
+        * Returns the constructor that this parameter belongs to.
         *
-        * @return The method that this parameter belongs to.
+        * @return The constructor that this parameter belongs to, or 
<jk>null</jk> if it belongs to a method.
         */
        public ConstructorInfo getConstructor() {
-               return (ConstructorInfo)eInfo;
+               return eInfo.isConstructor() ? (ConstructorInfo)eInfo : null;
        }
 
        /**
@@ -85,16 +85,37 @@ public final class ParamInfo {
                return eInfo.getParamType(index);
        }
 
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Annotations.
+       
//-----------------------------------------------------------------------------------------------------------------
+
        /**
-        * Returns the parameter annotations defined on this parameter.
+        * Returns the parameter annotations declared on this parameter.
         *
-        * @return The parameter annotations defined on this parameter.
+        * @return The parameter annotations declared on this parameter, or an 
empty array if none found.
         */
-       public Annotation[] getParameterAnnotations() {
+       public Annotation[] getDeclaredAnnotations() {
                return eInfo.getParameterAnnotations(index);
        }
 
        /**
+        * Returns the specified parameter annotation declared on this 
parameter.
+        *
+        * @param a
+        *      The annotation to search for.
+        * @param <T>
+        * @return The specified parameter annotation declared on this 
parameter, or <jk>null</jk> if not found.
+        */
+       @SuppressWarnings("unchecked")
+       public <T extends Annotation> T getDeclaredAnnotation(Class<T> a) {
+               if (a != null)
+                       for (Annotation aa : 
eInfo.getParameterAnnotations(index))
+                               if (a.isInstance(aa))
+                                       return (T)aa;
+               return null;
+       }
+
+       /**
         * Finds the annotation of the specified type defined on this method 
parameter.
         *
         * <p>
@@ -161,48 +182,23 @@ public final class ParamInfo {
         *      A list of all matching annotations found in child-to-parent 
order, or an empty list if none found.
         */
        public <T extends Annotation> List<T> getAnnotations(Class<T> a) {
-               return getAnnotations(a, false);
+               return appendAnnotations(new ArrayList<>(), a, false);
        }
 
        /**
-        * Identical to {@link #getAnnotations(Class)} but optionally returns 
the list in reverse (parent-to-child) order.
+        * Identical to {@link #getAnnotations(Class)} but returns the list in 
reverse (parent-to-child) order.
         *
         * @param a
         *      The annotation to search for.
-        * @param parentFirst If <jk>true</jk>, results are in parent-to-child 
order.
         * @return
         *      A list of all matching annotations found or an empty list if 
none found.
         */
-       public <T extends Annotation> List<T> getAnnotations(Class<T> a, 
boolean parentFirst) {
-               return appendAnnotations(new ArrayList<>(), a, parentFirst);
-       }
-
-       /**
-        * Finds and appends the specified annotation on the specified method 
and methods onsuperclasses/interfaces to the specified
-        * list.
-        *
-        * <p>
-        * Results are ordered in child-to-parent order.
-        *
-        * @param l The list of annotations.
-        * @param a The annotation.
-        * @return The same list.
-        */
-       public <T extends Annotation> List<T> appendAnnotations(List<T> l, 
Class<T> a) {
-               return appendAnnotations(l, a, false);
+       public <T extends Annotation> List<T> 
getAnnotationsParentFirst(Class<T> a) {
+               return appendAnnotations(new ArrayList<>(), a, true);
        }
 
-       /**
-        * Finds and appends the specified annotation on the specified class 
and superclasses/interfaces to the specified
-        * list.
-        *
-        * @param l The list of annotations.
-        * @param a The annotation.
-        * @param parentFirst If <jk>true</jk>, results are ordered in 
parent-to-child order.
-        * @return The same list.
-        */
        @SuppressWarnings("unchecked")
-       public <T extends Annotation> List<T> appendAnnotations(List<T> l, 
Class<T> a, boolean parentFirst) {
+       private <T extends Annotation> List<T> appendAnnotations(List<T> l, 
Class<T> a, boolean parentFirst) {
                if (eInfo.isConstructor) {
                        ClassInfo ci = eInfo.getParamType(index).resolved();
                        Annotation[] annotations = 
eInfo.getParameterAnnotations(index);
@@ -238,13 +234,23 @@ public final class ParamInfo {
                return l;
        }
 
+       private synchronized Map<Class<?>,Optional<Annotation>> annotationMap() 
{
+               if (annotationMap == null)
+                       annotationMap = new ConcurrentHashMap<>();
+               return annotationMap;
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Other methods.
+       
//-----------------------------------------------------------------------------------------------------------------
+
        /**
         * Returns <jk>true</jk> if the parameter has a name provided by the 
class file.
         *
         * @return <jk>true</jk> if the parameter has a name provided by the 
class file.
         */
        public boolean hasName() {
-               return p.isNamePresent();
+               return p.isNamePresent() || p.isAnnotationPresent(Name.class);
        }
 
        /**
@@ -258,13 +264,12 @@ public final class ParamInfo {
         * @see Parameter#getName()
         */
        public String getName() {
-               return p.getName();
-       }
-
-       private synchronized Map<Class<?>,Optional<Annotation>> annotationMap() 
{
-               if (annotationMap == null)
-                       annotationMap = new ConcurrentHashMap<>();
-               return annotationMap;
+               Name n = p.getAnnotation(Name.class);
+               if (n != null)
+                       return n.value();
+               if (p.isNamePresent())
+                       return p.getName();
+               return null;
        }
 
        @Override
diff --git a/juneau-core/juneau-svl/.settings/org.eclipse.jdt.core.prefs 
b/juneau-core/juneau-svl/.settings/org.eclipse.jdt.core.prefs
index 72d13e9..5b789dd 100644
--- a/juneau-core/juneau-svl/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-core/juneau-svl/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git a/juneau-doc/docs/ReleaseNotes/8.0.1.html 
b/juneau-doc/docs/ReleaseNotes/8.0.1.html
index 36e1acf..f587c2f 100644
--- a/juneau-doc/docs/ReleaseNotes/8.0.1.html
+++ b/juneau-doc/docs/ReleaseNotes/8.0.1.html
@@ -23,6 +23,8 @@
 <ul class='spaced-list'>
        <li>
                New utility class for diffing beans: {@link oaj.utils.BeanDiff}
+       <li>
+               New annotation for defining bean property names: {@link 
oaj.annotation.Name}
 </ul>
 
 <h5 class='topic w800'>juneau-config</h5>
diff --git 
a/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/08.BeanAnnotation.html
 
b/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/08.BeanAnnotation.html
index aea79ec..7ff9999 100644
--- 
a/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/08.BeanAnnotation.html
+++ 
b/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/08.BeanAnnotation.html
@@ -13,7 +13,7 @@
  
***************************************************************************************************************************/
  -->
 
-@BeanProperty Annotation
+@Bean Annotation
 
 <p>
        The {@link oaj.annotation.Bean @Bean} annotation is used to tailor how 
beans are 
diff --git 
a/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/09.BeanPropertyAnnotation.html
 
b/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/09.BeanPropertyAnnotation.html
index f78a5bc..8bdef83 100644
--- 
a/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/09.BeanPropertyAnnotation.html
+++ 
b/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/09.BeanPropertyAnnotation.html
@@ -13,7 +13,7 @@
  
***************************************************************************************************************************/
  -->
 
-@BeanProperty Annotation
+{updated} @BeanProperty Annotation
 
 <p>
        The {@link oaj.annotation.BeanProperty @BeanProperty} annotation is 
used to tailor how 
@@ -30,6 +30,15 @@
        }
 </p>
 <p>
+       The {@link oaj.annoation.Name @Name} annotation is a shortcut for 
specifying a bean property name:
+</p>
+<p class='bpcode w800'>
+       <jk>public class</jk> MyBean {
+               <ja>@Name</ja>(<js>"Bar"</js>)
+               <jk>public</jk> String getFoo() {...}
+       }
+</p>
+<p>
        If the {@link oaj.BeanContext#BEAN_beanFieldVisibility} setting on the 
bean context excludes this field 
        (e.g. the visibility is set to the default of PUBLIC, but the field is 
PROTECTED), this annotation 
        can be used to force the field to be identified as a property.
diff --git 
a/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/10.BeanConstructorAnnotation.html
 
b/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/10.BeanConstructorAnnotation.html
index ee796d3..768fb54 100644
--- 
a/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/10.BeanConstructorAnnotation.html
+++ 
b/juneau-doc/docs/Topics/02.juneau-marshall/10.Transforms/10.BeanConstructorAnnotation.html
@@ -13,7 +13,7 @@
  
***************************************************************************************************************************/
  -->
 
-@BeanConstructor Annotation
+{updated} @BeanConstructor Annotation
 
 <p>
        The {@link oaj.annotation.BeanConstructor @BeanConstructor} annotation 
is used to 
@@ -58,3 +58,17 @@
 <p>
        Beans can also be defined with a combination of read-only and 
read-write properties.
 </p>
+<p>
+       The {@link oaj.annotation.Name @Name} annotation can also be used 
instead of <code><ja>@BeanConstructor</ja>(properties)</code>:
+</p>
+<p class='bpcode w800'>
+       <ja>@BeanConstructor</ja>
+       <jk>public</jk> Person(<ja>@Name</ja>(<js>"name"</js>) String name, 
<ja>@Name</ja>(<js>"age"</js>) <jk>int</jk> age) {
+               <jk>this</jk>.<jf>name</jf> = name;
+               <jk>this</jk>.<jf>age</jf> = age;
+       }
+</p>
+<p>
+       If neither <code><ja>@BeanConstructor</ja>(properties)</code> or 
<ja>@Name</ja> is used to identify the bean property names, 
+       we will try to use the parameter names if they are available in the 
bytecode.
+</p>
diff --git 
a/juneau-examples/juneau-examples-core/.settings/org.eclipse.jdt.core.prefs 
b/juneau-examples/juneau-examples-core/.settings/org.eclipse.jdt.core.prefs
index 0721a8a..3bfcb67 100644
--- a/juneau-examples/juneau-examples-core/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-examples/juneau-examples-core/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/core/pojo/Pojo.java
 
b/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/core/pojo/Pojo.java
index 8980396..d30621c 100644
--- 
a/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/core/pojo/Pojo.java
+++ 
b/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/core/pojo/Pojo.java
@@ -19,7 +19,7 @@
 
 package org.apache.juneau.examples.core.pojo;
 
-import org.apache.juneau.annotation.BeanConstructor;
+import org.apache.juneau.annotation.*;
 
 /**
  * Sample pojo class.
@@ -33,8 +33,8 @@ public class Pojo {
        private final String id;
        private final String name;
 
-       @BeanConstructor(properties = "id,name")
-       public Pojo(String id, String name) {
+       @BeanConstructor
+       public Pojo(@Name("id") String id, @Name("name") String name) {
                this.id = id;
                this.name = name;
        }
diff --git 
a/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/core/pojo/PojoComplex.java
 
b/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/core/pojo/PojoComplex.java
index 302af32..869afd5 100644
--- 
a/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/core/pojo/PojoComplex.java
+++ 
b/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/core/pojo/PojoComplex.java
@@ -38,8 +38,8 @@ public class PojoComplex {
         * @param innerPojo
         * @param values
         */
-       @BeanConstructor(properties = "id,innerPojo,values")
-       public PojoComplex(String id, Pojo innerPojo, HashMap<String, 
List<Pojo>> values) {
+       @BeanConstructor
+       public PojoComplex(@Name("id") String id, @Name("innerPojo") Pojo 
innerPojo, @Name("values") HashMap<String, List<Pojo>> values) {
                this.id = id;
                this.innerPojo = innerPojo;
                this.values = values;
diff --git 
a/juneau-examples/juneau-examples-rest-springboot/.settings/org.eclipse.jdt.core.prefs
 
b/juneau-examples/juneau-examples-rest-springboot/.settings/org.eclipse.jdt.core.prefs
index 0721a8a..3bfcb67 100644
--- 
a/juneau-examples/juneau-examples-rest-springboot/.settings/org.eclipse.jdt.core.prefs
+++ 
b/juneau-examples/juneau-examples-rest-springboot/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-examples/juneau-examples-rest/.settings/org.eclipse.jdt.core.prefs 
b/juneau-examples/juneau-examples-rest/.settings/org.eclipse.jdt.core.prefs
index 0721a8a..3bfcb67 100644
--- a/juneau-examples/juneau-examples-rest/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-examples/juneau-examples-rest/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-microservice/juneau-microservice-test/.settings/org.eclipse.jdt.core.prefs
 
b/juneau-microservice/juneau-microservice-test/.settings/org.eclipse.jdt.core.prefs
index 4b04196..bb79aba 100644
--- 
a/juneau-microservice/juneau-microservice-test/.settings/org.eclipse.jdt.core.prefs
+++ 
b/juneau-microservice/juneau-microservice-test/.settings/org.eclipse.jdt.core.prefs
@@ -1,6 +1,6 @@
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -10,6 +10,7 @@ org.eclipse.jdt.core.compiler.debug.sourceFile=generate
 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git a/juneau-releng/juneau-all/.project 
b/juneau-releng/juneau-all/.project
index 5ba7b4e..a9599a8 100644
--- a/juneau-releng/juneau-all/.project
+++ b/juneau-releng/juneau-all/.project
@@ -6,18 +6,12 @@
        </projects>
        <buildSpec>
                <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
                        <name>org.eclipse.m2e.core.maven2Builder</name>
                        <arguments>
                        </arguments>
                </buildCommand>
        </buildSpec>
        <natures>
-               <nature>org.eclipse.jdt.core.javanature</nature>
                <nature>org.eclipse.m2e.core.maven2Nature</nature>
        </natures>
 </projectDescription>
diff --git 
a/juneau-rest/juneau-rest-client/.settings/org.eclipse.jdt.core.prefs 
b/juneau-rest/juneau-rest-client/.settings/org.eclipse.jdt.core.prefs
index 1a5f6d5..dbc47bf 100644
--- a/juneau-rest/juneau-rest-client/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-rest/juneau-rest-client/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-rest/juneau-rest-server-jaxrs/.settings/org.eclipse.jdt.core.prefs 
b/juneau-rest/juneau-rest-server-jaxrs/.settings/org.eclipse.jdt.core.prefs
index 1a5f6d5..dbc47bf 100644
--- a/juneau-rest/juneau-rest-server-jaxrs/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-rest/juneau-rest-server-jaxrs/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-rest/juneau-rest-server/.settings/org.eclipse.jdt.core.prefs 
b/juneau-rest/juneau-rest-server/.settings/org.eclipse.jdt.core.prefs
index 1a5f6d5..dbc47bf 100644
--- a/juneau-rest/juneau-rest-server/.settings/org.eclipse.jdt.core.prefs
+++ b/juneau-rest/juneau-rest-server/.settings/org.eclipse.jdt.core.prefs
@@ -6,7 +6,7 @@ 
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
 
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=1.8
@@ -112,6 +112,7 @@ 
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
 org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
index bc54f8f..c033bf5 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
@@ -593,7 +593,7 @@ public class RestJavaMethod implements 
Comparable<RestJavaMethod>  {
                } catch (IllegalArgumentException e) {
                        throw new BadRequest(e,
                                "Invalid argument type passed to the following 
method: ''{0}''.\n\tArgument types: {1}",
-                               info.toString(), info.getReadableName()
+                               info.toString(), info.getFullName()
                        );
                } catch (InvocationTargetException e) {
                        Throwable e2 = e.getTargetException();          // Get 
the throwable thrown from the doX() method.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
index 8b76cb6..1097428 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
@@ -344,19 +344,19 @@ final class SwaggerGenerator {
                                        try {
                                                if (mpi != null) {
                                                        if (in == BODY) {
-                                                               for (Body a : 
mpi.getAnnotations(Body.class, true))
+                                                               for (Body a : 
mpi.getAnnotationsParentFirst(Body.class))
                                                                        
merge(param, a);
                                                        } else if (in == QUERY) 
{
-                                                               for (Query a : 
mpi.getAnnotations(Query.class, true))
+                                                               for (Query a : 
mpi.getAnnotationsParentFirst(Query.class))
                                                                        
merge(param, a);
                                                        } else if (in == 
FORM_DATA) {
-                                                               for (FormData a 
: mpi.getAnnotations(FormData.class, true))
+                                                               for (FormData a 
: mpi.getAnnotationsParentFirst(FormData.class))
                                                                        
merge(param, a);
                                                        } else if (in == 
HEADER) {
-                                                               for (Header a : 
mpi.getAnnotations(Header.class, true))
+                                                               for (Header a : 
mpi.getAnnotationsParentFirst(Header.class))
                                                                        
merge(param, a);
                                                        } else if (in == PATH) {
-                                                               for (Path a : 
mpi.getAnnotations(Path.class, true))
+                                                               for (Path a : 
mpi.getAnnotationsParentFirst(Path.class))
                                                                        
merge(param, a);
                                                        }
                                                }
@@ -410,7 +410,7 @@ final class SwaggerGenerator {
                        }
 
                        if (mi.hasAnnotation(Response.class)) {
-                               List<Response> la = 
mi.getAnnotations(Response.class, true);
+                               List<Response> la = 
mi.getAnnotationsParentFirst(Response.class);
                                Set<Integer> codes = getCodes(la, 200);
                                for (Response a : la) {
                                        for (Integer code : codes) {
@@ -448,7 +448,7 @@ final class SwaggerGenerator {
                                ParamInfo mpi = mp.getMethodParamInfo();
 
                                if (in == RESPONSE_HEADER) {
-                                       List<ResponseHeader> la = 
mpi.getAnnotations(ResponseHeader.class, true);
+                                       List<ResponseHeader> la = 
mpi.getAnnotationsParentFirst(ResponseHeader.class);
                                        Set<Integer> codes = getCodes2(la, 200);
                                        for (ResponseHeader a : la) {
                                                for (Integer code : codes) {
@@ -459,7 +459,7 @@ final class SwaggerGenerator {
                                        }
 
                                } else if (in == RESPONSE) {
-                                       List<Response> la = 
mpi.getAnnotations(Response.class, true);
+                                       List<Response> la = 
mpi.getAnnotationsParentFirst(Response.class);
                                        Set<Integer> codes = getCodes(la, 200);
                                        for (Response a : la) {
                                                for (Integer code : codes) {

Reply via email to