JUNEAU-169 Dynamic annotations.
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanMapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanMapTest.java
index 9cbe297..1f45b27 100755
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanMapTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanMapTest.java
@@ -1858,6 +1858,60 @@
}
}
+ @Test
+ public void testHiddenProperties_usingConfig() throws Exception {
+ JsonSerializer s = SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(Uc.class).build();
+ BeanMeta bm = s.getBeanMeta(U.class);
+ assertNotNull(bm.getPropertyMeta("a"));
+ assertNotNull(bm.getPropertyMeta("b"));
+ assertNull(bm.getPropertyMeta("c"));
+ assertNull(bm.getPropertyMeta("d"));
+
+ Uc t = new Uc();
+ t.a = "a";
+ t.b = "b";
+ String r = s.serialize(t);
+ assertEquals("{a:'a',b:'b'}", r);
+
+ // Make sure setters are used if present.
+ t = JsonParser.DEFAULT.builder().applyAnnotations(Uc.class).build().parse(r, Uc.class);
+ assertEquals("b(setter)", t.b);
+ }
+
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="Uc.getB,Uc.c,Uc.getD,Uc.setD"))
+ public static class Uc {
+ public String a, b;
+
+ public String getA() {
+ return a;
+ }
+
+ public void setA(String a) {
+ this.a = a;
+ }
+
+ @BeanIgnore
+ public String getB() {
+ return b;
+ }
+
+ public void setB(String b) {
+ this.b = b+"(setter)";
+ }
+
+ @BeanIgnore
+ public String c;
+
+ @BeanIgnore
+ public String getD() {
+ return null;
+ }
+
+ @BeanIgnore
+ public void setD(String d) {
+ }
+ }
+
//====================================================================================================
// testBeanPropertyOrder
//====================================================================================================
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/annotation/BeanIgnoreTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/annotation/BeanIgnoreTest.java
index 97ae0f1..1893314 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/annotation/BeanIgnoreTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/annotation/BeanIgnoreTest.java
@@ -14,10 +14,15 @@
import static org.apache.juneau.testutils.TestUtils.*;
+import org.apache.juneau.json.*;
import org.junit.*;
public class BeanIgnoreTest {
+ //------------------------------------------------------------------------------------------------------------------
+ // Test @BeanIgnore on properties
+ //------------------------------------------------------------------------------------------------------------------
+
public static class A {
public String getA() {
return "a";
@@ -34,15 +39,39 @@
}
@Test
- public void test() throws Exception {
+ public void testBeanIgnoreOnProperties() throws Exception {
assertObjectEquals("{c:'c',a:'a'}", new A());
}
- @Test
- public void testBeanIgnoreOnBean() throws Exception {
- assertObjectEquals("{f2:2,f3:'xxx',f4:'xxx'}", new B());
+ @BeanConfig(
+ annotateBeanIgnore={
+ @BeanIgnore(on="Ac.getB"),
+ @BeanIgnore(on="Ac.d")
+ }
+ )
+ public static class Ac {
+ public String getA() {
+ return "a";
+ }
+
+ public String getB() {
+ return "b";
+ }
+
+ public String c = "c";
+
+ public String d = "d";
}
+ @Test
+ public void testBeanIgnoreOnProperties_usingConfig() throws Exception {
+ assertObjectEquals("{c:'c',a:'a'}", new Ac(), SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(Ac.class).build());
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Test @BeanIgnore on classes
+ //------------------------------------------------------------------------------------------------------------------
+
@BeanIgnore
public static class B1 {
public int f = 1;
@@ -61,5 +90,34 @@
return new B1();
}
}
+
+ @Test
+ public void testBeanIgnoreOnBean() throws Exception {
+ assertObjectEquals("{f2:2,f3:'xxx',f4:'xxx'}", new B());
+ }
+
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="B1c"))
+ public static class B1c {
+ public int f = 1;
+
+ @Override
+ public String toString() {
+ return "xxx";
+ }
+ }
+
+ public static class Bc {
+ public int f2 = 2;
+ public B1c f3 = new B1c();
+
+ public B1c getF4() {
+ return new B1c();
+ }
+ }
+
+ @Test
+ public void testBeanIgnoreOnBean_usingConfig() throws Exception {
+ assertObjectEquals("{f2:2,f3:'xxx',f4:'xxx'}", new Bc(), SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(B1c.class).build());
+ }
}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java
index 3655367..a5c51d7 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java
@@ -34,7 +34,15 @@
private static final ObjectList OBJECTLIST = new ObjectList().append("foo");
private static PojoSwap find(Class<?> c) {
- return AutoListSwap.find(ClassInfo.of(c));
+ return AutoListSwap.find(BeanContext.DEFAULT, ClassInfo.of(c));
+ }
+
+ private static PojoSwap find(BeanContext bc, Class<?> c) {
+ return AutoListSwap.find(bc, ClassInfo.of(c));
+ }
+
+ private static BeanContext bc(Class<?> applyAnnotations) {
+ return BeanContext.DEFAULT.builder().applyAnnotations(applyAnnotations).build();
}
//------------------------------------------------------------------------------------------------------------------
@@ -186,6 +194,30 @@
assertNull(find(D02.D02A.class));
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="D01c"))
+ public static class D01c {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+ public static class D02c {
+ public class D02Ac {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+ }
+
+ @Test
+ public void d03_ignoreClass_beanIgnore_usingConfig() throws Exception {
+ assertNull(find(bc(D01c.class), D01c.class));
+ }
+
+ @Test
+ public void d04_ignoreClass_memberClass_usingConfig() throws Exception {
+ assertNull(find(bc(D01c.class), D02c.D02Ac.class));
+ }
+
//------------------------------------------------------------------------------------------------------------------
// Ignore swap method
//------------------------------------------------------------------------------------------------------------------
@@ -196,6 +228,12 @@
return STRINGLIST;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="E01c.toList"))
+ public static class E01c {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
public static class E02 {
@Deprecated
public List<String> toList() {
@@ -224,6 +262,11 @@
}
@Test
+ public void e01c_ignoreSwapMethod_beanIgnore_usingConfig() throws Exception {
+ assertNull(find(BeanContext.DEFAULT.builder().applyAnnotations(E01c.class).build(), E01c.class));
+ }
+
+ @Test
public void e02_ignoreSwapMethod_deprecated() throws Exception {
assertNull(find(E02.class));
}
@@ -256,6 +299,15 @@
return null;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="F01c.create"))
+ public static class F01c {
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ public static F01c create(List<String> o) {
+ return null;
+ }
+ }
public static class F02 {
public List<String> toList() {
return STRINGLIST;
@@ -304,6 +356,11 @@
}
@Test(expected = ParseException.class)
+ public void f01c_ignoreUnswapMethod_beanIgnore_applyConfig() throws Exception {
+ find(bc(F01c.class), F01c.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
public void f02_ignoreUnswapMethod_deprecated() throws Exception {
find(F02.class).unswap(null, null, null);
}
@@ -340,6 +397,14 @@
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="G01c(List)"))
+ public static class G01c {
+ public G01c(List<String> o) {}
+ public List<String> toList() {
+ return STRINGLIST;
+ }
+ }
+
public static class G02 {
@Deprecated
public G02(List<String> o) {}
@@ -354,6 +419,11 @@
}
@Test(expected = ParseException.class)
+ public void g01c_ignoreUnswapConstructor_beanIgnore_usingConfig() throws Exception {
+ find(bc(G01c.class), G01c.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
find(G02.class).unswap(null, null, null);
}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java
index c32fa0f..2761e11 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java
@@ -34,7 +34,15 @@
private static final ObjectMap OBJECTMAP = new ObjectMap().append("foo","bar");
private static PojoSwap find(Class<?> c) {
- return AutoMapSwap.find(ClassInfo.of(c));
+ return AutoMapSwap.find(BeanContext.DEFAULT, ClassInfo.of(c));
+ }
+
+ private static PojoSwap find(BeanContext bc, Class<?> c) {
+ return AutoMapSwap.find(bc, ClassInfo.of(c));
+ }
+
+ private static BeanContext bc(Class<?> applyAnnotations) {
+ return BeanContext.DEFAULT.builder().applyAnnotations(applyAnnotations).build();
}
//------------------------------------------------------------------------------------------------------------------
@@ -168,6 +176,12 @@
return STRINGMAP;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="D01c"))
+ public static class D01c {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
public static class D02 {
public class D02A {
public Map<String,String> toMap() {
@@ -182,6 +196,11 @@
}
@Test
+ public void d01c_ignoreClass_beanIgnore_usingConfig() throws Exception {
+ assertNull(find(bc(D01c.class), D01c.class));
+ }
+
+ @Test
public void d02_ignoreClass_memberClass() throws Exception {
assertNull(find(D02.D02A.class));
}
@@ -196,6 +215,12 @@
return STRINGMAP;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="E01c.toMap"))
+ public static class E01c {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
public static class E02 {
@Deprecated
public Map<String,String> toMap() {
@@ -224,6 +249,11 @@
}
@Test
+ public void e01c_ignoreSwapMethod_beanIgnore_usingConfig() throws Exception {
+ assertNull(find(bc(E01c.class), E01c.class));
+ }
+
+ @Test
public void e02_ignoreSwapMethod_deprecated() throws Exception {
assertNull(find(E02.class));
}
@@ -256,6 +286,15 @@
return null;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="F01c.create(Map)"))
+ public static class F01c {
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ public static F01c create(Map<String,String> o) {
+ return null;
+ }
+ }
public static class F02 {
public Map<String,String> toMap() {
return STRINGMAP;
@@ -304,6 +343,11 @@
}
@Test(expected = ParseException.class)
+ public void f01c_ignoreUnswapMethod_beanIgnore_usingConfig() throws Exception {
+ find(bc(F01c.class), F01c.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
public void f02_ignoreUnswapMethod_deprecated() throws Exception {
find(F02.class).unswap(null, null, null);
}
@@ -340,6 +384,14 @@
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="G01c(Map)"))
+ public static class G01c {
+ public G01c(Map<String,String> o) {}
+ public Map<String,String> toMap() {
+ return STRINGMAP;
+ }
+ }
+
public static class G02 {
@Deprecated
public G02(Map<String,String> o) {}
@@ -354,6 +406,11 @@
}
@Test(expected = ParseException.class)
+ public void g01c_ignoreUnswapConstructor_beanIgnore_usingConfig() throws Exception {
+ find(bc(G01c.class), G01c.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
find(G02.class).unswap(null, null, null);
}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java
index 4415e78..099a644 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java
@@ -17,6 +17,7 @@
import java.util.*;
+import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.reflect.*;
@@ -29,7 +30,15 @@
public class AutoNumberSwapTest {
private static PojoSwap find(Class<?> c) {
- return AutoNumberSwap.find(ClassInfo.of(c));
+ return AutoNumberSwap.find(BeanContext.DEFAULT, ClassInfo.of(c));
+ }
+
+ private static PojoSwap find(BeanContext bc, Class<?> c) {
+ return AutoNumberSwap.find(bc, ClassInfo.of(c));
+ }
+
+ private static BeanContext bc(Class<?> applyAnnotations) {
+ return BeanContext.DEFAULT.builder().applyAnnotations(applyAnnotations).build();
}
//------------------------------------------------------------------------------------------------------------------
@@ -593,6 +602,12 @@
return 1;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="D01c"))
+ public static class D01c {
+ public Integer toInteger() {
+ return 1;
+ }
+ }
public static class D02 {
public class D02A {
public Integer toInteger() {
@@ -607,6 +622,11 @@
}
@Test
+ public void d01c_ignoreClass_beanIgnore_usingConfig() throws Exception {
+ assertNull(find(bc(D01c.class), D01c.class));
+ }
+
+ @Test
public void d02_ignoreClass_memberClass() throws Exception {
assertNull(find(D02.D02A.class));
}
@@ -633,6 +653,12 @@
return 1;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="E01c.toInteger"))
+ public static class E01c {
+ public Integer toInteger() {
+ return 1;
+ }
+ }
public static class E02 {
@Deprecated
public Integer toInteger() {
@@ -661,6 +687,11 @@
}
@Test
+ public void e01c_ignoreSwapMethod_beanIgnore_usingConfig() throws Exception {
+ assertNull(find(bc(E01c.class), E01c.class));
+ }
+
+ @Test
public void e02_ignoreSwapMethod_deprecated() throws Exception {
assertNull(find(E02.class));
}
@@ -693,6 +724,15 @@
return null;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="F01c.create(java.lang.Integer)"))
+ public static class F01c {
+ public Integer toInteger() {
+ return 1;
+ }
+ public static F01 create(Integer o) {
+ return null;
+ }
+ }
public static class F02 {
public Integer toInteger() {
return 1;
@@ -741,6 +781,11 @@
}
@Test(expected = ParseException.class)
+ public void f01c_ignoreUnswapMethod_beanIgnore_usingConfig() throws Exception {
+ find(bc(F01c.class), F01c.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
public void f02_ignoreUnswapMethod_deprecated() throws Exception {
find(F02.class).unswap(null, null, null);
}
@@ -777,6 +822,14 @@
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="G01c(java.lang.Integer)"))
+ public static class G01c {
+ public G01c(Integer o) {}
+ public Integer toInteger() {
+ return 1;
+ }
+ }
+
public static class G02 {
@Deprecated
public G02(Integer o) {}
@@ -791,6 +844,11 @@
}
@Test(expected = ParseException.class)
+ public void g01c_ignoreUnswapConstructor_beanIgnore_usingConfig() throws Exception {
+ find(bc(G01c.class), G01c.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
find(G02.class).unswap(null, null, null);
}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java
index a0eda02..6fa75d9 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java
@@ -35,7 +35,15 @@
private static final ObjectMap OBJECTMAP = new ObjectMap().append("foo","bar");
private static PojoSwap find(Class<?> c) {
- return AutoObjectSwap.find(ClassInfo.of(c));
+ return AutoObjectSwap.find(BeanContext.DEFAULT, ClassInfo.of(c));
+ }
+
+ private static PojoSwap find(BeanContext bc, Class<?> c) {
+ return AutoObjectSwap.find(bc, ClassInfo.of(c));
+ }
+
+ private static BeanContext bc(Class<?> applyAnnotations) {
+ return BeanContext.DEFAULT.builder().applyAnnotations(applyAnnotations).build();
}
//------------------------------------------------------------------------------------------------------------------
@@ -171,6 +179,12 @@
return STRINGMAP;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="D01c"))
+ public static class D01c {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
public static class D02 {
public class D02A {
public Map<String,String> swap() {
@@ -185,6 +199,11 @@
}
@Test
+ public void d01c_ignoreClass_beanIgnore_usingConfig() throws Exception {
+ assertNull(find(bc(D01c.class), D01c.class));
+ }
+
+ @Test
public void d02_ignoreClass_memberClass() throws Exception {
assertNull(find(D02.D02A.class));
}
@@ -199,6 +218,12 @@
return STRINGMAP;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="E01c.swap"))
+ public static class E01c {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
public static class E02 {
@Deprecated
public Map<String,String> swap() {
@@ -222,6 +247,11 @@
}
@Test
+ public void e01c_ignoreSwapMethod_beanIgnore_usingConfig() throws Exception {
+ assertNull(find(bc(E01c.class), E01c.class));
+ }
+
+ @Test
public void e02_ignoreSwapMethod_deprecated() throws Exception {
assertNull(find(E02.class));
}
@@ -249,6 +279,15 @@
return null;
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="F01c.create(java.util.Map)"))
+ public static class F01c {
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ public static F01 create(Map<String,String> o) {
+ return null;
+ }
+ }
public static class F02 {
public Map<String,String> swap() {
return STRINGMAP;
@@ -297,6 +336,11 @@
}
@Test(expected = ParseException.class)
+ public void f01c_ignoreUnswapMethod_beanIgnore_usingConfig() throws Exception {
+ find(bc(F01c.class), F01c.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
public void f02_ignoreUnswapMethod_deprecated() throws Exception {
find(F02.class).unswap(null, null, null);
}
@@ -333,6 +377,14 @@
}
}
+ @BeanConfig(annotateBeanIgnore=@BeanIgnore(on="G01c(Map)"))
+ public static class G01c {
+ public G01c(Map<String,String> o) {}
+ public Map<String,String> swap() {
+ return STRINGMAP;
+ }
+ }
+
public static class G02 {
@Deprecated
public G02(Map<String,String> o) {}
@@ -347,6 +399,11 @@
}
@Test(expected = ParseException.class)
+ public void g01c_ignoreUnswapConstructor_beanIgnore_usingConfig() throws Exception {
+ find(bc(G01c.class), G01c.class).unswap(null, null, null);
+ }
+
+ @Test(expected = ParseException.class)
public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
find(G02.class).unswap(null, null, null);
}
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 71cf6a1..3758c7a 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
@@ -205,7 +205,7 @@
if (! (cVis.isVisible(c.getModifiers()) || c.isAnonymousClass()))
return "Class is not public";
- if (c.isAnnotationPresent(BeanIgnore.class))
+ if (ctx.hasAnnotation(BeanIgnore.class, c))
return "Class is annotated with @BeanIgnore";
// Make sure it's serializable.
@@ -383,7 +383,7 @@
BeanPropertyMeta.Builder p = i.next();
try {
if (p.field == null)
- p.setInnerField(findInnerBeanField(c, stopClass, p.name));
+ p.setInnerField(findInnerBeanField(ctx, c, stopClass, p.name));
if (p.validate(ctx, beanRegistry, typeVarImpls, bpro, bpwo)) {
@@ -752,7 +752,7 @@
for (FieldInfo f : c2.getDeclaredFields()) {
if (f.isAny(STATIC, TRANSIENT))
continue;
- if (f.hasAnnotation(BeanIgnore.class))
+ if (ctx.hasAnnotation(BeanIgnore.class, f))
continue;
@SuppressWarnings("deprecation")
@@ -773,12 +773,12 @@
return l;
}
- static final Field findInnerBeanField(Class<?> c, Class<?> stopClass, String name) {
+ static final Field findInnerBeanField(BeanContext bc, Class<?> c, Class<?> stopClass, String name) {
for (ClassInfo c2 : findClasses(c, stopClass)) {
for (FieldInfo f : c2.getDeclaredFields()) {
if (f.isAny(STATIC, TRANSIENT))
continue;
- if (f.hasAnnotation(BeanIgnore.class))
+ if (f.hasAnnotation(BeanIgnore.class, bc))
continue;
if (f.hasName(name))
return f.inner();
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 c0cd6f4..9a3a7bf 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
@@ -458,13 +458,13 @@
}
for (FieldInfo f : ci.getAllFieldsParentFirst()) {
- if (f.hasAnnotation(ParentProperty.class)) {
+ if (bc.hasAnnotation(ParentProperty.class, f)) {
if (f.isStatic())
throw new ClassMetaRuntimeException(c, "@ParentProperty used on invalid field ''{0}''. Must be static.", f);
f.setAccessible();
parentPropertyMethod = new Setter.FieldSetter(f.inner());
}
- if (f.hasAnnotation(NameProperty.class)) {
+ if (bc.hasAnnotation(NameProperty.class, f)) {
if (f.isStatic())
throw new ClassMetaRuntimeException(c, "@NameProperty used on invalid field ''{0}''. Must be static.", f);
f.setAccessible();
@@ -473,7 +473,7 @@
}
for (FieldInfo f : ci.getDeclaredFields()) {
- if (f.hasAnnotation(Example.class)) {
+ if (bc.hasAnnotation(Example.class, f)) {
if (! (f.isStatic() && ci.isParentOf(f.getType().inner())))
throw new ClassMetaRuntimeException(c, "@Example used on invalid field ''{0}''. Must be static and an instance of the type.", f);
f.setAccessible();
@@ -483,13 +483,13 @@
// Find @NameProperty and @ParentProperty methods if present.
for (MethodInfo m : ci.getAllMethodsParentFirst()) {
- if (m.hasAnnotation(ParentProperty.class)) {
+ if (bc.hasAnnotation(ParentProperty.class, m)) {
if (m.isStatic() || ! m.hasNumParams(1))
throw new ClassMetaRuntimeException(c, "@ParentProperty used on invalid method ''{0}''. Must not be static and have one argument.", m);
m.setAccessible();
parentPropertyMethod = new Setter.MethodSetter(m.inner());
}
- if (m.hasAnnotation(NameProperty.class)) {
+ if (bc.hasAnnotation(NameProperty.class, m)) {
if (m.isStatic() || ! m.hasNumParams(1))
throw new ClassMetaRuntimeException(c, "@NameProperty used on invalid method ''{0}''. Must not be static and have one argument.", m);
m.setAccessible();
@@ -498,7 +498,7 @@
}
for (MethodInfo m : ci.getDeclaredMethods()) {
- if (m.hasAnnotation(Example.class)) {
+ if (bc.hasAnnotation(Example.class, m)) {
if (! (m.isStatic() && m.hasFuzzyParamTypes(BeanSession.class) && ci.isParentOf(m.getReturnType().inner())))
throw new ClassMetaRuntimeException(c, "@Example used on invalid method ''{0}''. Must be static and return an instance of the declaring class.", m);
m.setAccessible();
@@ -541,7 +541,7 @@
this.pojoSwaps.addAll(Arrays.asList(pojoSwaps));
if (bc != null)
- this.builderSwap = BuilderSwap.findSwapFromPojoClass(c, bc.getBeanConstructorVisibility(), bc.getBeanMethodVisibility());
+ this.builderSwap = BuilderSwap.findSwapFromPojoClass(bc, c, bc.getBeanConstructorVisibility(), bc.getBeanMethodVisibility());
findPojoSwaps(this.pojoSwaps, bc);
@@ -701,13 +701,13 @@
PojoSwap defaultSwap = DefaultSwaps.find(ci);
if (defaultSwap == null)
- defaultSwap = AutoObjectSwap.find(ci);
+ defaultSwap = AutoObjectSwap.find(bc, ci);
if (defaultSwap == null)
- defaultSwap = AutoNumberSwap.find(ci);
+ defaultSwap = AutoNumberSwap.find(bc, ci);
if (defaultSwap == null)
- defaultSwap = AutoMapSwap.find(ci);
+ defaultSwap = AutoMapSwap.find(bc, ci);
if (defaultSwap == null)
- defaultSwap = AutoListSwap.find(ci);
+ defaultSwap = AutoListSwap.find(bc, ci);
if (defaultSwap != null)
l.add(defaultSwap);
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Bean.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Bean.java
index 436291b..ac8f525 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Bean.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Bean.java
@@ -227,6 +227,51 @@
Class<?> interfaceClass() default Object.class;
/**
+ * Dynamically apply this annotation to the specified classes.
+ *
+ * <p>
+ * Used in conjunction with the {@link BeanConfig#annotateBean()}.
+ * It is ignored when the annotation is applied directly to classes.
+ *
+ * <p>
+ * The following example shows the equivalent methods for applying the {@link Bean @Bean} annotation to REST methods:
+ * <p class='bpcode w800'>
+ * <jc>// Class with explicit annotation.</jc>
+ * <ja>@Bean</ja>(bpi=<jk>"street,city,state"</js>)
+ * <jk>public class</jk> A {...}
+ *
+ * <jc>// Class with annotation applied via @BeanConfig</jc>
+ * <jk>public class</jk> B {...}
+ *
+ * <jc>// Java REST method with @BeanConfig annotation.</jc>
+ * <ja>@RestMethod</ja>(...)
+ * <ja>@BeanConfig</ja>(
+ * annotateBean={
+ * <ja>@Bean</ja>(on=<js>"B"</js>, bpi=<jk>"street,city,state"</js>)
+ * }
+ * )
+ * <jk>public void</jk> doFoo() {...}
+ * </p>
+ *
+ * The valid pattern matches are:
+ * <ul>
+ * <li>Classes:
+ * <ul>
+ * <li>Fully qualified: <js>"com.foo.MyClass"</js>
+ * <li>Fully qualified inner class: <js>"com.foo.MyClass$Inner1$Inner2"</js>
+ * <li>Simple: <js>"MyClass"</js>
+ * <li>Simple inner: <js>"MyClass$Inner1$Inner2"</js> or <js>"Inner1$Inner2"</js> or <js>"Inner2"</js>
+ * </ul>
+ * <li>A comma-delimited list of anything on this list.
+ * </ul>
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
+ String on() default "";
+
+ /**
* The set and order of names of properties associated with a bean class.
*
* @deprecated Use {@link #bpi()}
@@ -265,48 +310,6 @@
Class<? extends PropertyNamer> propertyNamer() default PropertyNamerDefault.class;
/**
- * Defines which classes/methods this annotation applies to.
- *
- * <p>
- * Used in conjunction with the {@link BeanConfig#annotateBean()}.
- * It is ignored when the annotation is applied directly to classes and methods.
- *
- * <p>
- * The following example shows the equivalent methods for applying the {@link Bean @Bean} annotation:
- * <p class='bpcode w800'>
- * <jc>// Class with explicit annotation.</jc>
- * <ja>@Bean</ja>(bpi=<jk>"street,city,state"</js>)
- * <jk>public class</jk> A {...}
- *
- * <jc>// Class with annotation applied via @BeanConfig</jc>
- * <jk>public class</jk> B {...}
- *
- * <jc>// Java REST method with @BeanConfig annotation.</jc>
- * <ja>@RestMethod</ja>(...)
- * <ja>@BeanConfig</ja>(
- * annotateBean={
- * <ja>@Bean</ja>(on=<js>"B"</js>, bpi=<jk>"street,city,state"</js>)
- * }
- * )
- * <jk>public void</jk> doFoo() {...}
- * </p>
- *
- * The format can be any of the following:
- * <ul>
- * <li>Full class name (e.g. <js>"com.foo.MyClass"</js>).
- * <li>Simple class name (e.g. <js>"MyClass"</js>).
- * <li>Full method name (e.g. <js>"com.foo.MyClass.myMethod"</js>).
- * <li>Simple method name (e.g. <js>"MyClass.myMethod"</js>).
- * <li>A comma-delimited list of anything on this list.
- * </ul>
- *
- * <ul class='seealso'>
- * <li class='link'>{@doc juneau-marshall.ClassMethodAnnotations}
- * </ul>
- */
- String on() default "";
-
- /**
* Sort bean properties in alphabetical order.
*
* <p>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfig.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfig.java
index edc06f9..3a59ac8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfig.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfig.java
@@ -50,45 +50,136 @@
//-----------------------------------------------------------------------------------------------------------------
/**
- * Indirectly applies {@link Bean @Bean} annotations to classes/methods.
+ * Dynamically applies {@link Bean @Bean} annotations to specified classes.
*
* <p>
- * Provides an alternate approach for applying annotations to classes/methods annotations using the {@link Bean#on() @Bean.on}
- * annotation to specify the class/method names to apply the annotation to.
+ * Provides an alternate approach for applying annotations using {@link Bean#on() @Bean.on} to specify the names
+ * to apply the annotation to.
*
* <ul class='seealso'>
- * <li class='link'>{@doc juneau-marshall.ClassMethodAnnotations}
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
* </ul>
*/
Bean[] annotateBean() default {};
/**
- * Indirectly applies {@link Beanc @Beanc} annotations to constructors.
+ * Dynamically applies {@link Beanc @Beanc} annotations to specified constructors.
*
* <p>
- * Provides an alternate approach for applying annotations to constructor annotations using the {@link Beanc#on() @Beanc.on}
- * annotation to specify the constructor names to apply the annotation to.
+ * Provides an alternate approach for applying annotations using {@link Beanc#on() @Beanc.on} to specify the names
+ * to apply the annotation to.
*
* <ul class='seealso'>
- * <li class='link'>{@doc juneau-marshall.ClassMethodAnnotations}
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
* </ul>
*/
Beanc[] annotateBeanc() default {};
/**
- * Indirectly applies {@link Beanp @Beanp} annotations to classes/methods.
+ * Dynamically applies {@link Beanp @Beanp} annotations to specified methods.
*
* <p>
- * Provides an alternate approach for applying annotations to classes/methods annotations using the {@link Beanp#on() @Beanp.on}
- * annotation to specify the class/method names to apply the annotation to.
+ * Provides an alternate approach for applying annotations using {@link Beanp#on() @Beanp.on} to specify the names
+ * to apply the annotation to.
*
* <ul class='seealso'>
- * <li class='link'>{@doc juneau-marshall.ClassMethodAnnotations}
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
* </ul>
*/
Beanp[] annotateBeanp() default {};
/**
+ * Dynamically applies {@link BeanIgnore @BeanIgnore} annotations to specified classes/methods/fields/constructors.
+ *
+ * <p>
+ * Provides an alternate approach for applying annotations using {@link BeanIgnore#on() @BeanIgnore.on} to specify the names
+ * to apply the annotation to.
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
+ BeanIgnore[] annotateBeanIgnore() default {};
+
+ /**
+ * Dynamically applies {@link Example @Example} annotations to specified classes/methods/fields.
+ *
+ * <p>
+ * Provides an alternate approach for applying annotations using {@link Example#on() @Example.on} to specify the names
+ * to apply the annotation to.
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
+ Example[] annotateExample() default {};
+
+ /**
+ * Dynamically applies {@link Name @Name} annotations to specified methods/fields.
+ *
+ * <p>
+ * Provides an alternate approach for applying annotations using {@link Name#on() @Name.on} to specify the names
+ * to apply the annotation to.
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
+ Name[] annotateName() default {};
+
+ /**
+ * Dynamically applies {@link NameProperty @NameProperty} annotations to specified methods/fields.
+ *
+ * <p>
+ * Provides an alternate approach for applying annotations using {@link NameProperty#on() @NameProperty.on} to specify the names
+ * to apply the annotation to.
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
+ NameProperty[] annotateNameProperty() default {};
+
+ /**
+ * Dynamically applies {@link ParentProperty @ParentProperty} annotations to specified methods/fields.
+ *
+ * <p>
+ * Provides an alternate approach for applying annotations using {@link ParentProperty#on() @ParentProperty.on} to specify the names
+ * to apply the annotation to.
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
+ ParentProperty[] annotateParentProperty() default {};
+
+ /**
+ * Dynamically applies {@link Swap @Swap} annotations to specified classes/methods/fields.
+ *
+ * <p>
+ * Provides an alternate approach for applying annotations using {@link Swap#on() @Swap.on} to specify the names
+ * to apply the annotation to.
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
+ Swap[] annotateSwap() default {};
+
+ /**
+ * Dynamically applies {@link URI @URI} annotations to specified classes/methods/fields.
+ *
+ * <p>
+ * Provides an alternate approach for applying annotations using {@link URI#on() @URI.on} to specify the names
+ * to apply the annotation to.
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
+ URI[] annotateURI() default {};
+
+ /**
* Configuration property: Minimum bean class visibility.
*
* <p>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfigApply.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfigApply.java
index 06be70e..c78993c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfigApply.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfigApply.java
@@ -172,6 +172,20 @@
psb.addTo(BEAN_annotations, a.annotateBeanp());
if (a.annotateBeanc().length > 0)
psb.addTo(BEAN_annotations, a.annotateBeanc());
+ if (a.annotateBeanIgnore().length > 0)
+ psb.addTo(BEAN_annotations, a.annotateBeanIgnore());
+ if (a.annotateExample().length > 0)
+ psb.addTo(BEAN_annotations, a.annotateExample());
+ if (a.annotateName().length > 0)
+ psb.addTo(BEAN_annotations, a.annotateName());
+ if (a.annotateNameProperty().length > 0)
+ psb.addTo(BEAN_annotations, a.annotateNameProperty());
+ if (a.annotateParentProperty().length > 0)
+ psb.addTo(BEAN_annotations, a.annotateParentProperty());
+ if (a.annotateURI().length > 0)
+ psb.addTo(BEAN_annotations, a.annotateURI());
+ if (a.annotateSwap().length > 0)
+ psb.addTo(BEAN_annotations, a.annotateSwap());
}
private Locale locale(String in) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
index f9caeb4..b01afbd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
@@ -40,6 +40,49 @@
@Retention(RUNTIME)
@Inherited
public @interface BeanIgnore {
+ /**
+ * Dynamically apply this annotation to the specified classes/methods/fields/constructors.
+ *
+ * <p>
+ * Used in conjunction with the {@link BeanConfig#annotateBeanIgnore()}.
+ * It is ignored when the annotation is applied directly to classes/methods/fields/constructors.
+ *
+ * The valid pattern matches are:
+ * <ul>
+ * <li>Classes:
+ * <ul>
+ * <li>Fully qualified: <js>"com.foo.MyClass"</js>
+ * <li>Fully qualified inner class: <js>"com.foo.MyClass$Inner1$Inner2"</js>
+ * <li>Simple: <js>"MyClass"</js>
+ * <li>Simple inner: <js>"MyClass$Inner1$Inner2"</js> or <js>"Inner1$Inner2"</js> or <js>"Inner2"</js>
+ * </ul>
+ * <li>Methods:
+ * <ul>
+ * <li>Fully qualified with args: <js>"com.foo.MyClass.myMethod(String,int)"</js> or <js>"com.foo.MyClass.myMethod(java.lang.String,int)"</js> or <js>"com.foo.MyClass.myMethod()"</js>
+ * <li>Fully qualified: <js>"com.foo.MyClass.myMethod"</js>
+ * <li>Simple with args: <js>"MyClass.myMethod(String,int)"</js> or <js>"MyClass.myMethod(java.lang.String,int)"</js> or <js>"MyClass.myMethod()"</js>
+ * <li>Simple: <js>"MyClass.myMethod"</js>
+ * <li>Simple inner class: <js>"MyClass$Inner1$Inner2.myMethod"</js> or <js>"Inner1$Inner2.myMethod"</js> or <js>"Inner2.myMethod"</js>
+ * </ul>
+ * <li>Fields:
+ * <ul>
+ * <li>Fully qualified: <js>"com.foo.MyClass.myField"</js>
+ * <li>Simple: <js>"MyClass.muyField"</js>
+ * <li>Simple inner class: <js>"MyClass$Inner1$Inner2.myField"</js> or <js>"Inner1$Inner2.myField"</js> or <js>"Inner2.myField"</js>
+ * </ul>
+ * <li>Constructors:
+ * <ul>
+ * <li>Fully qualified with args: <js>"com.foo.MyClass(String,int)"</js> or <js>"com.foo.MyClass(java.lang.String,int)"</js> or <js>"com.foo.MyClass()"</js>
+ * <li>Simple with args: <js>"MyClass(String,int)"</js> or <js>"MyClass(java.lang.String,int)"</js> or <js>"MyClass()"</js>
+ * <li>Simple inner class: <js>"MyClass$Inner1$Inner2()"</js> or <js>"Inner1$Inner2()"</js> or <js>"Inner2()"</js>
+ * </ul>
+ * <li>A comma-delimited list of anything on this list.
+ * </ul>
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
String on() default "";
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Beanc.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Beanc.java
index 2e4a65b..bec5ca5 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Beanc.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Beanc.java
@@ -52,20 +52,78 @@
@Inherited
public @interface Beanc {
+ /**
+ * Dynamically apply this annotation to the specified constructors.
+ *
+ * <p>
+ * Used in conjunction with the {@link BeanConfig#annotateBeanc()}.
+ * It is ignored when the annotation is applied directly to constructors.
+ *
+ * <p>
+ * The following example shows this annotation in use:
+ * <p class='bpcode w800'>
+ * <jc>// Our read-only bean.</jc>
+ * <jk>public class</jk> Person {
+ * <jk>private final</jk> String <jf>name</jf>;
+ * <jk>private final int</jk> <jf>age</jf>;
+ *
+ * <jk>public</jk> Person(String name, <jk>int</jk> age) {
+ * <jk>this</jk>.<jf>name</jf> = name;
+ * <jk>this</jk>.<jf>age</jf> = age;
+ * }
+ *
+ * <jc>// Read only properties.</jc>
+ * <jc>// Getters, but no setters.</jc>
+ *
+ * <jk>public</jk> String getName() {
+ * <jk>return</jk> <jf>name</jf>;
+ * }
+ *
+ * <jk>public int</jk> getAge() {
+ * <jk>return</jk> <jf>age</jf>;
+ * }
+ * }
+ *
+ * <ja>@BeanConfig</ja>(annotateBeanc=<ja>@Beanc</ja>(on="Person(String,int)", properties=<js>"name,age"</js>))
+ * public static class X {}
+ * </p>
+ * <p class='bpcode w800'>
+ * <jc>// Parsing into a read-only bean.</jc>
+ * String json = <js>"{name:'John Smith',age:45}"</js>;
+ * Person p = JsonParser.<jsf>DEFAULT</jsf>.builder().applyAnnotations(X.<jk>class</jk>).build().parse(json);
+ * String name = p.getName(); <jc>// "John Smith"</jc>
+ * <jk>int</jk> age = p.getAge(); <jc>// 45</jc>
+ * </p>
+ *
+ * The valid pattern matches are:
+ * <ul>
+ * <li>Constructors:
+ * <ul>
+ * <li>Fully qualified with args: <js>"com.foo.MyClass(String,int)"</js> or <js>"com.foo.MyClass(java.lang.String,int)"</js> or <js>"com.foo.MyClass()"</js>
+ * <li>Simple with args: <js>"MyClass(String,int)"</js> or <js>"MyClass(java.lang.String,int)"</js> or <js>"MyClass()"</js>
+ * <li>Simple inner class: <js>"MyClass$Inner1$Inner2()"</js> or <js>"Inner1$Inner2()"</js> or <js>"Inner2()"</js>
+ * </ul>
+ * <li>A comma-delimited list of anything on this list.
+ * </ul>
+ *
+ * <ul class='seealso'>
+ * <li class='link'>{@doc juneau-marshall.DynamicallyAppliedAnnotations}
+ * </ul>
+ */
String on() default "";
/**
* The names of the properties of the constructor arguments.
+ *
* <p>
- * The {@link org.apache.juneau.annotation.Beanc @Beanc} 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
- * 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 class='bpcode w800'>
+ * The {@link org.apache.juneau.annotation.Beanc @Beanc} 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 them so that
+ * they are available at runtime.
+ *
+ * <p>
+ * The definition of a read-only bean is a bean with properties with only getters, like shown below:
+ * <p class='bpcode w800'>
* <jc>// Our read-only bean.</jc>
* <jk>public class</jk> Person {
* <jk>private final</jk> String <jf>name</jf>;
@@ -88,14 +146,14 @@
* <jk>return</jk> <jf>age</jf>;
* }
* }
- * </p>
- * <p class='bpcode w800'>
+ * </p>
+ * <p class='bpcode w800'>
* <jc>// Parsing into a read-only bean.</jc>
* String json = <js>"{name:'John Smith',age:45}"</js>;
* Person p = JsonParser.<jsf>DEFAULT</jsf>.parse(json);
* String name = p.getName(); <jc>// "John Smith"</jc>
* <jk>int</jk> age = p.getAge(); <jc>// 45</jc>
- * </p>
+ * </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
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swap.java
index 4c44af8..b02edc1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swap.java
@@ -40,6 +40,8 @@
@Inherited
public @interface Swap {
+ String on() default "";
+
/**
* The {@link PojoSwap} and {@link Surrogate} class.
*
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 3a39b0a..9cce182 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
@@ -122,6 +122,17 @@
return f.isAnnotationPresent(a);
}
+ /**
+ * Returns <jk>true</jk> if the specified annotation is present.
+ *
+ * @param a The annotation to check for.
+ * @param mp The meta provider for looking up annotations on reflection objects (classes, methods, fields, constructors).
+ * @return <jk>true</jk> if the specified annotation is present.
+ */
+ public boolean hasAnnotation(Class<? extends Annotation> a, MetaProvider mp) {
+ return mp.getAnnotation(a, f) != null;
+ }
+
//-----------------------------------------------------------------------------------------------------------------
// Characteristics
//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
index 2602c4f..23d06c1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
@@ -82,27 +82,28 @@
/**
* Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
*
+ * @param bc The bean context to use for looking up annotations.
* @param ci The class to try to constructor a dynamic swap on.
* @return A POJO swap instance, or <jk>null</jk> if one could not be created.
*/
@SuppressWarnings({ "rawtypes" })
- public static PojoSwap<?,?> find(ClassInfo ci) {
+ public static PojoSwap<?,?> find(BeanContext bc, ClassInfo ci) {
- if (shouldIgnore(ci))
+ if (shouldIgnore(bc, ci))
return null;
// Find swap() method if present.
for (MethodInfo m : ci.getPublicMethods()) {
- if (isSwapMethod(m)) {
+ if (isSwapMethod(bc, m)) {
ClassInfo rt = m.getReturnType();
for (MethodInfo m2 : ci.getPublicMethods())
- if (isUnswapMethod(m2, ci, rt))
+ if (isUnswapMethod(bc, m2, ci, rt))
return new AutoListSwap(ci, m, m2, null);
for (ConstructorInfo cs : ci.getPublicConstructors())
- if (isUnswapConstructor(cs, rt))
+ if (isUnswapConstructor(bc, cs, rt))
return new AutoListSwap(ci, m, null, cs);
return new AutoListSwap(ci, m, null, null);
@@ -112,37 +113,37 @@
return null;
}
- private static boolean shouldIgnore(ClassInfo ci) {
+ private static boolean shouldIgnore(BeanContext bc, ClassInfo ci) {
return
- ci.hasAnnotation(BeanIgnore.class)
+ bc.hasAnnotation(BeanIgnore.class, ci)
|| ci.isNonStaticMemberClass();
}
- private static boolean isSwapMethod(MethodInfo mi) {
+ private static boolean isSwapMethod(BeanContext bc, MethodInfo mi) {
return
mi.isNotDeprecated()
&& mi.isNotStatic()
&& mi.hasName(SWAP_METHOD_NAMES)
&& mi.hasReturnTypeParent(List.class)
&& mi.hasFuzzyParamTypes(BeanSession.class)
- && ! mi.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, mi);
}
- private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+ private static boolean isUnswapMethod(BeanContext bc, MethodInfo mi, ClassInfo ci, ClassInfo rt) {
return
mi.isNotDeprecated()
&& mi.isStatic()
&& mi.hasName(UNSWAP_METHOD_NAMES)
&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
&& mi.hasReturnTypeParent(ci)
- && ! mi.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, mi);
}
- private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+ private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) {
return
cs.isNotDeprecated()
&& cs.hasParamTypeParents(rt)
- && ! cs.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, cs);
}
//------------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
index 53dace1..ba1b813 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
@@ -82,27 +82,28 @@
/**
* Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
*
+ * @param bc The bean context to use for looking up annotations.
* @param ci The class to try to constructor a dynamic swap on.
* @return A POJO swap instance, or <jk>null</jk> if one could not be created.
*/
@SuppressWarnings({ "rawtypes" })
- public static PojoSwap<?,?> find(ClassInfo ci) {
+ public static PojoSwap<?,?> find(BeanContext bc, ClassInfo ci) {
- if (shouldIgnore(ci))
+ if (shouldIgnore(bc, ci))
return null;
// Find swap() method if present.
for (MethodInfo m : ci.getPublicMethods()) {
- if (isSwapMethod(m)) {
+ if (isSwapMethod(bc, m)) {
ClassInfo rt = m.getReturnType();
for (MethodInfo m2 : ci.getPublicMethods())
- if (isUnswapMethod(m2, ci, rt))
+ if (isUnswapMethod(bc, m2, ci, rt))
return new AutoMapSwap(ci, m, m2, null);
for (ConstructorInfo cs : ci.getPublicConstructors())
- if (isUnswapConstructor(cs, rt))
+ if (isUnswapConstructor(bc, cs, rt))
return new AutoMapSwap(ci, m, null, cs);
return new AutoMapSwap(ci, m, null, null);
@@ -112,37 +113,37 @@
return null;
}
- private static boolean shouldIgnore(ClassInfo ci) {
+ private static boolean shouldIgnore(BeanContext bc, ClassInfo ci) {
return
- ci.hasAnnotation(BeanIgnore.class)
+ bc.hasAnnotation(BeanIgnore.class, ci)
|| ci.isNonStaticMemberClass();
}
- private static boolean isSwapMethod(MethodInfo mi) {
+ private static boolean isSwapMethod(BeanContext bc, MethodInfo mi) {
return
mi.isNotDeprecated()
&& mi.isNotStatic()
&& mi.hasName(SWAP_METHOD_NAMES)
&& mi.hasReturnTypeParent(Map.class)
&& mi.hasFuzzyParamTypes(BeanSession.class)
- && ! mi.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, mi);
}
- private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+ private static boolean isUnswapMethod(BeanContext bc, MethodInfo mi, ClassInfo ci, ClassInfo rt) {
return
mi.isNotDeprecated()
&& mi.isStatic()
&& mi.hasName(UNSWAP_METHOD_NAMES)
&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
&& mi.hasReturnTypeParent(ci)
- && ! mi.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, mi);
}
- private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+ private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) {
return
cs.isNotDeprecated()
&& cs.hasParamTypeParents(rt)
- && ! cs.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, cs);
}
//------------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
index 80ae1cc..ebb89d6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
@@ -105,27 +105,28 @@
/**
* Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
*
+ * @param bc The bean context to use for looking up annotations.
* @param ci The class to try to constructor a dynamic swap on.
* @return A POJO swap instance, or <jk>null</jk> if one could not be created.
*/
@SuppressWarnings({ "rawtypes" })
- public static PojoSwap<?,?> find(ClassInfo ci) {
+ public static PojoSwap<?,?> find(BeanContext bc, ClassInfo ci) {
- if (shouldIgnore(ci))
+ if (shouldIgnore(bc, ci))
return null;
// Find swap() method if present.
for (MethodInfo m : ci.getPublicMethods()) {
- if (isSwapMethod(m)) {
+ if (isSwapMethod(bc, m)) {
ClassInfo rt = m.getReturnType();
for (MethodInfo m2 : ci.getPublicMethods())
- if (isUnswapMethod(m2, ci, rt))
+ if (isUnswapMethod(bc, m2, ci, rt))
return new AutoNumberSwap(ci, m, m2, null);
for (ConstructorInfo cs : ci.getPublicConstructors())
- if (isUnswapConstructor(cs, rt))
+ if (isUnswapConstructor(bc, cs, rt))
return new AutoNumberSwap(ci, m, null, cs);
return new AutoNumberSwap(ci, m, null, null);
@@ -135,15 +136,15 @@
return null;
}
- private static boolean shouldIgnore(ClassInfo ci) {
+ private static boolean shouldIgnore(BeanContext bc, ClassInfo ci) {
return
- ci.hasAnnotation(BeanIgnore.class)
+ bc.hasAnnotation(BeanIgnore.class, ci)
|| ci.isNonStaticMemberClass()
|| ci.isPrimitive()
|| ci.isChildOf(Number.class);
}
- private static boolean isSwapMethod(MethodInfo mi) {
+ private static boolean isSwapMethod(BeanContext bc, MethodInfo mi) {
ClassInfo rt = mi.getReturnType();
return
mi.isNotDeprecated()
@@ -151,24 +152,24 @@
&& (rt.isChildOf(Number.class) || (rt.isPrimitive() && rt.isAny(int.class, short.class, long.class, float.class, double.class, byte.class)))
&& mi.hasName(SWAP_METHOD_NAMES)
&& mi.hasFuzzyParamTypes(BeanSession.class)
- && ! mi.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, mi);
}
- private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+ private static boolean isUnswapMethod(BeanContext bc, MethodInfo mi, ClassInfo ci, ClassInfo rt) {
return
mi.isNotDeprecated()
&& mi.isStatic()
&& mi.hasName(UNSWAP_METHOD_NAMES)
&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
&& mi.hasReturnTypeParent(ci)
- && ! mi.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, mi);
}
- private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+ private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) {
return
cs.isNotDeprecated()
&& cs.hasParamTypeParents(rt)
- && ! cs.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, cs);
}
//------------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
index a55f700..aea43c4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
@@ -84,27 +84,28 @@
/**
* Inspects the specified class and returns a swap of this type if possible.
*
+ * @param bc The bean context to use for looking up annotations.
* @param ci The class to return a swap on.
* @return A POJO swap instance, or <jk>null</jk> if one could not be created.
*/
@SuppressWarnings({ "rawtypes" })
- public static PojoSwap<?,?> find(ClassInfo ci) {
+ public static PojoSwap<?,?> find(BeanContext bc, ClassInfo ci) {
- if (shouldIgnore(ci))
+ if (shouldIgnore(bc, ci))
return null;
// Find swap() method if present.
for (MethodInfo m : ci.getPublicMethods()) {
- if (isSwapMethod(m)) {
+ if (isSwapMethod(bc, m)) {
ClassInfo rt = m.getReturnType();
for (MethodInfo m2 : ci.getPublicMethods())
- if (isUnswapMethod(m2, ci, rt))
+ if (isUnswapMethod(bc, m2, ci, rt))
return new AutoObjectSwap(ci, m, m2, null);
for (ConstructorInfo cs : ci.getPublicConstructors())
- if (isUnswapConstructor(cs, rt))
+ if (isUnswapConstructor(bc, cs, rt))
return new AutoObjectSwap(ci, m, null, cs);
return new AutoObjectSwap(ci, m, null, null);
@@ -114,36 +115,36 @@
return null;
}
- private static boolean shouldIgnore(ClassInfo ci) {
+ private static boolean shouldIgnore(BeanContext bc, ClassInfo ci) {
return
- ci.hasAnnotation(BeanIgnore.class)
+ bc.hasAnnotation(BeanIgnore.class, ci)
|| ci.isNonStaticMemberClass();
}
- private static boolean isSwapMethod(MethodInfo mi) {
+ private static boolean isSwapMethod(BeanContext bc, MethodInfo mi) {
return
mi.isNotDeprecated()
&& mi.isNotStatic()
&& mi.hasName(SWAP_METHOD_NAMES)
&& mi.hasFuzzyParamTypes(BeanSession.class)
- && ! mi.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, mi);
}
- private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+ private static boolean isUnswapMethod(BeanContext bc, MethodInfo mi, ClassInfo ci, ClassInfo rt) {
return
mi.isNotDeprecated()
&& mi.isStatic()
&& mi.hasName(UNSWAP_METHOD_NAMES)
&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
&& mi.hasReturnTypeParent(ci)
- && ! mi.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, mi);
}
- private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+ private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) {
return
cs.isNotDeprecated()
&& cs.hasParamTypeParents(rt)
- && ! cs.hasAnnotation(BeanIgnore.class);
+ && ! bc.hasAnnotation(BeanIgnore.class, cs);
}
//------------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BuilderSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BuilderSwap.java
index 35c0674..d6269c2 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BuilderSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BuilderSwap.java
@@ -175,19 +175,20 @@
/**
* Creates a BuilderSwap from the specified POJO class if it has one.
*
+ * @param bc The bean context to use to look up annotations.
* @param pojoClass The POJO class to check.
* @param cVis Minimum constructor visibility.
* @param mVis Minimum method visibility.
* @return A new swap instance, or <jk>null</jk> if class didn't have a builder class.
*/
@SuppressWarnings("rawtypes")
- public static BuilderSwap<?,?> findSwapFromPojoClass(Class<?> pojoClass, Visibility cVis, Visibility mVis) {
+ public static BuilderSwap<?,?> findSwapFromPojoClass(BeanContext bc, Class<?> pojoClass, Visibility cVis, Visibility mVis) {
Class<?> builderClass = null;
MethodInfo pojoCreateMethod, builderCreateMethod;
ConstructorInfo pojoConstructor = null;
ConstructorInfo builderConstructor;
- org.apache.juneau.annotation.Builder b = pojoClass.getAnnotation(org.apache.juneau.annotation.Builder.class);
+ org.apache.juneau.annotation.Builder b = bc.getAnnotation(org.apache.juneau.annotation.Builder.class, pojoClass);
if (b != null && b.value() != Null.class)
builderClass = b.value();
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
index 4b803b9..d0bbc17 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ReflectionMap.java
@@ -52,9 +52,9 @@
* <li>Simple with args: <js>"MyClass(String,int)"</js> or <js>"MyClass(java.lang.String,int)"</js> or <js>"MyClass()"</js>
* <li>Simple inner class: <js>"MyClass$Inner1$Inner2()"</js> or <js>"Inner1$Inner2()"</js> or <js>"Inner2()"</js>
* </ul>
+ * <li>A comma-delimited list of anything on this list.
* </ul>
*
- *
* @param <V> The type of object in this map.
*/
public class ReflectionMap<V> {