Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA Criteria API and type safety

I seem to have missed something in JPA's criteria API and its type safety. Consider the following code:

@Entity
@Access(FIELD)
class User(

  @Id
  Long id;

  @Column(unique=true)
  String email;

  String password;
}

Here the meta model:

@StaticMetamodel(User.class)
public static class User_ {
  public static volatile SingularAttribute<User, Long> id;
  public static volatile SingularAttribute<User, String> email;
  public static volatile SingularAttribute<User, String> password;
}

Then some code to exercise the class, built using pages from the Java EE Tutorial:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> user = cq.from(User.class);
cq.select(user);
cq.where(cb.equal(user.get(User_.email), "[email protected]")); //this line is my problem

TypedQuery<User> q = em.createQuery(cq);
List<User> allUsers = q.getResultList();

assertEquals(1, allUsers.size());

It works fine. However, if I change the "where" clause to use an Integer instead of a String ("[email protected]"), I expected the code to not compile. Yet it compiles fine.

I thought the criteria API was supposed to be type safe? That is hardly more type safe than the following, using standard JPQL. I mean, what is the purpose of the meta model in the above code?? I have gained nothing from it.

User u = em.createQuery("select u from User u where u.email = :email", User.class)
           .setParameter("email", "[email protected]")
       .getSingleResult();

So the question is: can I make the criteria API query more type safe, so that I can only pass a String to the "from" clause?

like image 255
John Smith Avatar asked Aug 21 '12 19:08

John Smith


People also ask

What is JPA Criteria API?

Advertisements. The Criteria API is a predefined API used to define queries for entities. It is the alternative way of defining a JPQL query. These queries are type-safe, and portable and easy to modify by changing the syntax.

What is a criteria API?

The Criteria API is used to define queries for entities and their persistent state by creating query-defining objects. Criteria queries are written using Java programming language APIs, are typesafe, and are portable. Such queries work regardless of the underlying data store.

Is Criteria API deprecated?

The Criteria API allows us to build up a criteria query object programmatically, where we can apply different kinds of filtration rules and logical conditions. Since Hibernate 5.2, the Hibernate Criteria API is deprecated, and new development is focused on the JPA Criteria API.

What is type-safe queries?

Type-safe queries refer to a writing database query statement mechanism that allows developers to verify the correctness of database query statements at compile time. Normally developers write database queries in string literal style therefore compiler has no way to check if the statements are incorrect.


1 Answers

Type safety is restricted to the upper bound of the generic type of the Expression<T> interface, not the exact type defined in the metamodel. So, because CriteriaBuilder.equal(Expression<?> x, java.lang.Object y) takes an argument of type Expression<?> it allows to pass any object for comparison.

The other CriteriaBuiler methods are more type safe, for example CriteriaBuilder.ge(Expression<? extends java.lang.Number> x, Expression<? extends java.lang.Number> y) allows only numbers. But allows to compare an integer field with a float for example.

You can't do better than this. The methods should have been something like CriteriaBuilder.equal(Expression<T> x, T y) with T being the field type from the metamodel.

Of course this is a hole in the type safety of the criteria API. I don't know why the JPA API creators choosed the wildcard version of these methods.

like image 158
dcernahoschi Avatar answered Nov 05 '22 05:11

dcernahoschi