TOTD #148: JPA2 Metamodel Classes in NetBeans 7.0 - Writing type-safe Criteria API

NetBeans 7.0 M2 was released recently. There are several Java EE related improvements in this release:

  • Find usages of managed beans (JSF/CDI) and their properties
  • PrimeFaces is now available as an integrated JSF component library
  • Wizard for creating Bean Validation constraint
  • CDI Qualifier creation editor hint
  • Cleaned up Inspect Observer/Producer for CDI events
  • Generation of Bean Validation annotations for Entities

and some others. One of the features that is not much spoken about is the automatic generation of JPA 2 Metamodel classes from Entity classes. This Tip Of The Day (TOTD) will explain how to generate these classes and use them for writing type-safe JPA2 Criteria queries.

The JPA2 Metamodel classes capture the metamodel of the persistent state and relationships of the managed classes of a persistence unit. This abstract persistence schema is then used to author the type-safe queries using Critieria API. The canonical metamodel classes can be generated statically using an annotation processor following the rules defined by the specification. The good thing is that no extra configuration is required to generate these metamodel classes. NetBeans IDE automatically generates the canonical metamodel classes using the EclipseLink Canonical Model Generator. There are two ways these metamodel classes are generated in NetBeans:

  1. Pre-configured when Entity Classes are generated from a Database using the wizards. TOTD #122 provide more details on that. The actual metamodel classes are generated when the project is build using "Clean and Build", "Deploy" or some other related target.
  2. Explicitly configured by right-clicking on the project, "Properties", "Libraries", "Processor", "Add Library...", and select "EclipseLink(JPA 2.0)" and "EclipseLink-ModelGen(JPA 2.0)" libraries and click on "Add Library" as shown below.


This TOTD will use the "Manufacturer" table from the pre-configured "jdbc/sample" JDBC resource in NetBeans and GlassFish. It will create a simple 2-page application where the first page (index.xhtml) accepts a Manufacturer name and the second page (show.xhtml) displays some details about that manufacturer.

  1. Create a NetBeans Web project with the title "CriteriaMetamodel", make sure to enable CDI and Java Server Faces during the creation.
  2. Create "Manufacturer" JPA entity by using the pre-configured "jdbc:derby://localhost:1527/sample" database connection and using the MANUFACTURER table. Notice that the generated manufacturer entity contains the bean validation constraints derived from the database schema, yet another new feature in 7.0 M2. More on this topic in a later blog.
  3. Generate the metamodel classes by right-clicking on the project and selecting "Clean and Build". The generated metamodel class looks like:
    package org.glassfish.samples.entities;
    import javax.annotation.Generated;
    import javax.persistence.metamodel.SingularAttribute;
    import javax.persistence.metamodel.StaticMetamodel;
    @Generated("EclipseLink-2.1.0.v20100614-r7608 @ Mon Oct 25 16:35:03 PDT 2010")
    @StaticMetamodel(Manufacturer.class)
    public class Manufacturer_ { 
        public static volatile SingularAttribute addressline2;
        public static volatile SingularAttribute zip;
        public static volatile SingularAttribute phone;
        public static volatile SingularAttribute addressline1;
        public static volatile SingularAttribute fax;
        public static volatile SingularAttribute manufacturerId;
        public static volatile SingularAttribute email;
        public static volatile SingularAttribute name;
        public static volatile SingularAttribute state;
        public static volatile SingularAttribute city;
        public static volatile SingularAttribute rep;
    }
    

    This is shown as "Generated Sources" in NetBeans IDE as shown:

  4. Generate a new Java class "DatabaseBean" and mark it with "@javax.enterprise.inject.Model" annotation. This class will be the "backing bean" for the JSF pages and will have
    1. A field to accept the manufacturer's name from "index.xhtml"
    2. A field to show information about the searched manufacturer in "show.xhtml"
    3. A business method "searchManufacturer" that searches the database for the given manufacturer's name. This method will use the generated metamodel class and type-safe Criteria API to query the database.

    The complete source code for the class looks like:
    @PersistenceUnit EntityManagerFactory emf;
    
    String name;
    
    Manufacturer manufacturer;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public Manufacturer getManufacturer() {
        return manufacturer;
    }
    
    public void searchManufacturer() {
        EntityManager em = emf.createEntityManager();
    
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery criteria = builder.createQuery(Manufacturer.class);
    
        // FROM clause
        Root root = criteria.from(Manufacturer.class);
    
        // SELECT clause
        criteria.select(root);
    
        // WHERE clause
        Predicate condition = builder.like(root.get(Manufacturer_.name),
                "%" + name + "%");
        criteria.where(condition);
    
        // FIRE query
        TypedQuery query = em.createQuery(criteria);
    
        // PRINT result
        List manufacturers = query.getResultList();
    
        if (manufacturers != null && manufacturers.size() > 0) {
            manufacturer = (Manufacturer)manufacturers.get(0);
        }
    }
    

    The business method returns the first manufacturer whose name contains the text entered in the textbox. No validation is performed in order to keep the business logic simple.

    Notice how "searchManufacturer" method is not using any String-based identifiers for constructing the query graph. This gives the complete type-safety for query construction and allows the errors to be detected much earlier.
  5. Edit the generated "index.xhtml" such that the content within <h:body> looks like:
    <h:form>
     <h:panelGrid columns="3">
     <h:outputText value="Name:" />
     <h:inputText value="#{databaseBean.name}" id="name"/>
     </h:panelGrid>
    
     <h:commandButton
        actionListener="#{databaseBean.searchManufacturer}"
        action="show"
        value="submit"/>
    </h:form>
    

    This page shows a text box and a submit button. The "searchManufacturer" method of the DatabaseBean is invoked when the "submit" button is clicked and passes the entered text in the "name"property of the DatabaseBean.
  6. Create a new XHTML page and name it "show.xhtml". Replace the generated boilerplate code with the code given below:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Show Manufacturer's Detail</title>
      </head>
      <body>
        Name: #{databaseBean.manufacturer.name}<br/>
        Phone: #{databaseBean.manufacturer.phone}<br/>
        Address Line1: #{databaseBean.manufacturer.addressline1}<br/>
        Address Line2: #{databaseBean.manufacturer.addressline2}<br/>
     </body>
    </html>

Now you can deploy the application to GlassFish by usual means and access "http://localhost:8080/CriteriaMetamodel/faces/index.xhtml" which gets displayed as:

Enter some value as "S" in the text box and click on "Submit" to display the result as:

The complete source code for this sample can be downloaded here.

Now Criteria query is little verbose but it does give you the type-safety and was explicitly asked within the JPA Expert Group. It allows you to manipulate different parts of a query such as SELECT, FROM, and WHERE clauses and that too using the Java type system. This reminds me of Mr Potato Head :-)

This behavior can be achieved in JPQL but is available exclusively using String manipulation and the errors are not detected until runtime.


How are you using Criteria API ?

What use cases would you like to see solved in JPA2.next ?

Technorati: totd jpa2 criteria metamodel netbeans javaee6 glassfish

Comments:

I like the criteria api but I think the next version needs to be put on a diet. It's extremely verbose compared to JPQL. Yes we have achieved type safety but at the expense of conciseness. Let's see if we can tighten things up in the next rev.

Posted by sboulay on October 31, 2010 at 06:35 AM PDT #

As you pointed out the Criteria API is a little verbose. For a more compact typesafe alternative you might want to try out Querydsl : http://source.mysema.com/display/querydsl/Querydsl

It uses APT as well, but with a dynamic metamodel, instead of a static one, which results in much more compact expressions.

Posted by Timo Westkämper on October 31, 2010 at 05:59 PM PDT #

Thank you for your example.
I am working, since about 6 months, with JSF + Hibernate, using a abstract facade that provides DB operations for any class that extends it, and my question is: why should I learn a new query specification sintax, why should I use JPA2? I am feeling so good with Hibernate! According to you, what would be the main advantage(s) for me?
Thank you,
Andrew

Posted by Andrew on November 02, 2010 at 07:13 AM PDT #

Andrew,

JPA2 is a standard specification and part of Java EE 6. It does not tie you to a particular implementation or persistence provider or an application provider and keeps your application portable across multiple Java EE 6 applications easily.

Posted by Arun Gupta on November 02, 2010 at 10:19 AM PDT #

I am using NB 7.0.1 and working with GF 3.1.1 on Windows XP SP3. The EclipseLink and EclipseLink-modelgen are present and the metamodel classes have been generated.

I have worked through following this example and the information given in http://download.oracle.com/javaee/6/tutorial/doc/gjivm.html . I am trying to use the CriteriaQuery orderBy. I have established my Root, my Metamodel, and EntityType. However, the EntityType used ( root.get(EntityType_.<column name>) cannot find the column name at all. I am using a primary key, but even using a column name that is not part of the primary key fails. Your example seems simple enough, but the real world use coughs and chokes. Where do I need to do to find resolution to my issue?

Posted by guest on August 08, 2011 at 07:10 AM PDT #

Please follow up on GlassFish forums:

http://www.java.net/forums/glassfish/glassfish

Thanks
-Arun

Posted by Arun on August 08, 2011 at 07:16 AM PDT #

I am using Netbeans 7.2 and JDK 1.6 on Mac Lion to create a maven project that uses queryDSL.

My pom.xml has the following snippets

<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>2.5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-core</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-hibernate-search</artifactId>
<version>2.5.0</version>
</dependency>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/generated</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>

The following pom does not ensure my QueryDSL annotations are processed and the 'Q' classes are created. The same settings are working fine on eclipse.

Any help much appreciated

Nandish

Posted by guest on June 24, 2012 at 02:08 AM PDT #

Great! It's works fine! Thank you very much.

Posted by Daniel Della Savia on September 27, 2012 at 08:57 PM PDT #

Post a Comment:
Comments are closed for this entry.
About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today