
org.hibernate.processor.validation.Validation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-jpamodelgen Show documentation
Show all versions of hibernate-jpamodelgen Show documentation
Annotation Processor to generate JPA 2 static metamodel classes
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.processor.validation;
import org.antlr.v4.runtime.ANTLRErrorListener;
import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.DefaultErrorStrategy;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.QueryException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.grammars.hql.HqlLexer;
import org.hibernate.grammars.hql.HqlParser;
import org.hibernate.query.hql.internal.HqlParseTreeBuilder;
import org.hibernate.query.hql.internal.SemanticQueryBuilder;
import org.hibernate.query.hql.spi.SqmCreationOptions;
import org.hibernate.query.sqm.EntityTypeException;
import org.hibernate.query.sqm.PathElementException;
import org.hibernate.query.sqm.TerminalPathException;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.type.descriptor.java.spi.JdbcTypeRecommendationException;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import static org.hibernate.processor.validation.ProcessorSessionFactory.getEntityName;
import static org.hibernate.processor.validation.ProcessorSessionFactory.isEntity;
/**
* The entry point for HQL validation.
*
* @author Gavin King
*/
public class Validation {
public interface Handler extends ANTLRErrorListener {
void error(int start, int end, String message);
void warn(int start, int end, String message);
int getErrorCount();
}
public static @Nullable SqmStatement> validate(
String hql,
@Nullable TypeMirror returnType,
boolean checkTyping,
Handler handler,
SessionFactoryImplementor factory) {
return validate( hql, returnType, checkTyping, handler, factory, 0 );
}
public static @Nullable SqmStatement> validate(
String hql,
@Nullable TypeMirror returnType,
boolean checkTyping,
Handler handler,
SessionFactoryImplementor factory,
int errorOffset) {
try {
final HqlParser.StatementContext statementContext = parseAndCheckSyntax( hql, handler );
if ( checkTyping && handler.getErrorCount() == 0 ) {
return checkTyping( hql, returnType, handler, factory, errorOffset, statementContext );
}
}
catch (Exception e) {
// e.printStackTrace();
}
return null;
}
private static @Nullable SqmStatement> checkTyping(
String hql,
@Nullable TypeMirror returnType,
Handler handler,
SessionFactoryImplementor factory,
int errorOffset,
HqlParser.StatementContext statementContext) {
try {
return createSemanticQueryBuilder( returnType, hql, factory ).visitStatement( statementContext );
}
catch ( JdbcTypeRecommendationException ignored ) {
// just squash these for now
}
catch ( QueryException | PathElementException | TerminalPathException | EntityTypeException
| PropertyNotFoundException se ) { //TODO is this one really thrown by core? It should not be!
final String message = se.getMessage();
if ( message != null ) {
handler.error( -errorOffset +1, -errorOffset + hql.length(), message );
}
}
return null;
}
private static final SqmCreationOptions CREATION_OPTIONS = new SqmCreationOptions() {
};
private static SemanticQueryBuilder> createSemanticQueryBuilder(
@Nullable TypeMirror returnType, String hql, SessionFactoryImplementor factory) {
if ( returnType != null && returnType.getKind() == TypeKind.DECLARED ) {
final DeclaredType declaredType = (DeclaredType) returnType;
final TypeElement typeElement = (TypeElement) declaredType.asElement();
final String typeName = typeElement.getQualifiedName().toString();
final String shortName = typeElement.getSimpleName().toString();
return isEntity( typeElement )
? new SemanticQueryBuilder<>( typeName, shortName, getEntityName(typeElement), CREATION_OPTIONS, factory, hql )
: new SemanticQueryBuilder<>( typeName, shortName, Object[].class, CREATION_OPTIONS, factory, hql );
}
else {
return new SemanticQueryBuilder<>( Object[].class, CREATION_OPTIONS, factory, hql );
}
}
private static HqlParser.StatementContext parseAndCheckSyntax(String hql, Handler handler) {
final HqlLexer hqlLexer = HqlParseTreeBuilder.INSTANCE.buildHqlLexer( hql );
final HqlParser hqlParser = HqlParseTreeBuilder.INSTANCE.buildHqlParser( hql, hqlLexer );
hqlLexer.addErrorListener( handler );
hqlParser.getInterpreter().setPredictionMode( PredictionMode.SLL );
hqlParser.removeErrorListeners();
hqlParser.addErrorListener( handler );
hqlParser.setErrorHandler( new BailErrorStrategy() );
try {
return hqlParser.statement();
}
catch ( ParseCancellationException e) {
// reset the input token stream and parser state
hqlLexer.reset();
hqlParser.reset();
// fall back to LL(k)-based parsing
hqlParser.getInterpreter().setPredictionMode( PredictionMode.LL );
hqlParser.setErrorHandler( new DefaultErrorStrategy() );
return hqlParser.statement();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy