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:

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);
    });
})