New Release: XPages Jakarta EE 3.6.0

Sat Jan 17 15:59:32 EST 2026

Tags: jakartaee java

Earlier today, I released version 3.6.0 of the XPages JEE project, which has a number of handy improvements.

NoSQL Driver Improvements

In continuing with my goal to remove as many instances of needing to use the lotus.domino API (or others, like ODA or JNX) in app dev, I've added a couple more useful features to NoSQL DominoRepository objects:

  • The queryEffectiveAccess() method gives you a summary of the current user's access rights to the underlying database: the user's DN, the access level (Author, Editor, etc.), their privileges (delete docs, etc.), and their roles
  • The send(...) method lets you send the underlying document as mail
  • The queryLastModified() method will tell you the last time the database was modified in a speedy way, which can be useful for cache invalidation

There are also a handful of fixes and performance improvements, such as a better ETag generation routine that brings it more in line with the standard way of doing these.

sessionAsSigner in Faces Requests

Originally, Faces (JSF) requests didn't have access to sessionAsSigner due to the way the Servlet had to work around the XPages environment without colliding. Now, though, these sessions will be available during requests for Faces files, allowing them to be used as dominoSessionAsSigner on a page itself and also injected normally in managed beans.

Annotated Async Methods

This release contains version bumps for a number of upstream implementations, and one is of particular note: Concurro, the Jakarta Concurrency implementation, added support for the runAt property of the @Asynchronous.

In case you're unfamiliar with it, the Concurrency spec provides for a couple handy ways to do asynchronous programming, and the glue code in this project makes it so that works on Domino and carries the DB and user context into the other threads. One of the neat ways you can do that is via annotations on CDI beans that make things implicitly async. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Asynchronous
public CompletableFuture<String> doAsyncOp() {
	// Do some complex work here
	return Asynchronous.Result.complete("job's done");
}

public void kickOffSomeWork() {
	// Do basic work here
	CompletableFuture<String> future = doAsyncOp();
	// Continue on while the async operation does its thing
}

The CompletableFuture there is a standard Java class that you can use to wait in the current thread until it's done (future.get()) or compose other behavior. It's quite handy, and generally much easier than trying to get this stuff to work without this project.

The new addition in Concurro is support for runAt, which lets you provide a repeating schedule for the task, looping until the app ends or the method returns a complete result. For example:

1
2
3
4
5
6
7
8
private int scheduleRan;

@Asynchronous(runAt = @Schedule(cron="* * * * * *"))
public void runScheduled() {
	if(++scheduleRan == 5) {
		Asynchronous.Result.complete(null);
	}
}

Calling runScheduled() will run that code every second (thanks to that cron pattern) until it's done so five times, at which it will stop. While it was previously possible to do this by providing a Trigger implementation passed to the ManagedScheduledExecutorService, it can potentially be much nicer and clearer to do it in annotation code like this.

Misc. Improvements

There are also just generally a number of bug fixes here and there, hopefully avoiding the ServiceLoader trouble that cropped up recently.

I also did some fun tinkering and expansion of the XPages Build Stubs project to be able to build this one without requiring the real proprietary dependencies. In practice, it's still better to use a generated update site from the real thing, since the stubs don't include every class, but this made it easier to set up automated builds on GitHub Actions without yet having to worry about how to keep secrets from leaking. This doesn't include the ability to build the NSFs from the ODPs or run the integration test suite, since both of those require true Domino containers, but it's a nice step in making the build more portable.