Skip to content
XPages Jakarta EE support libraries
Java
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
eclipse Set version to 1.0.0 Dec 27, 2018
osgi-deps
.gitignore Initial implementation with functional application and request scoped… Jun 2, 2018
LICENSE
NOTICE
NOTICE-Weld
README.md

README.md

XPages Jakarta EE Support

This project adds partial support for several Java/Jakarta EE technologies to XPages applications. Of the list of technologies included in the full JEE 8 spec, this project currently provides:

  • Expression Language 3.0
  • Context and Dependency Injection for Java 2.0
    • Common Annotations for the Java Platform 1.3
    • Interceptors 1.2
    • Dependency Injection for Java 1.0
  • Java API for RESTful Web Services (JAX-RS) 2.1
  • Bean Validation 2.0
  • Java API for JSON Processing 1.1
  • Java API for JSON Binding 1.0
  • JNoSQL 0.0.7

CDI 2.0

The Context and Dependency Injection for Java EE (CDI) 2.0 specification provides for managed beans and dependency injection. To use this feature, add the "org.openntf.xsp.cdi" library to your XPages app.

Currently, this support is focused around adding annotated CDI managed bean classes in an NSF and having them picked up by the variable resolver. For example:

@ApplicationScoped
@Named("applicationGuy")
public class ApplicationGuy {
  public void getFoo() {
    return "hello";
  }
}
<xp:text value="#{applicationGuy.foo}"/>

These beans are managed and instantiated by Weld and support injection with other annotated beans:

@RequestScoped
@Named("requestGuy")
public class RequestGuy {
	@Inject private ApplicationGuy applicationGuy;
	// Or with a name:
	@Inject @Named("applicationGuy") private ApplicationGuy applicationGuy;
  
	// ...
}

Additionally, the CDI system can inject implementations of interfaces based on available concrete implementations, as well as use @PostConstruct and @PreDestroy annotations:

public class RequestGuy extends AbstractBean {
	static interface AppModel {

	}
	static class SomeModelClass implements AppModel {
		
	}
	@Inject AppModel model; // Will be a new instance of SomeModelClass each request
	
	@PostConstruct
	public void postConstruct() { System.out.println("Created with " + model); }
	@PreDestroy
	public void preDestroy() { System.out.println("Destroying!"); }
}

Conversation Scope

This implementation maps CDI @ConversationScoped beans to the XPages view scope. This isn't necessarily a direct analogue, but it's close enough.

Limitations

Currently, the CDI environment for the application acts as if there is a META-INF/beans.xml file with bean-discovery-mode="all" set, but only resolves within the active NSF. So, while NSF beans and classes can reference each other, plugin and system classes are not available for CDI injection.

Expression Language 3.0

The Expression Language 3.0 spec is the evolved version of the original Expression Language as used in XPages. It contains numerous improvements over its predecessors, such as method parameters and lambda expressions. To use this feature, add the "org.openntf.xsp.el3" library to your XPages app.

When the library is enabled, the EL 3 processor takes over for all normal expression language bindings and so can be used without a prefix in some cases:

<xp:text value="${someBean.calculateFoo('some arg')}"/>

Note that Designer attempts to validate the syntax of runtime EL bindings; to work around this, add an "el:" prefix to the binding. This will leave a warning in Designer, but it will work:

<xp:text value="#{el:someBean.hello()}"/>

Implementation Details

The EL 3 handler is currently stricter about null values than the default handler in XPages. For example, take this binding:

<xp:text value="${beanThatDoesNotExist.someProp}"/>

In standard XPages, this will result in an empty output. With the EL 3 resolver, however, this will cause an exception like ELResolver cannot handle a null base Object with identifier 'beanThatDoesNotExist'. I'm considering changing this behavior to match the XPages default, but there's also some value in the strictness, especially because the exception is helpful in referencing the object it's trying to resolve against, which could help track down subtle bugs.

JAX-RS 2.1

The JAX-RS specification is the standard way to provide web services in Java EE applications. A version of it has been included for a long time in Domino by way of the Extension Library. However, this version is also out of date, with Apache Wink implementing JAX-RS 1.1.1.

This library is based on the work of Martin Pradny and provides JAX-RS 2.1 support by way of RESTEasy 3.5.1 for classes inside the NSF. When a class is or has a method annotated with @Path, it is included as a service beneath /xsp/.jaxrs inside the NSF. For example:

package servlet;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import beans.ApplicationGuy;

@Path("/sample")
public class Sample {
  @Inject private ApplicationGuy applicationGuy;
  
	@GET
	public Response hello() {
		try {
			return Response.ok()
				.type(MediaType.TEXT_PLAIN)
				.entity(applicationGuy.toString())
				.build();
		} catch(Throwable t) {
			return Response.serverError().build();
		}
	}
}

As intimated there, it has access to the CDI environment if enabled, though it doesn't yet have proper lifecycle support for ConversationScoped beans.

Bean Validation 2.0

The Bean Validation spec provides a standard mechanism for performing validation of arbitrary objects via annotations. XPages doesn't provide any type of bean validation mechanism - the closest things it provides are UI component validators, but those don't connect to the back-end objects at all.

This library provides validation annotations and a processor via Hibernate Validator 6.0.13.Final. Since there is no existing structure to hook into in the XPages runtime, bean validation must be called explicitly by your code, such as in a common "save" method in model objects. This is done by constructing a Validator object using the builder and then running it against a given bean. Due to the intricacies of the XPages runtime, code performing validation should be run from an OSGi plugin.

For generic use, this library provides an org.openntf.xsp.beanvalidation.XPagesValidationUtil class with methods to construct a Validator object and to use that validator to validate a bean:

import org.openntf.xsp.beanvalidation.XPagesValidationUtil;
import javax.validation.Validator;
import javax.validation.ConstraintViolation;
import javax.validation.constraints.NotEmpty;

public class Tester {
  public static class ExampleBean {
    private @NotEmpty String id;
    public ExampleBean(String id) {
      this.id = id;
    }
  }
  
  public void test() {
    ExampleBean bean = new ExampleBean("");
    Validator validator = XPagesValidationUtil.constructXPagesValidator();
    Set<ConstraintViolation<ExampleBean>> violations = XPagesValidationUtil.validate(bean, validator);
    if(!violations.isEmpty()) {
      // Handle error message here
    }
  }
}

Implementation Details

Using Bean Validation 2.0 requires also having Expression Language 3.0 installed, even if it is not active for the current application.

JSON-P and JSON-B

The Java API for JSON Processing spec is the standardized JSON library for Jakarta EE. The lack of a standard API led to the proliferation of similar-but-incompatible libraries like the initial json.org implementation, Google Gson, and (mostly for XPages developers) the IBM Commons JSON implementation. JSON-P is intended to be a simple and functional unified implementation.

The Java API for JSON Binding spec is a standardization of JSON serialization of Java objects, something that libraries like Gson specialize in. It allows for converting objects to and from a JSON representation, either with its default guesses or by customizing the processor or annotating the Java class.

The "org.openntf.xsp.jsonapi" library provides both of these libraries to XPages, though they don't replace any standard behavior in the environment. To avoid permissions problems, it contains an org.openntf.xsp.jsonapi.JSONBindUtil class to serialize and deserialize objects in AccessController blocks:

import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;

import org.openntf.xsp.jsonapi.JSONBindUtil;

public class JsonTest {
	public static class TestBean {
		private String firstName;
		private String lastName;
		
		public TestBean() { }
		public String getFirstName() { return firstName; }
		public void setFirstName(String firstName) { this.firstName = firstName; }
		public String getLastName() { return lastName; }
		public void setLastName(String lastName) { this.lastName = lastName; }
	}
	
	public String getJson() {
		TestBean foo = new TestBean();
		foo.setFirstName("foo");
		foo.setLastName("fooson");
		Jsonb jsonb = JsonbBuilder.create();
		return JSONBindUtil.toJson(foo, jsonb);
	}
	
	public Object getObject() {
		Jsonb jsonb = JsonbBuilder.create();
		String json = getJson();
		return JSONBindUtil.fromJson(json, jsonb, TestBean.class);
	}
}

JNoSQL

JNoSQL is a nascent project that is slated to be added to the first officially-branded Jakarta EE release.

For now, this plugin just adds the core JNoSQL libraries but no drivers. It should allow working with existing drivers if installed separately, but it is primarily waiting in the wings for the Domino JNoSQL driver to reach maturity.

Requirements

  • Domino FP8+
  • Designer FP10+ (for compiling the NSF)
  • Some of the APIs require setting the project Java compiler level to 1.8

Building

To build this application, first package the osgi-deps Maven project, which will provide the target platform dependencies used by the eclipse Maven tree.

License

The code in the project is licensed under the Apache License 2.0. The dependencies in the binary distribution are licensed under compatible licenses - see NOTICE for details.

You can’t perform that action at this time.