HHH-4203 - Implement JPA 2.0 criteria apis (compiling)

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17772 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2009-10-16 00:50:22 +00:00
parent 7daebe4992
commit 694a694d5d
4 changed files with 122 additions and 47 deletions

View File

@ -42,7 +42,7 @@ import javax.persistence.Query;
import javax.persistence.TransactionRequiredException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.QueryBuilder;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.transaction.Status;
@ -72,6 +72,7 @@ import org.hibernate.UnresolvableObjectException;
import org.hibernate.cfg.Environment;
import org.hibernate.ejb.transaction.JoinableCMTTransaction;
import org.hibernate.ejb.util.ConfigurationHelper;
import org.hibernate.ejb.criteria.CriteriaQueryCompiler;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.proxy.HibernateProxy;
@ -148,38 +149,13 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
}
}
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
// TODO-STEVE : here is the interpretation/compilation portion.
// One option is to build on top of the existing
// org.hibernate.loader.custom.CustomQuery infastructure
// (which is how native sql queries are implemented e.g.).
// If so, then here we could interpret the criteria into
// a CustomQuery instance which is passed into the
// Query instance returned here. We would then call into
// the various SessionImplementor methods for execution
// such as #listCustomQuery and #scrollCustomQuery.
//
// The drawback to this (^^) approach is that CustomQuery +
// SessionImplementor combo does not support #executeUpdate
// processing...
throw new UnsupportedOperationException( "Not yet implemented!" );
}
private CriteriaQueryCompiler criteriaQueryCompiler;
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery, Class<T> resultClass) {
// TODO-STEVE : here is the interpretation/compilation portion.
// One option is to build on top of the existing
// org.hibernate.loader.custom.CustomQuery infastructure
// (which is how native sql queries are implemented e.g.).
// If so, then here we could interpret the criteria into
// a CustomQuery instance which is passed into the
// Query instance returned here. We would then call into
// the various SessionImplementor methods for execution
// such as #listCustomQuery and #scrollCustomQuery.
//
// The drawback to this (^^) approach is that CustomQuery +
// SessionImplementor combo does not support #executeUpdate
// processing...
throw new UnsupportedOperationException( "Not yet implemented!" );
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
if ( criteriaQueryCompiler == null ) {
criteriaQueryCompiler = new CriteriaQueryCompiler( this );
}
return criteriaQueryCompiler.compile( criteriaQuery );
}
public Query createNamedQuery(String name) {
@ -481,8 +457,8 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
/**
* {@inheritDoc}
*/
public QueryBuilder getQueryBuilder() {
return getEntityManagerFactory().getQueryBuilder();
public CriteriaBuilder getCriteriaBuilder() {
return getEntityManagerFactory().getCriteriaBuilder();
}
/**
@ -672,13 +648,13 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
}
catch ( SystemException se ) {
log.error( "could not determine transaction status", se );
//throwPersistenceException will mark the transaction as rollbacked
throwPersistenceException(
new PersistenceException(
"could not determine transaction status in beforeCompletion()",
se
)
PersistenceException pe = new PersistenceException(
"could not determine transaction status in beforeCompletion()",
se
);
// handlePersistenceException will mark the transaction as rollbacked
handlePersistenceException( pe );
throw pe;
}
catch ( HibernateException he ) {
throwPersistenceException( he );

View File

@ -21,8 +21,6 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
//$Id$
package org.hibernate.ejb;
import java.util.Calendar;
@ -150,7 +148,7 @@ public class QueryImpl<X> extends org.hibernate.ejb.AbstractQueryImpl<X> impleme
return position;
}
public Class getJavaType() {
public Class getParameterType() {
return javaType;
}
}
@ -521,10 +519,10 @@ public class QueryImpl<X> extends org.hibernate.ejb.AbstractQueryImpl<X> impleme
@SuppressWarnings({ "unchecked" })
public <T> Parameter<T> getParameter(String name, Class<T> type) {
Parameter param = getParameter( name );
if ( param.getJavaType() != null ) {
if ( param.getParameterType() != null ) {
// we were able to determine the expected type during analysis, so validate it here
throw new IllegalArgumentException(
"Parameter type [" + param.getJavaType().getName() +
"Parameter type [" + param.getParameterType().getName() +
"] is not assignment compatible with requested type [" +
type.getName() + "]"
);
@ -538,10 +536,10 @@ public class QueryImpl<X> extends org.hibernate.ejb.AbstractQueryImpl<X> impleme
@SuppressWarnings({ "unchecked" })
public <T> Parameter<T> getParameter(int position, Class<T> type) {
Parameter param = getParameter( position );
if ( param.getJavaType() != null ) {
if ( param.getParameterType() != null ) {
// we were able to determine the expected type during analysis, so validate it here
throw new IllegalArgumentException(
"Parameter type [" + param.getJavaType().getName() +
"Parameter type [" + param.getParameterType().getName() +
"] is not assignment compatible with requested type [" +
type.getName() + "]"
);

View File

@ -0,0 +1,61 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @author tags or express
* copyright attribution statements applied by the authors. All
* third-party contributions are distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.ejb.criteria;
import java.util.Set;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import org.hibernate.ejb.HibernateEntityManagerImplementor;
/**
* Compiles a JPA criteria query into an executable {@link TypedQuery}. Its single contract is the {@link #compile}
* method.
* <p/>
* NOTE : This is a temporay implementation which simply translates the criteria query into a JPAQL query string. A
* better, long-term solution is being implemented as part of refactoring the JPAQL/HQL translator.
*
* @author Steve Ebersole
*/
public class CriteriaQueryCompiler {
private final HibernateEntityManagerImplementor entityManager;
public CriteriaQueryCompiler(HibernateEntityManagerImplementor entityManager) {
this.entityManager = entityManager;
}
public <T> TypedQuery<T> compile(CriteriaQuery<T> criteriaQuery) {
CriteriaQueryImpl<T> criteriaQueryImpl = ( CriteriaQueryImpl<T> ) criteriaQuery;
criteriaQueryImpl.validate();
Set<ParameterExpression<?>> explicitParameters = criteriaQueryImpl.getParameters();
// todo : implicit parameter handling (handling literal as param, etc).
String jpaqlEquivalent = criteriaQueryImpl.render();
return null;
}
}

View File

@ -293,4 +293,44 @@ public class CriteriaQueryImpl<T> extends AbstractNode implements CriteriaQuery<
return queryStructure.subquery( subqueryType );
}
public void validate() {
// getRoots() is explicitly supposed to return empty if none defined, no need to check for null
if ( getRoots().isEmpty() ) {
throw new IllegalStateException( "No criteria query roots were specified" );
}
// if there is not an explicit selection, there is an *implicit* selection of the root entity provided only
// a single query root was defined.
if ( getSelection() == null && !hasImplicitSelection() ) {
throw new IllegalStateException( "No explicit selection and an implicit one cold not be determined" );
}
}
/**
* If no explicit selection was defined, we have a condition called an implicit selection if the query specified
* a single {@link Root} and the java type of that {@link Root root's} model is the same as this criteria's
* {@link #getResultType() result type}.
*
* @return True if there is an explicit selection; false otherwise.
*/
private boolean hasImplicitSelection() {
if ( getRoots().size() != 1 ) {
return false;
}
Root root = getRoots().iterator().next();
if ( root.getModel().getJavaType() != returnType ) {
return false;
}
// if we get here, the query defined no selection but defined a single root of the same type as the
// criteria query return, so we use that as the implicit selection
//
// todo : should we put an implicit marker in the selection to this fact to make later processing easier?
return true;
}
public String render() {
return null;
}
}