It would be easiest to sort and get the first record. The JPA query would look something like this.
Code:
//Obtain entity manager
EntityManager em = ...
//Required item ID
int id = ...
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<StateChange> query = builder.createQuery(StateChange.class);
Root<StateChange> root = query.from(StateChange.class);
query.where(builder.isNotNull(root.get("date")), builder.equal(root.get("itemId"), id));
query.select(root);
query.orderBy(builder.desc(root.get("date")));
StateChange p = em.createQuery(query).setMaxResults(1).getSingleResult();
Another approach is selecting the maximum date, then selecting the entity that matches this date.
Code:
//Obtain entity manager
EntityManager em = ...
//Required item ID.
int id = ...;
CriteriaBuilder builder = em.getCriteriaBuilder();
EntityType<StateChange> type = em.getMetamodel().entity(StateChange.class);
//Select the max value of date from the StateChange entity
//where the ID matches the required ID and the date is not null (ANSI requirement, prevent aggregating null values).
CriteriaQuery<Date> query1 = builder.createQuery(Date.class);
Root<StateChange> root1 = query1.from(StateChange.class);
Expression<Date> maxDateExpression = builder.greatest(root1.get(type.getDeclaredSingularAttribute("date", Date.class)));
Expression<Date> thisDateExpression = root1.get("date");
query1.select(maxDateExpression);
query1.where(builder.isNotNull(thisDateExpression), builder.equal(root1.get("itemId"), id));
Date maxDate = em.createQuery(query1).getSingleResult();
//We have found the highest date for the provided ID. Select the StateChange that matches the maximum date.
CriteriaQuery<StateChange> query2 = builder.createQuery(StateChange.class);
Root<StateChange> root2 = query2.from(StateChange.class);
query2.where(builder.equal(root2.get("date"), maxDate), builder.equal(root2.get("itemId"), id));
query2.select(root2);
StateChange p = em.createQuery(query2).setMaxResults(1).getSingleResult();
Wouldn't know how to put this in one query though.