Skip to main content

@Beanp Annotation

The @Beanp annotation is used to tailor how individual bean properties are interpreted by the framework.

The @Beanp(name) annotation is used to override the name of the bean property.

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

The @Name annotation is a shortcut for specifying a bean property name:

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

If the 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 {
@Beanp
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 {

@Beanp("*")
public Map extraStuff = new LinkedHashMap();
}

// 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 {

@Beanp("*")
public Map getMyExtraStuff() {
...
}

@Beanp("*")
public void setAnExtraField(String name, Object value) {
...
}
}

// Option #3 - Getter only.
// Properties will be added through the getter.
public class BeanWithDynaGetterOnly {

@Beanp("*")
public Map 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 {

@Beanp("*")
public Map> getMyExtraStuff() {
...
}
}

// A swapped value.
public class BeanWithDynaFieldWithSwappedValues {

@Beanp(name="*", swap=TemporalCalendarSwap.IsoOffsetDateTime.class)
public Map getMyExtraStuff() {
...
}
}
note

Note that if you're not interested in these additional properties, you can also use the ignoreUnknownBeanProperties setting to ignore values that don't fit into existing properties.

The @Beanp(value) annotation is a synonym for @Beanp(name). Use it in cases where you're only specifying a name so that you can shorten your annotation.

The following annotations are equivalent:

@Beanp(name="foo")

@Beanp("foo")

The @Beanp(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 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.
@Beanp(type=HashMap.class)
public Map p1;
}

The @Beanp(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.
@Beanp(type=HashMap.class, params={String.class,Integer.class})
public Map p1;
}

The @Beanp(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.
@Beanp(properties={"f1"})
public MyChildClass x1 = new MyChildClass();
}

public class MyChildClass {
public int f1 = 1;
public int f2 = 2;
}

// Renders "{x1:{f1:1}}"
String json = Json.of(new MyClass());

The @Beanp(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.
@Beanp(format="$%.2f")
public float price;

Annotation Inheritance

Since 9.2.0

Starting with Juneau 9.2.0, @Beanp and @Name annotations are automatically inherited when bean property methods (getters, setters, extraKeys) are overridden in subclasses.

This feature is particularly useful for fluent APIs where you want to override setters to change the return type without needing to re-annotate every method with @Beanp, @Xml, @Json, and other serialization annotations.

Example:

// Parent class with annotated property
public class Parent {
private List<String> children;

@Beanp("c") // Custom property name
@Xml(format=XmlFormat.ELEMENTS)
public List<String> getChildren() {
return children;
}

public Parent setChildren(List<String> children) {
this.children = children;
return this;
}
}

// Child class with fluent setter override
public class Child extends Parent {
@Override
public List<String> getChildren() {
return super.getChildren();
}

@Override
public Child setChildren(List<String> children) {
// ✓ Automatically inherits @Beanp("c") from parent
// ✓ Property name remains "c" (not "children")
// ✓ No re-annotation needed!
super.setChildren(children);
return this; // Return type changed for fluent chaining
}
}

How It Works:

When the serialization framework processes the Child class, it:

  1. Detects that setChildren() overrides a parent method
  2. Walks up the class hierarchy to find the parent method
  3. Inherits the @Beanp("c") annotation from the parent
  4. Uses the same property name ("c") for both parent and child classes

This prevents duplicate property definitions and ensures consistent serialization behavior across inheritance hierarchies.

Without Annotation Inheritance (pre-9.2.0):

Prior to 9.2.0, the Child class above would have created TWO separate properties:

  • Property "c" from the parent getter
  • Property "children" from the child setter (derived from method name)

This would cause serialization errors like:

SerializeException: ELEMENTS and ELEMENT properties found on the same bean. 
These cannot be mixed.

Edge Case - Intentional Property Name Override:

If you want to override a method and use a different property name, simply re-annotate the method:

public class Child extends Parent {
@Override
@Beanp("childList") // Explicit new name
public Child setChildren(List<String> children) {
super.setChildren(children);
return this;
}
}

In this case, the explicit @Beanp("childList") takes precedence over the inherited annotation.

note

Annotation inheritance applies to ALL bean property annotations, including @Beanp, @Name, @Xml, @Json, @Schema, and others. This ensures complete metadata is preserved across inheritance hierarchies.

Discussion

Share feedback or follow-up questions for this page directly through GitHub.