Minimal 3-tier Java EE app, without any XML config

Older versions of Java EE and Java frameworks in general were rather heavy with regard to required XML for configuration. Notorious were EJB2, Spring 2.x, JSF 1.x, Servlet 2.5 and many more.

These days things have improved quite a lot. In this post I'll demonstrate a very simple, yet 3-tiered, Hello word application for Java EE. It uses JSF 2.1 and EJB 3.1 and absolutely not a single line of XML configuration.

The entire application consists of just 3 files: page.xhtml, and To run the application, create a dynamic web project called 'mytest' in Eclipse (EE edition) and delete everything that's generated by default in WebContent. Copy page.xhtml to WebContent and copy both .java files to src. Add the app to your server (e.g. Payara 164) and browse to localhost:8080/mytest/page.jsf to see all the action.

The following shows the code of the 3 files involved:


<html xmlns="" xmlns:jsf="">

        <form jsf:id="form">
            <input type="text" jsf:value="#{}" />
            <input type="submit" value="Say Hello" jsf:action="#{backingBean.sayHello}" /> 

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;

public class BackingBean {

    String name;
    String hello;
    BusinessBean businessBean;

    public void sayHello() {
        hello = businessBean.generateHello(name);

    public String getName() {
        return name;

    public void setName(String name) { = name;
    public String getHello() {
        return hello;

import javax.ejb.Stateless;

public class BusinessBean {

    public String generateHello(String name) {
        return String.format("Hello, %s!", name);

The following shows that the project in Eclipse only has the 3 mentioned files:

The deployment itself also consists of only the 3 files mentioned (no IDE generated magic), although one extra step has been performed and that's that the .java classes have been compiled to their .class versions and have been put into a newly generated directory WEB-INF/classes:

Note the use of a couple of conventions that make this all work:

  • The context root is by default the name of the directory in which the app is deployed (technically: the exploded war name).
  • JSF by default maps the JSF controller servlet to *.jsf (and to /faces/* and *.faces).
  • Facelets files have a default suffix of .xhtml.
  • The backing bean's default name in EL is the simple class name with the first letter de-capitalized.
  • The backing bean is by default in request scope.
  • The bi-directional binding from the view (page.xhtml) to the model via the EL expression #{} takes advantage of the JavaBean naming conventions for getters/setters.
  • The EJB is by default pooled and transactional.
  • A no-interface view is created for the EJB by default (since it doesn't implement business interfaces).

Everything that is defaulted can be configured differently as needed. For instance, the default name in EL for the backing bean can be set to a different name via an attribute on the ManagedBean annotation, and the EJB can be made not transactional via an extra annotation. Some things would require XML to be configured differently. For instance, alternative mappings for the Faces Servlet or the default Facelets file suffix have to be configured in a web.xml file.

Finally, note that the goal of this example is to demonstrate one of the simplest possible setups and doesn't necessarily adheres to all best practices. In reality, for non-trivial applications you'd want to declare you instance variables as private, definitely would not use the default package for your classes, probably create separate packages for your backing and business code, make sure *.xhtml is not directly accessible (e.g. by mapping the Faces Servlet directly to .xhtml in web.xml), and if your application really grows you might want to consider putting the business code in a separate module, add interfaces to the beans, etc etc.

But the point is that Java EE (and various other Java frameworks as well), now allow you to start with very simple defaults, making the barrier to enter much lower than before. You can then refactor and configure when the need arrises.

Arjan Tijms


Popular posts from this blog

Implementing container authentication in Java EE with JASPIC

Jakarta EE Survey 2022

Counting the rows returned from a JPA query