{8.1.3-new} Dynamically Applied Annotations

In the section {@doc juneau-marshall.Transforms}, you were introduced to annotations that can be applied to bean classes, methods, fields, and constructors such as {@link oaj.annotation.Bean @Bean}:

// Address class with only street/city/state properties (in that order). // All other properties are ignored. @Bean(bpi="street,city,state") public class Address { ... }

An alternate way of applying these annotations is using the @XConfig annotations introduced in section {@doc juneau-marshall.ConfigurableAnnotations}.

// Unannotated class. public class Address { ... } @BeanConfig( applyBean={ @Bean(on="Address", bpi="AddressBean: street,city,state") } } public static class DummyClass {} WriterSerializer ws = JsonSerializer.create().applyAnnotations(DummyClass.class).build(); String json = ws.toString(addressBean);

The advantage to this approach is it allows you to use Juneau annotations on classes/methods/fields/constructors where you might not have access to the source code, or when you only want to selectively apply the annotation under certain scenarios instead of globally.

For example, the following shows the @Bean annotation being selectively applied on a single REST method (described later in {@doc juneau-rest-server}):

@RestMethod @BeanConfig( applyBean={ @Bean(on="Address", bpi="AddressBean: street,city,state") } } public List<Address> getAddresses() {}

Any Juneau annotation that has an on() method can be applied dynamically this way. These include:

- {@link oaj.annotation.Bean}
- {@link oaj.annotation.Beanc}
- {@link oaj.annotation.BeanIgnore}
- {@link oaj.annotation.Beanp}
- {@link oaj.annotation.Example}
- {@link oaj.annotation.NameProperty}
- {@link oaj.annotation.ParentProperty}
- {@link oaj.annotation.Swap}
- {@link oaj.annotation.URI}
- {@link oaj.csv.annotation.Csv}
- {@link oaj.html.annotation.Html}
- {@link oaj.jso.annotation.Jso}
- {@link oaj.json.annotation.Json}
- {@link oaj.jsonschema.annotation.Schema}
- {@link oaj.msgpack.annotation.MsgPack}
- {@link oaj.oapi.annotation.OpenApi}
- {@link oaj.plaintext.annotation.PlainText}
- {@link oaj.soap.annotation.SoapXml}
- {@link oaj.uon.annotation.Uon}
- {@link oaj.urlencoding.annotation.UrlEncoding}
- {@link oaj.xml.annotation.Xml}
- {@link oaj.jena.annotation.Rdf}

The valid pattern matches are:

- Classes:
  - Fully qualified:
    - "com.foo.MyClass"
  - Fully qualified inner class:
    - "com.foo.MyClass$Inner1$Inner2"
  - Simple:
    - "MyClass"
  - Simple inner:
    - "MyClass$Inner1$Inner2"
    - "Inner1$Inner2"
    - "Inner2"
- Methods:
  - Fully qualified with args:
    - "com.foo.MyClass.myMethod(String,int)"
    - "com.foo.MyClass.myMethod(java.lang.String,int)"
    - "com.foo.MyClass.myMethod()"
  - Fully qualified:
    - "com.foo.MyClass.myMethod"
  - Simple with args:
    - "MyClass.myMethod(String,int)"
    - "MyClass.myMethod(java.lang.String,int)"
    - "MyClass.myMethod()"
  - Simple:
    - "MyClass.myMethod"
  - Simple inner class:
    - "MyClass$Inner1$Inner2.myMethod"
    - "Inner1$Inner2.myMethod"
    - "Inner2.myMethod"
- Fields:
  - Fully qualified:
    - "com.foo.MyClass.myField"
  - Simple:
    - "MyClass.myField"
  - Simple inner class:
    - "MyClass$Inner1$Inner2.myField"
    - "Inner1$Inner2.myField"
    - "Inner2.myField"
- Constructors:
  - Fully qualified with args:
    - "com.foo.MyClass(String,int)"
    - "com.foo.MyClass(java.lang.String,int)"
    - "com.foo.MyClass()"
  - Simple with args:
    - "MyClass(String,int)"
    - "MyClass(java.lang.String,int)"
    - "MyClass()"
  - Simple inner class:
    - "MyClass$Inner1$Inner2()"
    - "Inner1$Inner2()"
    - "Inner2()"
- A comma-delimited list of anything on this list.