Restfull access to JSF ManagedBeans
With the rising of the popularity of REST with JSON, JSF becomes a bit of a hassle in situations with mixed technologies. JSF @ManagedBean's are not accessable through REST.
By adding a REST service that accesses the JSF beans this can be solved. Problem is that the REST has no JSF context and so can't access the @ManagedBean's. But current JSF also works with CDI @Named beans and those can be accessed from REST services.
By creating a REST service that accesses the @Named beans through CDI, the same bean is used for both JSF and REST and so we can mix both technologies.
- Be carefull about thread safety!
- Security is not arranged in given example code!!!
The code below works for JSF beans annotated with @Named. @ManagedBean does not work because CDI can't access those beans.
In a pure Tomcat environment we need some dependencies:
- Tomcat
- CDI (Weld)
- REST (CXF)
- JSON (Jackson)
Relevant dependecies in pom.xml:
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>${cdi-version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf-version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf-version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf-version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-integration-cdi</artifactId>
<version>${cxf-version}</version>
</dependency>
<dependency>
<!-- Allow for "<service url>?_wadl" usage to automatically generate the wadl file -->
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>${cxf-version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-service-description</artifactId>
<version>${cxf-version}</version>
</dependency>
<dependency>
<!-- JSON converter -->
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<!-- CDI implementation -->
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
<version>${weld-version}</version>
<scope>runtime</scope>
</dependency>
Relevant parts in web.xml:
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.cdi.CXFCdiServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/api/rest/*</url-pattern>
</servlet-mapping>
<!-- CDI -->
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
Bootstrap REST:
@ApplicationPath("/")
public class ApplicationConfig extends Application {}
Create REST service that produces the json:
@Path("/jsf/{beanName}/{fieldName}")
@Produces(MediaType.APPLICATION_JSON)
public class CalendarService {
/**
* @return Object
*/
@GET
public Object getBeanProperty(@PathParam("beanName") String beanName, @PathParam("fieldName") String fieldName) {
BeanManager beanManager = CDI.current().getBeanManager();
Object bean = CDIUtils.lookup(beanManager, beanName);
Object object = PropertyUtils.getProperty(bean, fieldName);
return object;
}
}
The REST service can now be consumed by jQuery like this:
$.ajax({url: "/api/rest/jsf/<beanName>/<fieldName>"}).then(function(data) {
$.each(blocks, function(index, data) {
console.log(index + ": " + data);
});
})