Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Monster Component in Java EE 7

DZone's Guide to

Monster Component in Java EE 7

· Java Zone
Free Resource

The single app analytics solutions to take your web and mobile apps to the next level.  Try today!  Brought to you in partnership with CA Technologies

With Java EE 7 being released I thought it was time to update the Monster Component ! A few years ago Ludovic Champenois had this idea of adding as many Java EE annotations as possible to a Java class. It was then used by Alexis Moussine Pouchkine on his Java EE seminars. It was time to have a revival and update the code to fit Java EE 7 novelties.

What is a Monster Component ?

A monster component is a useless piece of code to which you add several Java EE annotations giving it different aspects. Java EE is a managed environment : take a Java class, add a @Stateless annotation, and the container gives you transactions, security, pooling… take another class, add a @Path annotation and the container gives you REST invocation. So, if you add both @Stateless and @Path to the same class, you accumulate the services of a stateless EJB and a REST Web Service.

The Monster Component

The Book class below is a persistent class with a method (createAndListBooks) that persists itself and retrieves all the books from the database. It has been turned into a Monster Component because it accumulates several services:

  • Persistence (JPA) : the Book class is annotated with @Entity, @Table and declares a @NamedQuery. Some Book attributes customize the mapping (with @Column) or are marked as @Transient (such as the EntityManager)
  • XML binding (JAXB) : with the @XmlRootElement and @XmlAccessorType annotations, the Book class can use marshalization to get an XML representation of a Book. It customizes the XML binding using @XmlElement or @XmlTransient (for the EntityManager)
  • Constraints (Bean Validation) : some of the attributes of the Book have constraints (@Size) as well as method parameters (@NotNull on createAndListBooks)
  • EJB : the Book class is a stateless EJB (annotated with @Stateless), therefore it injects an EntityManager and declares the transactional method createAndListBooks
  • Servlet : the Book class is also a Servlet as it extends HttpServlet, is annotated with @WebServlet and overrides the doGetmethod. This method uses the injected Book EJB to persist itself.
  • RESTful Web Service (JAX-RS) : the @Path and @GET method allows you to invoke the createAndListBooks method via a HTTP GET. It produces an XML representation of all the books thanks to the JAXB @XmlRootElement annotation
  • Lifecycle management : two private methods have lifecycle management (@PostConstruct and @PreDestroy)
  • Interception : the Book class defines a method interceptor (method logMethod annotated with @AroundInvoke) that logs all method invocation
@Path("/MonsterRest")
@Stateless
@WebServlet(urlPatterns = "/MonsterServlet")
@Entity
@Table(name = "MonsterEntity")
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@NamedQuery(name = "findAll", query = "SELECT c FROM Book c")
public class Book extends HttpServlet {
 
    // ======================================
    // =             Attributes             =
    // ======================================
 
    @Id
    @GeneratedValue
    private Long id;
    private String isbn;
    private Integer nbOfPage;
    private Boolean illustrations;
    private String contentLanguage;
    @Column(nullable = false)
    @Size(min = 5, max = 50)
    @XmlElement(nillable = false)
    private String title;
    private Float price;
    @Column(length = 2000)
    @Size(max = 2000)
    private String description;
    @ElementCollection
    @CollectionTable(name = "tags")
    private List<String> tags = new ArrayList<>();
 
    // ======================================
    // =         Injected Resources         =
    // ======================================
 
    @XmlTransient
    @Transient
    @EJB
    private Book monsterEJB;
 
    @XmlTransient
    @Transient
    @PersistenceContext(unitName = "monsterPU")
    private EntityManager em;
 
    // ======================================
    // =        Servlet Entry Point         =
    // ======================================
 
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String title = request.getParameter("title");
        try {
            response.getWriter().println("Servlet calling EJB " + monsterEJB.createAndListBooks(title));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    // ======================================
    // =          Business methods          =
    // ======================================
 
    @GET
    @Path("/{title}")
    @Produces(MediaType.APPLICATION_XML)
    public List<Book> createAndListBooks(@PathParam("title") @NotNull String title) {
        // Sets data
        this.id = null;
        this.title = title + " " + new Date();
        this.price = new Float(0.01);
        this.description = "The hard-coded description";
        this.isbn = "978-1-4302-1954-5";
        this.nbOfPage = 210;
        this.illustrations = Boolean.TRUE;
        List<String> tags = new ArrayList<>();
        tags.add("Monster");
        tags.add("Component");
        this.tags = tags;
 
        // Persists the book
        em.persist(this);
 
        // Returns all books
        TypedQuery<Book> query = em.createNamedQuery("findAll", Book.class);
        List<Book> allBooks = query.getResultList();
        return allBooks;
    }
 
    // ======================================
    // =            Interceptor             =
    // ======================================
 
    @AroundInvoke
    public Object logMethod(InvocationContext ic) throws Exception {
        System.out.println(">>> " + ic.getTarget().getClass() + " - " + ic.getMethod().getName());
        try {
            return ic.proceed();
        } finally {
            System.out.println("<<< " + ic.getTarget().getClass() + " - " + ic.getMethod().getName());
        }
    }
 
    @PostConstruct
    private void prepare() {
        System.out.println("\n=> PostConstruct");
        System.out.println("================");
    }
 
    @PreDestroy
    private void release() {
        System.out.println("=============");
        System.out.println("=> PreDestroy");
    }
 
    (...)
}

Execute the Monster Component

First of all, if you download the code and run the integration test, you will notice that this code actually works ;o) I’ve added a simple JSF web page and a backing bean to invoke the Monster Component in several ways (EJB, Servlet and REST Web Service). So you can package everything in a war file and deploy it to GlassFish 4. There is also an Integration Test that checks it works in an embedded EJB container.

What’s missing ?

I could have added more annotations… but things don’t always work the way we want. I wanted to add SOAP Web Service (JAX-WS) capabilities with a @WebService and @WebMethod annotations. First of all, if you add a @WebService annotation, it makes the integration test fail (SOAP Web Services are not part of the embedded EJB container). I couldn’t also generate the WSDL, something wrong with the combination of JAX-WS and JPA mapping annotations. Also remember that JAX-WS is not part of the Java EE 7 Web Profile, and JAX-RS is.

The Servlet needs to inject the EJB. Impossible to use the CDI @Inject annotation because it is a cyclic reference (the Book injects itself). But with @EJB it works. So I didn’t add CDI in this example.

Do you see anything else that could be added ?

What does this show ?

This example of code shows that you don’t have to over engineer your code and add multiple decoupled architectural layers. Just put everything into a single class ;o) This code is a bit shocking, several concepts are embedded in a single class (no separation of concerns) and most of you (including me) will find this ugly. On the other hand, having several layers, abstraction, interfaces, DAOs, DTOs and so on… is also ugly (but it looks like we got use to such complexity). Don’t put everything into a single class, but do not spread a concern over several artifacts either. Find the right balance and KISS.

Conclusion

I’ve shown you in this post that the Java EE 7 philosophy is just about adding metadata to a Java class and leave the container to do the job. Metadata can be defined with XML or annotations. The Book class has be turned into a Monster Component by adding as many annotations as possible. The class can persist itself in a transactional manner thanks to JPA and EJB, as well as being invoked as a Servlet and RESTful Web Service, while intercepting each method invocation and validating constraints.

CA App Experience Analytics, a whole new level of visibility. Learn more. Brought to you in partnership with CA Technologies.

Topics:

Published at DZone with permission of Antonio Goncalves, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}