Skip to content

Java: How to create type-safe queries using JPA Static Metamodel Generator

Java-How-to-create-type-safe-queries-using-JPA-Static-Metamodel-Generator

JPA Static Metamodel Generator automates the task of metamodel generation to allow constructing typesafe Criteria queries.

For example, consider the Order class defined like this:

@Entity
public class Order {
    @Id
    @GeneratedValue
    Integer id;
    @Column(name = "SERIAL_NO", nullable = false)
    Long serialNo;
    @ManyToOne
    Customer customer;
    @OneToMany
    Set<Item> items;
    BigDecimal totalCost;
    // standard setter/getter methods
    ...
}
@Entity
public class Item {
    @Id
    @GeneratedValue
    Integer id;
    int quantity;
    @ManyToOne
    Order order;
    // standard setter/getter methods
    ...
}

The generated metamodel class of the Order class would be:

@StaticMetamodel(Order.class)
public class Order_ {
    public static volatile SingularAttribute<Order, Integer> id;
    public static volatile SingularAttribute<Order, Long> serialNo;
    public static volatile SingularAttribute<Order, Customer> customer;
    public static volatile SetAttribute<Order, Item> items;
    public static volatile SingularAttribute<Order, BigDecimal> totalCost;
    public static final String ID = "id";
    public static final String SERIAL_NO = "serialNo";
    public static final String CUSTOMER = "customer";
    public static final String ITEMS = "items";
    public static final String TOTAL_COST = "totalCost";
}

And the typesafe criteria query would be written like this:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
SetJoin<Order, Item> itemNode = cq.from(Order.class).join(Order_.items);
cq.where( cb.equal(itemNode.get(Item_.id), 5 ) ).distinct(true);

How to use the JPA Metamodel generator?

The annotation processor will automatically run once you include the processor jar in the Maven repository by including the following dependency in your pom.xml file.

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jpamodelgen</artifactId>
    <version>CURRENT-VERSION</version>
</dependency>

How to use the JPA Static Metamodel Generated classes for writing typesafe native queries?

The createNativeQuery method of EntityManager can be used to write native queries as below:

Query q = entityManager.createNativeQuery("SELECT o. FROM Order o");
List<Object[]> authors = q.getResultList();

When writing native SQL statements in the code, we can use reflection to get the table name and field names. For example, the following utility class does this. For the getColumnName method, the fieldName parameter can be provided using the JPA static metamodel generated classes, such as Order_.SERIAL_NO.

import javax.persistence.Column;
import javax.persistence.Table;
import com.google.common.base.CaseFormat;
public class UtilityClass {
	public static String getTableName(Class<?> clazz) {
		return clazz.getAnnotation(Table.class).name();
	}
	
	public static String getColumnName(Class<?> clazz, String fieldName) {
		String field = null;
		try {
			field = clazz.getDeclaredField(fieldName).
					getAnnotation(Column.class).
					name();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		
		if (field == null || field.isEmpty()) {
                        // convert camelcase to underscore-separated case
			field = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName);
		}
		return field;
	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *


The reCAPTCHA verification period has expired. Please reload the page.