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>