From dc1073e2121b9d94490f568ff1285013c50bdb15 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 20 Jun 2016 15:16:52 +0200 Subject: [PATCH] HHH-10861 - Fix nullLiteral in select expression (cherry picked from commit 597183a3b9f375b525eda3227538f3aff4031f14) Conflicts: hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/expression/NullLiteralExpression.java (cherry picked from commit 4f469686001cffaf121409eed6f881900a842038) --- hibernate-core/src/main/antlr/hql-sql.g | 2 +- .../hql/internal/ast/SqlASTFactory.java | 4 ++ .../hql/internal/ast/tree/NullNode.java | 38 +++++++++++++++++++ .../internal/ast/util/LiteralProcessor.java | 4 ++ .../internal/util/ReflectHelper.java | 18 ++++++--- .../expression/NullLiteralExpression.java | 3 +- 6 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/NullNode.java diff --git a/hibernate-core/src/main/antlr/hql-sql.g b/hibernate-core/src/main/antlr/hql-sql.g index b2303bd527..5172ed1077 100644 --- a/hibernate-core/src/main/antlr/hql-sql.g +++ b/hibernate-core/src/main/antlr/hql-sql.g @@ -685,7 +685,7 @@ functionCall constant : literal | NULL - | TRUE { processBoolean(#constant); } + | TRUE { processBoolean(#constant); } | FALSE { processBoolean(#constant); } | JAVA_CONSTANT ; diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/SqlASTFactory.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/SqlASTFactory.java index 631a49f940..acf4146b1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/SqlASTFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/SqlASTFactory.java @@ -15,6 +15,7 @@ import org.hibernate.hql.internal.ast.tree.BinaryArithmeticOperatorNode; import org.hibernate.hql.internal.ast.tree.BinaryLogicOperatorNode; import org.hibernate.hql.internal.ast.tree.BooleanLiteralNode; import org.hibernate.hql.internal.ast.tree.CastFunctionNode; +import org.hibernate.hql.internal.ast.tree.NullNode; import org.hibernate.hql.internal.ast.tree.SearchedCaseNode; import org.hibernate.hql.internal.ast.tree.SimpleCaseNode; import org.hibernate.hql.internal.ast.tree.CollectionFunction; @@ -192,6 +193,9 @@ public class SqlASTFactory extends ASTFactory implements HqlSqlTokenTypes { case ENTRY: { return MapEntryNode.class; } + case NULL : { + return NullNode.class; + } default: return SqlNode.class; } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/NullNode.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/NullNode.java new file mode 100644 index 0000000000..bd37e72c79 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/NullNode.java @@ -0,0 +1,38 @@ +/* + * 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.hql.internal.ast.tree; + +import antlr.SemanticException; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.hql.internal.ast.util.ColumnHelper; +import org.hibernate.type.Type; + +/** + * @author Andrea Boriero + */ +public class NullNode extends AbstractSelectExpression { + + public Type getDataType() { + return null; + } + + @Override + public void setScalarColumnText(int i) throws SemanticException { + ColumnHelper.generateSingleScalarColumn( this, i ); + } + + public Object getValue() { + return null; + } + + @Override + @SuppressWarnings({"unchecked"}) + public String getRenderText(SessionFactoryImplementor sessionFactory) { + return "null"; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/util/LiteralProcessor.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/util/LiteralProcessor.java index 1b994ec616..e5da5ee836 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/util/LiteralProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/util/LiteralProcessor.java @@ -191,6 +191,10 @@ public class LiteralProcessor implements HqlSqlTokenTypes { } } + public void processNull(AST constant) { + constant.setText( "null" ); + } + private void processLiteral(AST constant) { String replacement = (String) walker.getTokenReplacements().get( constant.getText() ); if ( replacement != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java index 6954c0fa33..d7116f5077 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java @@ -301,12 +301,14 @@ public final class ReflectHelper { */ public static Constructor getConstructor(Class clazz, Type[] types) throws PropertyNotFoundException { final Constructor[] candidates = clazz.getConstructors(); - for ( final Constructor constructor : candidates ) { - final Class[] params = constructor.getParameterTypes(); + Constructor constructor = null; + int numberOfMatchingConstructors = 0; + for ( final Constructor candidate : candidates ) { + final Class[] params = candidate.getParameterTypes(); if ( params.length == types.length ) { boolean found = true; for ( int j = 0; j < params.length; j++ ) { - final boolean ok = params[j].isAssignableFrom( types[j].getReturnedClass() ) || ( + final boolean ok = types[j] == null || params[j].isAssignableFrom( types[j].getReturnedClass() ) || ( types[j] instanceof PrimitiveType && params[j] == ( (PrimitiveType) types[j] ).getPrimitiveClass() ); @@ -316,12 +318,18 @@ public final class ReflectHelper { } } if ( found ) { - constructor.setAccessible( true ); - return constructor; + numberOfMatchingConstructors ++; + candidate.setAccessible( true ); + constructor = candidate; } } } + + if ( numberOfMatchingConstructors == 1 ) { + return constructor; + } throw new PropertyNotFoundException( "no appropriate constructor in class: " + clazz.getName() ); + } public static Method getMethod(Class clazz, Method method) { diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/expression/NullLiteralExpression.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/expression/NullLiteralExpression.java index ecb162c7c4..4cf290e118 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/expression/NullLiteralExpression.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/criteria/expression/NullLiteralExpression.java @@ -11,6 +11,7 @@ import java.io.Serializable; import org.hibernate.jpa.criteria.CriteriaBuilderImpl; import org.hibernate.jpa.criteria.ParameterRegistry; import org.hibernate.jpa.criteria.compile.RenderingContext; +import org.hibernate.jpa.criteria.expression.function.CastFunction; /** * Represents a NULLliteral expression. @@ -27,7 +28,7 @@ public class NullLiteralExpression extends ExpressionImpl implements Seria } public String render(RenderingContext renderingContext) { - return "null"; + return CastFunction.CAST_NAME + "( null as " + renderingContext.getCastType( getJavaType() ) + ')'; } public String renderProjection(RenderingContext renderingContext) {