{updated} @BeanProperty Annotation

The {@link oaj.annotation.BeanProperty @BeanProperty} annotation is used to tailor how individual bean properties are interpreted by the framework.

The {@link oaj.annotation.BeanProperty#name() @BeanProperty(name)} annotation is used to override the name of the bean property.

public class MyBean { @BeanProperty(name="Bar") public String getFoo() {...} }

The {@link oaj.annotation.Name @Name} annotation is a shortcut for specifying a bean property name:

public class MyBean { @Name("Bar") public String getFoo() {...} }

If the {@link oaj.BeanContext#BEAN_beanFieldVisibility} setting on the bean context excludes this field (e.g. the visibility is set to the default of PUBLIC, but the field is PROTECTED), this annotation can be used to force the field to be identified as a property.

public class MyBean { @BeanProperty protected String getFoo() {...} }

The bean property named "*" is the designated "dynamic property" which allows for "extra" bean properties not otherwise defined. This is similar in concept to the Jackson @JsonGetterAll and @JsonSetterAll annotations, but generalized for all supported marshall languages. The primary purpose is for backwards compatibility in parsing newer streams with addition information into older beans.

The following shows various ways of using dynamic bean properties.

// Option #1 - A simple public Map field. // The field name can be anything. public class BeanWithDynaField { @BeanProperty(name="*") public Map<String,Object> extraStuff = new LinkedHashMap<String,Object>(); } // Option #2 - Getters and setters. // Method names can be anything. // Getter must return a Map with String keys. // Setter must take in two arguments, a String and Object. public class BeanWithDynaMethods { @BeanProperty(name="*") public Map<String,Object> getMyExtraStuff() { ... } @BeanProperty(name="*") public void setAnExtraField(String name, Object value) { ... } } // Option #3 - Getter only. // Properties will be added through the getter. public class BeanWithDynaGetterOnly { @BeanProperty(name="*") public Map<String,Object> getMyExtraStuff() { ... } }

Similar rules apply for value types and swaps. The property values optionally can be any serializable type or use swaps.

// A serializable type other than Object. public class BeanWithDynaFieldWithListValues { @BeanProperty(name="*") public Map<String,List<String>> getMyExtraStuff() { ... } } // A swapped value. public class BeanWithDynaFieldWithSwappedValues { @BeanProperty(name="*", swap=TemporalCalendarSwap.IsoOffsetDateTime.class) public Map<String,Calendar> getMyExtraStuff() { ... } }

Note that if you're not interested in these additional properties, you can also use the {@link oaj.BeanContext#BEAN_ignoreUnknownBeanProperties} setting to ignore values that don't fit into existing properties.

The {@link oaj.annotation.BeanProperty#value() @BeanProperty(value)} annotation is a synonym for {@link oaj.annotation.BeanProperty#name() @BeanProperty(name)}. Use it in cases where you're only specifying a name so that you can shorten your annotation.

The following annotations are equivalent:

@BeanProperty(name="foo") @BeanProperty("foo")

The {@link oaj.annotation.BeanProperty#type() @BeanProperty(type)} annotation is used to identify a specialized class type for a generalized property. Normally the type is inferred through reflection of the field type or getter return type. However, you'll want to specify this value if you're parsing beans where the bean property class is an interface or abstract class to identify the bean type to instantiate. Otherwise, you may cause an {@link java.lang.InstantiationException} when trying to set these fields.

This property must denote a concrete class with a no-arg constructor.

public class MyBean { // Identify concrete type as a HashMap. @BeanProperty(type=HashMap.class) public Map p1; }

The {@link oaj.annotation.BeanProperty#params() @BeanProperty(params)} annotation is for bean properties of type map or collection. It's used to identify the class types of the contents of the bean property object when the general parameter types are interfaces or abstract classes.

public class MyBean { // This is a HashMap<String,Integer>. @BeanProperty(type=HashMap.class, params={String.class,Integer.class}) public Map p1; }

The {@link oaj.annotation.BeanProperty#properties() @BeanProperty(properties)} annotation is used to limit which child properties are rendered by the serializers. It can be used on any of the following bean property types:

- Beans - Only render the specified properties of the bean.
- Maps - Only render the specified entries in the map.
- Bean/Map arrays - Same, but applied to each element in the array.
- Bean/Map collections - Same, but applied to each element in the collection.

public class MyClass { // Only render 'f1' when serializing this bean property. @BeanProperty(properties={"f1"}) public MyChildClass x1 = new MyChildClass(); } public class MyChildClass { public int f1 = 1; public int f2 = 2; } // Renders "{x1:{f1:1}}" String json = JsonSerializer.DEFAULT.serialize(new MyClass());

The {@link oaj.annotation.BeanProperty#format() @BeanProperty(format)} annotation specifies a String format for converting a bean property value to a formatted string.

// Serialize a float as a string with 2 decimal places. @BeanProperty(format="$%.2f") public float price;