XPages Managed Beans: Giving SSJS a Real Java Object You Use Like database
You put logic in an SSJS script library as glue, and at first it flows. Then it grows and gets awkward: no real types, hard to unit-test, and stashing things in viewScope / sessionScope means worrying about serialization.
That’s when a managed bean earns its place: declare a Java class in faces-config.xml, and it becomes a top-level variable in SSJS and EL — used just like database or session.
This piece covers how to declare a managed bean, what the Java class must satisfy, how scope sets its lifetime, and when logic should move out of SSJS into a bean.
TL;DR
- A managed bean = a Java class declared in
faces-config.xml, with three elements:<managed-bean-name>(the name),<managed-bean-class>(fully-qualified class),<managed-bean-scope>(scope). - The name becomes a top-level variable: once declared, that name works in SSJS and EL just like
database/session/context—bean.someMethod(),#{bean.prop}. - Three class requirements: (1) a no-arg constructor; (2) getters/setters for the properties you expose; (3)
implements Serializablefor view/session/application scope (the “Keep pages on disk” serialization — the same rule as scope variables). - Scope sets the lifetime:
request/view/session/application(plusnone) — the bean lives in its scope and is discarded when the scope ends. - SSJS vs bean: keep glue and a few lines of logic in SSJS; move stateful, typed, testable, multi-page logic into a managed bean.
What a managed bean is: a faces-config declaration
A managed bean is XPages’ use of JSF’s built-in managed bean facility. Add a block to WebContent/WEB-INF/faces-config.xml (Per Lausten’s example):
<managed-bean> <managed-bean-name>helloWorld</managed-bean-name> <managed-bean-class>com.company.HelloWorld</managed-bean-class> <managed-bean-scope>session</managed-bean-scope></managed-bean>- name: the variable name you use in code.
- class: the fully-qualified Java class.
- scope: how long the bean lives.
What the Java class looks like
Just a standard Java class with three requirements:
public class HelloWorld implements Serializable { private static final long serialVersionUID = 1L; public HelloWorld() { } // no-arg constructor private String someVariable; public String getSomeVariable() { return someVariable; } public void setSomeVariable(String v) { this.someVariable = v; }}- No-arg constructor: JSF has to be able to
newit itself. - get/set: for each property you want to reach from the XPage / SSJS.
implements Serializable: as soon as the scope is view/session/application, the bean is serialized to disk with the page (“Keep pages on disk”) — skipSerializableand you hit the same trap as putting a non-serializable object in scope.
Accessing it from SSJS / EL: like database
Once declared, the name is a top-level object. Wissel puts it plainly: “a new top level object demo is available for use in EL or SSJS in the same way as you can use database, session, context etc.”
// SSJS: call the bean's methods by namedemo.playTune();var v = helloWorld.getSomeVariable();<!-- EL: bind to a control -->#{helloWorld.someVariable}You name the methods yourself and call them from SSJS; bind properties into a control’s value with #{bean.prop}.
Scope sets the lifetime (same set as scope variables)
A bean’s scope is the lifecycle of the four XPages scopes:
request: one request.view: one page instance.session: one browser session — in the example, “multiple XPages will see the same content”; when the scope ends, “the object is automatically discarded.”application: the whole app, shared across all users (mind memory and thread-safety).- (
none: not stored in a scope — built fresh each time it’s needed.)
So “which scope for this bean” is the same judgment as “which scope for this data”: use the lowest that works.
SSJS or a bean?
- Keep it in SSJS: page-event glue, a few lines of decision logic, a call to the back end — a script library is fine.
- Move it to a managed bean: state to hold (across pages, across requests), real Java types and collections, a wish to unit-test, one piece of logic shared by several XPages, or you’re already wrestling with serialization and scope. A bean gives you a clean, typed, testable home — and from SSJS it’s as smooth to use as a built-in object.
What about LotusScript and Java?
A managed bean is an XPages/JSF construct spanning Java and SSJS:
- Java: the bean itself is Java — this is the proper route for moving logic out of SSJS into strongly-typed Java.
- SSJS: not replaced but the consumer — it uses the bean like it uses
database. Glue in SSJS, heavy logic in the bean is the common split. - LotusScript: no equivalent. An LS agent is a procedural “run a program” model — there’s no “declare a scoped, framework-managed object that other code reaches by name.”