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


The following commit(s) were added to refs/heads/master by this push:
     new 8d87d4a  JUNEAU-197
8d87d4a is described below

commit 8d87d4aef6c67fc65fe21eb1b89ca61b3dc81e24
Author: JamesBognar <[email protected]>
AuthorDate: Tue Mar 10 17:59:53 2020 -0400

    JUNEAU-197
    
    @BeanConfig(bpi) does not override @Bean(bpi)
---
 .../apache/juneau/BeanConfigAnnotationTest.java    | 117 +++++++++++++++++----
 .../main/java/org/apache/juneau/ConfigApply.java   |  19 ++++
 .../org/apache/juneau/reflect/AnnotationInfo.java  |   4 +-
 juneau-doc/docs/ReleaseNotes/8.1.4.html            |  78 ++++++++++++++
 .../07.ConfigurableAnnotations.html                |  64 ++++++++++-
 5 files changed, 258 insertions(+), 24 deletions(-)

diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigAnnotationTest.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigAnnotationTest.java
index 2476542..af72ef2 100644
--- 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigAnnotationTest.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigAnnotationTest.java
@@ -309,7 +309,7 @@ public class BeanConfigAnnotationTest {
        // @BeanConfig(bpi/bpx) should override @Bean(bpi/bpx)
        
//-----------------------------------------------------------------------------------------------------------------
 
-       @BeanConfig(bpi="b,c,d", bpx="c")
+       @BeanConfig(bpi="D:b,c,d", bpx="D:c")
        @Bean(bpi="a,b,c", bpx="b")
        static class D {
                public int a, b, c, d;
@@ -326,25 +326,98 @@ public class BeanConfigAnnotationTest {
 
        private static ClassInfo d = ClassInfo.of(D.class);
 
-//     @Test
-//     public void beanBpiBpxCombined_noBeanConfig() throws Exception {
-//             String json = SimpleJson.DEFAULT.toString(D.create());
-//             assertEquals("{a:1,c:3}", json);
-//             D d = SimpleJson.DEFAULT.read(json, D.class);
-//             json = SimpleJson.DEFAULT.toString(d);
-//             assertEquals("{a:1,c:3}", json);
-//     }
-//
-//     @Test
-//     public void beanBpiBpxCombined_beanConfigOverride() throws Exception {
-//             AnnotationList al = c.getAnnotationListChildFirst(null);
-//             JsonSerializer js = 
JsonSerializer.create().simple().applyAnnotations(al, sr).build();
-//             JsonParser jp = JsonParser.create().applyAnnotations(al, 
sr).build();
-//
-//             String json = js.serialize(D.create());
-//             assertEquals("{b:2,d:4}", json);
-//             D d = jp.parse(json, D.class);
-//             json = js.serialize(d);
-//             assertEquals("{b:2,d:4}", json);
-//     }
+       @Test
+       public void beanBpiBpxCombined_noBeanConfig() throws Exception {
+               String json = SimpleJson.DEFAULT.toString(D.create());
+               assertEquals("{a:1,c:3}", json);
+               D d = SimpleJson.DEFAULT.read(json, D.class);
+               json = SimpleJson.DEFAULT.toString(d);
+               assertEquals("{a:1,c:3}", json);
+       }
+
+       @Test
+       public void beanBpiBpxCombined_beanConfigOverride() throws Exception {
+               AnnotationList al = d.getAnnotationList();
+               JsonSerializer js = 
JsonSerializer.create().simple().applyAnnotations(al, sr).build();
+               JsonParser jp = JsonParser.create().applyAnnotations(al, 
sr).build();
+
+               String json = js.serialize(D.create());
+               assertEquals("{b:2,d:4}", json);
+               D d = jp.parse(json, D.class);
+               json = js.serialize(d);
+               assertEquals("{b:2,d:4}", json);
+       }
+
+       @Test
+       public void beanBpiBpxCombined_beanContextBuilderOverride() throws 
Exception {
+               Bean ba = new BeanAnnotation("D").bpi("b,c,d").bpx("c");
+               JsonSerializer js = 
JsonSerializer.create().simple().annotations(ba).build();
+               JsonParser jp = JsonParser.create().annotations(ba).build();
+
+               String json = js.serialize(D.create());
+               assertEquals("{b:2,d:4}", json);
+               D d = jp.parse(json, D.class);
+               json = js.serialize(d);
+               assertEquals("{b:2,d:4}", json);
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // @BeanConfig(bpi/bpx) should override @Bean(bpi/bpx)
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Bean(bpi="a,b,c")
+       static class E1 {
+               public int a, b, c, d;
+       }
+
+       @BeanConfig(bpi="E:b,c,d", bpx="E:c")
+       @Bean(bpx="b")
+       static class E extends E1 {
+
+               public static E create() {
+                       E e = new E();
+                       e.a = 1;
+                       e.b = 2;
+                       e.c = 3;
+                       e.d = 4;
+                       return e;
+               }
+       }
+
+       private static ClassInfo e = ClassInfo.of(E.class);
+
+       @Test
+       public void beanBpiBpxCombined_multipleBeanAnnotations_noBeanConfig() 
throws Exception {
+               String json = SimpleJson.DEFAULT.toString(E.create());
+               assertEquals("{a:1,c:3}", json);
+               E e = SimpleJson.DEFAULT.read(json, E.class);
+               json = SimpleJson.DEFAULT.toString(e);
+               assertEquals("{a:1,c:3}", json);
+       }
+
+       @Test
+       public void 
beanBpiBpxCombined_multipleBeanAnnotations_beanConfigOverride() throws 
Exception {
+               AnnotationList al = e.getAnnotationList();
+               JsonSerializer js = 
JsonSerializer.create().simple().applyAnnotations(al, sr).build();
+               JsonParser jp = JsonParser.create().applyAnnotations(al, 
sr).build();
+
+               String json = js.serialize(E.create());
+               assertEquals("{b:2,d:4}", json);
+               E e = jp.parse(json, E.class);
+               json = js.serialize(e);
+               assertEquals("{b:2,d:4}", json);
+       }
+
+       @Test
+       public void 
beanBpiBpxCombined_multipleBeanAnnotations_beanContextBuilderOverride() throws 
Exception {
+               Bean ba = new BeanAnnotation("E").bpi("b,c,d").bpx("c");
+               JsonSerializer js = 
JsonSerializer.create().simple().annotations(ba).build();
+               JsonParser jp = JsonParser.create().annotations(ba).build();
+
+               String json = js.serialize(E.create());
+               assertEquals("{b:2,d:4}", json);
+               E e = jp.parse(json, E.class);
+               json = js.serialize(e);
+               assertEquals("{b:2,d:4}", json);
+       }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigApply.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigApply.java
index 8b79e52..b6876cf 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigApply.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigApply.java
@@ -173,4 +173,23 @@ public abstract class ConfigApply<T extends Annotation> {
                        throw new ConfigException("Invalid syntax for 
Simple-JSON on annotation @{0}({1}): {2}", c.getSimpleName(), loc, in);
                }
        }
+
+       /**
+        * Represents a no-op configuration apply.
+        */
+       public static class NoOp extends ConfigApply<Annotation> {
+
+               /**
+                * Constructor.
+                *
+                * @param c The annotation class.
+                * @param r The string resolver to use for resolving strings.
+                */
+               public NoOp(Class<Annotation> c, VarResolverSession r) {
+                       super(c, r);
+               }
+
+               @Override /* ConfigApply */
+               public void apply(AnnotationInfo<Annotation> a, 
PropertyStoreBuilder ps) {}
+       }
 }
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 4227828..6007a22 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
@@ -178,7 +178,9 @@ public class AnnotationInfo<T extends Annotation> {
                try {
                        if (configApplyConstructor == null) {
                                PropertyStoreApply psa = 
a.annotationType().getAnnotation(PropertyStoreApply.class);
-                               if (psa != null)
+                               if (psa == null)
+                                       configApplyConstructor = 
ConfigApply.NoOp.class.getConstructor(Class.class, VarResolverSession.class);
+                               else
                                        configApplyConstructor = (Constructor<? 
extends ConfigApply<?>>)psa.value().getConstructor(Class.class, 
VarResolverSession.class);
                                if (configApplyConstructor == null)
                                        throw new NoSuchFieldError("Could not 
find ConfigApply constructor for annotation:\n" + toString());
diff --git a/juneau-doc/docs/ReleaseNotes/8.1.4.html 
b/juneau-doc/docs/ReleaseNotes/8.1.4.html
index 479d397..279eaaf 100644
--- a/juneau-doc/docs/ReleaseNotes/8.1.4.html
+++ b/juneau-doc/docs/ReleaseNotes/8.1.4.html
@@ -32,6 +32,84 @@
        <li>
                The <ja>@Beanc</ja> annotation can now be recognized and used 
on non-public constructors.
        <li>
+               Annotations are now aggregated across the entire class 
hierarchy instead of simply being overridden.
+               <br>The following is an example.
+               <p class='bpcode w800'>
+       <jc>// Parent class with properties a,b,c</jc>
+       <ja>@Bean</ja>(bpi=<js>"a,b,c"</js>)
+       <jk>public class</jk> MyClass {
+               <jk>public int</jk> a, b, c, d;
+       }
+       
+       <jc>// New behavior:  Child class with properties a,c because @Beans 
are aggregated.</jc>
+       <jc>// Old behavior:  Child class with properties a,c,d because @Bean 
is overridden.</jc>
+       <ja>@Bean</ja>(bpx=<js>"b"</js>)
+       <jk>public class</jk> MyClass {
+               <jk>public int</jk> a, b, c, d;
+       }
+               </p>
+       <li>
+               Include/exclude/read-only/write-only properties defined on the 
bean context now override those defined on 
+               annotations of the class itself.  For example, the following 
methods override the {@link oaj.annotation.Bean @Bean} 
+               annotations on classes:
+               <ul class='javatree'>
+                       <li class='jc'>{@link oaj.BeanContextBuilder}
+                       <ul>
+                               <li class='jm'>{@link 
oaj.BeanContextBuilder#bpi(String) bpi(String)}
+                               <li class='jm'>{@link 
oaj.BeanContextBuilder#bpx(String) bpx(String)}
+                               <li class='jm'>{@link 
oaj.BeanContextBuilder#bpro(String) bpro(String)}
+                               <li class='jm'>{@link 
oaj.BeanContextBuilder#bpwo(String) bpwo(String}
+                       </ul>
+               </ul>
+       <li>
+               Config annotations now override class-level annotations.
+               <br>For example, only the 'a' and 'b' properties get serialized 
on the bean below:
+               <p class='bpcode w800'>
+       <jc>// Parent class with properties a,b,c</jc>
+       <ja>@Bean</ja>(bpi=<js>"a,b,c"</js>)
+       <jk>public class</jk> MyClass {
+               <jk>public int</jk> a, b, c, d;
+       }
+
+       <ja>@RestMethod</ja>
+       
<ja>@BeanConfig</ja>(beanApply={<ja>@Bean</ja>(on=<js>"MyClass"</js>,bpi=<js>"a,b"</js>)}
+       <jk>public</jk> MyClass getMyClass() {...}
+               </p>
+       <li>
+               The following concrete annotation implementation classes are 
now provided that can be used with the {@link 
oaj.BeanContextBuilder#annotations(Annotation)} method:
+               <ul class='javatree'>
+                       <li class'jc'>{@link oaj.annotation.BeanAnnotation} 
<jk>implements</jk> {@link oaj.annotation.BeanAnnotation}
+                       <li class'jc'>{@link oaj.annotation.BeancAnnotation} 
<jk>implements</jk> {@link oaj.annotation.BeancAnnotation}
+                       <li class'jc'>{@link 
oaj.annotation.BeanIgnoreAnnotation} <jk>implements</jk> {@link 
oaj.annotation.BeanIgnoreAnnotation}
+                       <li class'jc'>{@link oaj.annotation.BeanpAnnotation} 
<jk>implements</jk> {@link oaj.annotation.BeanpAnnotation}
+                       <li class'jc'>{@link oaj.annotation.ExampleAnnotation} 
<jk>implements</jk> {@link oaj.annotation.ExampleAnnotation}
+                       <li class'jc'>{@link 
oaj.annotation.NamePropertyAnnotation} <jk>implements</jk> {@link 
oaj.annotation.NamePropertyAnnotation}
+                       <li class'jc'>{@link 
oaj.annotation.ParentPropertyAnnotation} <jk>implements</jk> {@link 
oaj.annotation.ParentPropertyAnnotation}
+                       <li class'jc'>{@link oaj.annotation.SwapAnnotation} 
<jk>implements</jk> {@link oaj.annotation.SwapAnnotation}
+                       <li class'jc'>{@link oaj.annotation.UriAnnotation} 
<jk>implements</jk> {@link oaj.annotation.UriAnnotation}
+                       <li class'jc'>{@link oaj.csv.annotation.CsvAnnotation} 
<jk>implements</jk> {@link oaj.annotation.CsvAnnotation}
+                       <li class'jc'>{@link 
oaj.html.annotation.HtmlAnnotation} <jk>implements</jk> {@link 
oaj.annotation.HtmlAnnotation}
+                       <li class'jc'>{@link oaj.jso.annotation.JsoAnnotation} 
<jk>implements</jk> {@link oaj.annotation.JsoAnnotation}
+                       <li class'jc'>{@link 
oaj.json.annotation.JsonAnnotation} <jk>implements</jk> {@link 
oaj.annotation.JsonAnnotation}
+                       <li class'jc'>{@link 
oaj.jsonschema.annotation.SchemaAnnotation} <jk>implements</jk> {@link 
oaj.annotation.SchemaAnnotation}
+                       <li class'jc'>{@link 
oaj.msgpack.annotation.MsgPackAnnotation} <jk>implements</jk> {@link 
oaj.annotation.MsgPackAnnotation}
+                       <li class'jc'>{@link 
oaj.oapi.annotation.OpenApiAnnotation} <jk>implements</jk> {@link 
oaj.annotation.OpenApiAnnotation}
+                       <li class'jc'>{@link 
oaj.plaintext.annotation.PlainTextAnnotation} <jk>implements</jk> {@link 
oaj.annotation.PlainTextAnnotation}
+                       <li class'jc'>{@link 
oaj.soap.annotation.SoapXmlAnnotation} <jk>implements</jk> {@link 
oaj.annotation.SoapXmlAnnotation}
+                       <li class'jc'>{@link oaj.uon.annotation.UonAnnotation} 
<jk>implements</jk> {@link oaj.annotation.UonAnnotation}
+                       <li class'jc'>{@link 
oaj.urlencoding.annotation.UrlEncodingAnnotation} <jk>implements</jk> {@link 
oaj.annotation.UrlEncodingAnnotation}
+                       <li class'jc'>{@link oaj.xml.annotation.XmlAnnotation} 
<jk>implements</jk> {@link oaj.annotation.XmlAnnotation}
+               </ul>
+               <br>Example:
+               <p class='bpcode w800'>
+       <ja>@Bean</ja>(bpi=<js>"street,city"</js>) <jc>// Will be 
overridden</jc>
+       <jk>public class</jk> AddressBean {...}
+       
+       <ja>Bean</ja> ba = <jk>new</jk> 
BeanAnnotation(<js>"AddressBean"</js>).bpi(<js>"street,city,state"</js>);
+       WriterSerializer ws = 
JsonSerializer.<jsm>create</jsm>().annotations(ba).build();
+       String json = ws.toString(addressBean);  <jc>// Will print 
street,city,state</jc>
+               </p>
+       <li>
                Several bug fixes in the {@link HtmlSerializer} and {@link 
HtmlParser} classes around the handling of 
                collections and arrays of beans with 
<c><ja>@Bean</ja>(typeName)</c> annotations.
        <li>
diff --git 
a/juneau-doc/docs/Topics/02.juneau-marshall/07.ConfigurableAnnotations.html 
b/juneau-doc/docs/Topics/02.juneau-marshall/07.ConfigurableAnnotations.html
index ae63254..3cde6c4 100644
--- a/juneau-doc/docs/Topics/02.juneau-marshall/07.ConfigurableAnnotations.html
+++ b/juneau-doc/docs/Topics/02.juneau-marshall/07.ConfigurableAnnotations.html
@@ -13,7 +13,7 @@
  
***************************************************************************************************************************/
  -->
 
-{8.1.0-new, 8.1.3-updated} 
+{8.1.0-new, 8.1.3-updated, 8.1.4-updated} 
 Configurable Annotations
 
 <p>
@@ -103,6 +103,68 @@ Configurable Annotations
        String json = ws.toString(addressBean);
 </p>
 
+<p>
+       Annotations can also be applied directly to serializers and parsers 
using the following method: 
+</p>
+<ul class='javatree'>
+       <li class='jc'>{@link oaj.BeanContextBuilder}
+       <ul>
+               <li class='jm'>{@link 
oaj.BeanContextBuilder#annotations(Annotation...) annotations(Annotation...)} 
+       </ul>
+</ul>
+<p>
+       The following example shows a concrete implementation of an interface 
can be applied to a serializer:
+</p>
+<p class='bpcode w800'>
+       <jk>public class</jk> AddressBean {...}
+       
+       <ja>Bean</ja> ba = <jk>new</jk> 
BeanAnnotation(<js>"AddressBean"</js>).bpi(<js>"street,city,state"</js>);
+       WriterSerializer ws = 
JsonSerializer.<jsm>create</jsm>().annotations(ba).build();
+       String json = ws.toString(addressBean); <jc>// Will print 
street,city,state</jc>
+</p>
+
+<p>
+       The following concrete annotation implementation are provided:
+</p>
+<ul class='javatree'>
+       <li class'jc'>{@link org.apache.juneau.annotation.BeanAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.BeanAnnotation}
+       <li class'jc'>{@link org.apache.juneau.annotation.BeancAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.BeancAnnotation}
+       <li class'jc'>{@link org.apache.juneau.annotation.BeanIgnoreAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.BeanIgnoreAnnotation}
+       <li class'jc'>{@link org.apache.juneau.annotation.BeanpAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.BeanpAnnotation}
+       <li class'jc'>{@link org.apache.juneau.annotation.ExampleAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.ExampleAnnotation}
+       <li class'jc'>{@link 
org.apache.juneau.annotation.NamePropertyAnnotation} <jk>implements</jk> {@link 
org.apache.juneau.annotation.NamePropertyAnnotation}
+       <li class'jc'>{@link 
org.apache.juneau.annotation.ParentPropertyAnnotation} <jk>implements</jk> 
{@link org.apache.juneau.annotation.ParentPropertyAnnotation}
+       <li class'jc'>{@link org.apache.juneau.annotation.SwapAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.SwapAnnotation}
+       <li class'jc'>{@link org.apache.juneau.annotation.UriAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.UriAnnotation}
+       <li class'jc'>{@link org.apache.juneau.csv.annotation.CsvAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.CsvAnnotation}
+       <li class'jc'>{@link org.apache.juneau.html.annotation.HtmlAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.HtmlAnnotation}
+       <li class'jc'>{@link org.apache.juneau.jso.annotation.JsoAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.JsoAnnotation}
+       <li class'jc'>{@link org.apache.juneau.json.annotation.JsonAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.JsonAnnotation}
+       <li class'jc'>{@link 
org.apache.juneau.jsonschema.annotation.SchemaAnnotation} <jk>implements</jk> 
{@link org.apache.juneau.annotation.SchemaAnnotation}
+       <li class'jc'>{@link 
org.apache.juneau.msgpack.annotation.MsgPackAnnotation} <jk>implements</jk> 
{@link org.apache.juneau.annotation.MsgPackAnnotation}
+       <li class'jc'>{@link 
org.apache.juneau.oapi.annotation.OpenApiAnnotation} <jk>implements</jk> {@link 
org.apache.juneau.annotation.OpenApiAnnotation}
+       <li class'jc'>{@link 
org.apache.juneau.plaintext.annotation.PlainTextAnnotation} <jk>implements</jk> 
{@link org.apache.juneau.annotation.PlainTextAnnotation}
+       <li class'jc'>{@link 
org.apache.juneau.soap.annotation.SoapXmlAnnotation} <jk>implements</jk> {@link 
org.apache.juneau.annotation.SoapXmlAnnotation}
+       <li class'jc'>{@link org.apache.juneau.uon.annotation.UonAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.UonAnnotation}
+       <li class'jc'>{@link 
org.apache.juneau.urlencoding.annotation.UrlEncodingAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.UrlEncodingAnnotation}
+       <li class'jc'>{@link org.apache.juneau.xml.annotation.XmlAnnotation} 
<jk>implements</jk> {@link org.apache.juneau.annotation.XmlAnnotation}
+</ul>
+
+<p>
+       Any number of matching config or concrete annotations can be applied.  
They are applied in the order they are provided
+       to the context.  Therefore any values can be overridden.  Config and 
concrete annotations also override any class or method
+       level annotations 
+</p>
+
+<p class='bpcode w800'>
+       <ja>@Bean</ja>(bpi=<js>"street,city"</js>) <jc>// Will be 
overridden</jc>
+       <jk>public class</jk> AddressBean {...}
+       
+       <ja>Bean</ja> ba = <jk>new</jk> 
BeanAnnotation(<js>"AddressBean"</js>).bpi(<js>"street,city,state"</js>);
+       WriterSerializer ws = 
JsonSerializer.<jsm>create</jsm>().annotations(ba).build();
+       String json = ws.toString(addressBean);  <jc>// Will print 
street,city,state</jc>
+</p>
+
 <ul class='seealso'>
        <li class='doclink'>{@doc Glossaries.Annotations link} - Glossary of 
all annotations.
 </ul>

Reply via email to