Skip to main content

@BeanProp Annotation

The @BeanProp annotation is applied to bean fields, getter/setter methods, and constructor parameters to control bean introspection and property modeling.

This is the model-side annotation in juneau-commons. It carries the attributes that describe the bean property itself — its name, accessibility (read/write only), concrete type, generic type parameters, element type, and the bean factory used to instantiate its value. Format-side concerns (wire-format overrides, dictionary) live on @MarshalledProp in juneau-marshall.

Migration

This annotation was previously named @Beanp. Usages of @Beanp should be updated to @BeanProp (in org.apache.juneau.commons.bean).

Property Name: name / value​

The @BeanProp(name) annotation overrides the name of the bean property.

public class MyBean {
@BeanProp(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() {...}
}

The @BeanProp(value) annotation is a synonym for name. Use it when you are only specifying a name so the annotation is more concise:

// These two annotations are equivalent:
@BeanProp(name="foo")

@BeanProp("foo")

If the beanFieldVisibility setting on the marshalling 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 {
@BeanProp
protected String getFoo() {...}
}

Dynamic Properties: name="*"​

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

@BeanProp(name="*")
public Map<String,Object> 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 {

@BeanProp(name="*")
public Map<String,Object> getMyExtraStuff() {
...
}

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

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

@BeanProp(name="*")
public Map<String,Object> getMyExtraStuff() {
...
}
}
note

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

Property Type: type​

The @BeanProp(type) annotation identifies a specialized class type for a generalized property. Normally the type is inferred through reflection of the field type or getter return type. However, 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.
@BeanProp(type=HashMap.class)
public Map p1;
}

Generic Type Parameters: params​

The @BeanProp(params) annotation is for bean properties of type map or collection. It identifies the class types of the contents of the bean property object when the general parameter types are interfaces or abstract classes.

public class MyBean {

// Identify concrete map type with String keys and Integer values.
@BeanProp(type=HashMap.class, params={String.class,Integer.class})
public Map p1;
}

Read-Only Properties: ro​

The @BeanProp(ro) annotation identifies a property as read-only. Serializers will serialize such properties as usual, but parsers will silently ignore them.

public class MyBean {
@BeanProp(ro="true")
public float price;
}
Java Records

Marking record components as read-only is not supported during parsing. Because records are immutable, all components must be provided to the canonical constructor.

Write-Only Properties: wo​

The @BeanProp(wo) annotation identifies a property as write-only. Parsers will parse such properties as usual, but serializers will silently ignore them.

public class MyBean {
@BeanProp(wo="true")
public float price;
}

Element Type: elementType​

Specifies the element type for properties of type Stream, BeanSupplier, BeanConsumer, or BeanChannel when type erasure prevents the framework from inferring the generic type argument at runtime.

public class OrderCollection {
// Stream property - element type cannot be inferred at runtime due to erasure
@BeanProp(elementType=Order.class)
public Stream<Order> getOrders() { ... }
}

Bean Factory: factory​

Specifies a BeanFactory class to use when instantiating the value of this specific bean property, overriding the class-level @BeanType(factory) if present.

public class MyBean {
@BeanProp(factory=ItemChannelFactory.class, elementType=Item.class)
public BeanChannel<Item> getItems() { ... }
}

Annotation Inheritance​

info

@BeanProp 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.

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

@BeanProp("c") // Custom property name
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 @BeanProp("c") from parent.
// Property name remains "c" — no re-annotation needed.
super.setChildren(children);
return this; // Return type changed for fluent chaining
}
}

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

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