Skip to main content

Bean Contexts

The Bean Context (BCT — Bean Context Type) is Juneau's core bean-introspection framework. It provides a unified, highly configurable view of Java beans that all serializers, parsers, and other framework components share.

Every marshaller in Juneau extends MarshallingContext, which means a single set of bean-modeling settings controls how beans are discovered, read, and written across all formats — JSON, XML, YAML, CSV, MessagePack, and the rest — with no per-format configuration duplication.

The framework splits into two layers:

LayerLocationResponsibility
Bean modelingjuneau-commonsIntrospect classes, discover properties, apply @BeanType/@BeanProp/@BeanIgnore/@BeanCtor
Marshallingjuneau-marshallExtend the bean model with ClassMeta, type swaps, bean dictionaries, format-specific options

MarshallingContext — the Configuration Context​

MarshallingContext is the root configuration object for bean introspection and marshalling. All serializers and parsers (and their builders) extend from it, so they inherit every builder method on the context directly. Instances are:

  • Immutable — constructed once via a fluent builder and never changed thereafter.
  • Thread-safe — freely shared across serializers and threads.
  • Cache-sharing — contexts with the same settings reuse the same ClassMeta cache, so expensive reflective analysis of a given class happens only once.
// Create a standalone context (useful for programmatic bean introspection
// without going through a full serializer).
MarshallingContext ctx = MarshallingContext
.create()
.beansRequireDefaultConstructor() // Tighten bean detection
.beanFieldVisibility(Visibility.ANY) // Include private fields
.notBeanClasses(MyRawType.class) // Exclude this class from bean treatment
.build();

The static constant MarshallingContext.DEFAULT provides a pre-built, zero-config context for quick use.


MarshallingSession — the Per-Operation Session​

MarshallingSession is an ephemeral, per-operation companion to MarshallingContext. Sessions hold request-scoped state such as locale, time zone, active view, and media type. They are lightweight to create and are typically not shared across threads.

// Open a session for the DEFAULT context.
MarshallingSession session = MarshallingContext.DEFAULT_SESSION; // singleton no-op session

// Or create one with per-call settings.
MarshallingSession session = MarshallingContext.DEFAULT.createSession();

Sessions are the entry point for creating BeanMap instances (see below).


BeanMap — Beans as Maps​

BeanMap wraps a Java bean inside a Map<String, Object> interface, letting properties be read and written via the standard get/put methods. All serializers use BeanMap internally to traverse a bean's properties without generating intermediate structures. Although used internally by every serializer and parser, it is often useful on its own.

public class Person {
public String name = "John Smith";
public int age = 21;
}

// Wrap an existing bean.
BeanMap<Person> bm = MarshallingContext.DEFAULT_SESSION.toBeanMap(new Person());
bm.put("name", "Jane Doe");
String name = (String) bm.get("name"); // "Jane Doe"

// Typed accessor — convert the property value on read.
int age = bm.get("age", int.class);

// Create a new bean through the map.
BeanMap<Person> bm2 = MarshallingContext.DEFAULT_SESSION.newBeanMap(Person.class);
bm2.put("name", "Alice");
bm2.put("age", 30);
Person p = bm2.getBean();

BeanMap iteration follows a deterministic property order: explicit @BeanType(properties=...) list → alphabetical (default) → natural reflection order when @BeanType(unsorted=true) is set.


BeanMeta — Bean Class Metadata​

BeanMeta is the compiled introspection record for a single bean class. It holds the complete, resolved list of BeanPropertyMeta entries — one per logical property — including the underlying field or getter/setter pair, resolved generic types, and any applied annotations.

Instances are built once and cached by the context. Retrieve one via:

BeanMeta<Person> meta = MarshallingContext.DEFAULT_SESSION.getBeanMeta(Person.class);
for (BeanPropertyMeta prop : meta) {
System.out.println(prop.getName() + " : " + prop.getClassMeta().getInnerClass());
}

ClassMeta — Type Metadata Cache​

ClassMeta extends BeanMeta with marshalling-layer knowledge: whether a class is a bean, a collection, a map, a primitive, an enum, or something else (the Category enum covers ~20 categories). It also records the active object swaps and format overrides for that type.

ClassMeta<Person> cm = MarshallingContext.DEFAULT.getClassMeta(Person.class);
cm.isBean(); // true
cm.isMap(); // false

Core Annotations​

The bean-modeling layer lives in juneau-commons and uses a trio of annotations that are independent of any marshalling concern. The marshalling layer in juneau-marshall extends each one with a sibling that carries format-specific attributes.

@BeanType — class-level control​

Applied to a class to declare the canonical property list, sorting, excluded properties, stop class, and more. The marshalling-layer sibling is @Marshalled.

// Keep only "id" and "name"; expose them in that exact order.
@BeanType(properties = "id,name")
public class Person {
public int id;
public String name;
public String internalToken; // excluded — not in properties list
}
// Exclude a property by name (useful when you cannot edit the class).
@BeanType(excludeProperties = "password")
public class Account { ... }

@BeanProp — property-level control​

Applied to a field, getter, setter, or constructor parameter to rename a property, mark it read-only/write-only, specify a concrete type, or supply a factory. The marshalling-layer sibling is @MarshalledProp.

public class Contact {

// Rename the serialized property key.
@BeanProp("full_name")
public String fullName;

// Read-only — serialized but ignored on parse.
@BeanProp(ro = "true")
public String getCreatedAt() { ... }

// Write-only — accepted on parse but not serialized.
@BeanProp(wo = "true")
public void setPassword(String pw) { ... }
}

@BeanIgnore — exclusion​

Applied to a class, field, method, or constructor to exclude it from bean introspection. On a class, marks it as not a bean (the marshaller falls back to toString() or a registered swap). On a member, removes it from the property set.

// Entire class: never treated as a bean.
@BeanIgnore
public class RawToken { ... }

// Individual member: hidden from serialization and parsing.
public class Order {
public String orderId;

@BeanIgnore
public String getDebugString() { ... } // excluded from marshalling
}

@BeanCtor — constructor-based deserialization​

Applied to a constructor to map its parameters onto the bean's logical property names. Required when a bean is read-only (no setters) and must be instantiated during parsing. Java Records detect their canonical constructor automatically, so @BeanCtor is optional there.

public class Point {
public final int x, y;

@BeanCtor({"x","y"})
public Point(int x, int y) {
this.x = x; this.y = y;
}
}

// Parser can now reconstruct Point from {"x":1,"y":2}.
Point p = Json.to("{x:1,y:2}", Point.class);

Swaps and Filters​

When a class cannot be introspected as a bean (or needs a different wire representation), the bean context delegates to object swaps — pluggable converters registered on the context builder:

MarshallingContext ctx = MarshallingContext
.create()
.calendarFormat(CalendarFormat.ISO_INSTANT) // Instant → ISO-8601 string
.build();

The MarshalledFilter class (implements BeanFilter) is the programmatic API for applying bean-level overrides such as additional include/exclude lists or property namers without touching the annotated source class — useful for third-party types.

See Also

Builder Configuration​

Every marshaller builder inherits the full set of MarshallingContext.Builder settings. Common properties include:

Builder methodEffect
beanFieldVisibility(Visibility)Include PRIVATE, PROTECTED, or PUBLIC fields as properties
beanMethodVisibility(Visibility)Visibility threshold for getter/setter discovery
beansRequireDefaultConstructor()Only treat classes with a public no-arg constructor as beans
beansRequireSerializable()Only treat Serializable classes as beans
notBeanClasses(Class...)Exclude specific classes from bean treatment
notBeanPackages(String...)Exclude entire packages from bean treatment
sortProperties()Force alphabetical property order globally
ignoreUnknownBeanProperties()Silently skip unrecognized keys during parsing
swaps(Class...)Register object-swap converters
beanDictionary(Class...)Register types for polymorphic _type resolution

Any setting that can be applied via a builder can equally be applied via a @MarshalledConfig config annotation, allowing serializer settings to live on an annotated class and be applied via builder.applyAnnotations(MyAnnotatedClass.class).

// Config annotation on a class — useful in REST servlet hierarchies.
@MarshalledConfig(sortProperties = "true", ignoreUnknownBeanProperties = "true")
public class MyApiResource { ... }

// Apply the annotations to a serializer at build time.
JsonSerializer s = JsonSerializer.create()
.applyAnnotations(MyApiResource.class)
.build();
See Also

In This Section​