HHH-6916 - Not proper array-handling in AbstractQueryImpl.registerParameterBinding
This commit is contained in:
parent
e18d087592
commit
097e157329
|
@ -1,6 +1,8 @@
|
||||||
import org.apache.tools.ant.filters.ReplaceTokens
|
import org.apache.tools.ant.filters.ReplaceTokens
|
||||||
|
|
||||||
|
apply plugin: 'java'
|
||||||
apply plugin: "jdocbook"
|
apply plugin: "jdocbook"
|
||||||
|
apply plugin: org.hibernate.gradle.testing.matrix.MatrixTestingPlugin
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -14,27 +16,6 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
jdocbookStyles "org.hibernate:hibernate-jdocbook-style:2.0.1"
|
|
||||||
}
|
|
||||||
|
|
||||||
jdocbook {
|
|
||||||
format('html_single') {
|
|
||||||
finalName = "index.html"
|
|
||||||
stylesheet = "classpath:/xslt/org/hibernate/jdocbook/xslt/xhtml-single.xsl"
|
|
||||||
}
|
|
||||||
format('html') {
|
|
||||||
finalName = "index.html"
|
|
||||||
stylesheet = "classpath:/xslt/org/hibernate/jdocbook/xslt/xhtml.xsl"
|
|
||||||
}
|
|
||||||
masterSourceDocumentName="master.xml"
|
|
||||||
masterLanguage="en"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: 'java'
|
|
||||||
apply plugin: org.hibernate.gradle.testing.matrix.MatrixTestingPlugin
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
|
|
||||||
compile( project(':hibernate-core') )
|
compile( project(':hibernate-core') )
|
||||||
compile( libraries.dom4j )
|
compile( libraries.dom4j )
|
||||||
compile( libraries.commons_annotations )
|
compile( libraries.commons_annotations )
|
||||||
|
@ -47,16 +28,9 @@ dependencies {
|
||||||
testCompile( libraries.shrinkwrap )
|
testCompile( libraries.shrinkwrap )
|
||||||
testCompile( libraries.validation )
|
testCompile( libraries.validation )
|
||||||
testRuntime( libraries.validator )
|
testRuntime( libraries.validator )
|
||||||
|
jdocbookStyles "org.hibernate:hibernate-jdocbook-style:2.0.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
aptDumpDir = file( buildDirName + "/tmp/apt" )
|
|
||||||
|
|
||||||
sourceSets.test {
|
|
||||||
originalJavaSrcDirs = java.srcDirs
|
|
||||||
generatedJpaMetamodelSrcDir = file( "${buildDir}/generated-src/jpamodelgen/${name}" )
|
|
||||||
java.srcDir generatedJpaMetamodelSrcDir
|
|
||||||
}
|
|
||||||
compileMatrixJava.options.define(compilerArgs: ["-proc:none", "-encoding", "UTF-8"])
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
matrix {
|
matrix {
|
||||||
java {
|
java {
|
||||||
|
@ -67,13 +41,21 @@ sourceSets {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ideaModule {
|
|
||||||
excludeDirs += file("$buildDir/bundles")
|
|
||||||
testSourceDirs += file( 'src/matrix/java')
|
|
||||||
testSourceDirs += file( 'src/matrix/resources')
|
|
||||||
}
|
|
||||||
|
|
||||||
task generateJpaMetamodelClasses(type: Compile) {
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// JPA model-gen set up
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
aptDumpDir = file( buildDirName + "/tmp/apt" )
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 'test' sourceSet specific JPA model-gen set up
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
sourceSets.test {
|
||||||
|
originalJavaSrcDirs = java.srcDirs
|
||||||
|
generatedJpaMetamodelSrcDir = file( "${buildDir}/generated-src/jpamodelgen/${name}" )
|
||||||
|
java.srcDir generatedJpaMetamodelSrcDir
|
||||||
|
}
|
||||||
|
task generateTestJpaMetamodelClasses(type: Compile) {
|
||||||
classpath = compileTestJava.classpath + configurations.hibernateJpaModelGenTool
|
classpath = compileTestJava.classpath + configurations.hibernateJpaModelGenTool
|
||||||
source = sourceSets.test.originalJavaSrcDirs
|
source = sourceSets.test.originalJavaSrcDirs
|
||||||
destinationDir = aptDumpDir
|
destinationDir = aptDumpDir
|
||||||
|
@ -89,13 +71,41 @@ task generateJpaMetamodelClasses(type: Compile) {
|
||||||
sourceSets.test.generatedJpaMetamodelSrcDir.mkdirs()
|
sourceSets.test.generatedJpaMetamodelSrcDir.mkdirs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for the time being eat the annoying output from running the annotation processors
|
// for the time being eat the annoying output from running the annotation processors
|
||||||
generateJpaMetamodelClasses.logging.captureStandardError(LogLevel.INFO)
|
generateTestJpaMetamodelClasses.logging.captureStandardError(LogLevel.INFO)
|
||||||
|
compileTestJava.dependsOn generateTestJpaMetamodelClasses
|
||||||
compileTestJava.dependsOn generateJpaMetamodelClasses
|
|
||||||
compileTestJava.options.define(compilerArgs: ["-proc:none"])
|
compileTestJava.options.define(compilerArgs: ["-proc:none"])
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 'matrix' sourceSet specific JPA model-gen set up
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
sourceSets.matrix {
|
||||||
|
originalJavaSrcDirs = java.srcDirs
|
||||||
|
generatedJpaMetamodelSrcDir = file( "${buildDir}/generated-src/jpamodelgen/${name}" )
|
||||||
|
java.srcDir generatedJpaMetamodelSrcDir
|
||||||
|
}
|
||||||
|
task generateMatrixJpaMetamodelClasses(type: Compile) {
|
||||||
|
classpath = compileMatrixJava.classpath + configurations.hibernateJpaModelGenTool
|
||||||
|
source = sourceSets.matrix.java
|
||||||
|
destinationDir = aptDumpDir
|
||||||
|
options.define(
|
||||||
|
compilerArgs: [
|
||||||
|
"-proc:only",
|
||||||
|
"-processor", "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor",
|
||||||
|
"-s", "$sourceSets.matrix.generatedJpaMetamodelSrcDir.absolutePath"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
outputs.dir sourceSets.matrix.generatedJpaMetamodelSrcDir;
|
||||||
|
doFirst {
|
||||||
|
sourceSets.matrix.generatedJpaMetamodelSrcDir.mkdirs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for the time being eat the annoying output from running the annotation processors
|
||||||
|
generateMatrixJpaMetamodelClasses.logging.captureStandardError(LogLevel.INFO)
|
||||||
|
compileMatrixJava.dependsOn generateMatrixJpaMetamodelClasses
|
||||||
|
compileMatrixJava.options.define(compilerArgs: ["-proc:none", "-encoding", "UTF-8"])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bundlesTargetDir = file( "$buildDirName/bundles" )
|
bundlesTargetDir = file( "$buildDirName/bundles" )
|
||||||
task copyBundleResources (type: Copy) {
|
task copyBundleResources (type: Copy) {
|
||||||
|
@ -116,3 +126,22 @@ task copyBundleResources (type: Copy) {
|
||||||
|
|
||||||
// make sure that the bundles for the packaged test (PackagingTestCase) are copied as well
|
// make sure that the bundles for the packaged test (PackagingTestCase) are copied as well
|
||||||
processTestResources.dependsOn copyBundleResources
|
processTestResources.dependsOn copyBundleResources
|
||||||
|
|
||||||
|
jdocbook {
|
||||||
|
format('html_single') {
|
||||||
|
finalName = "index.html"
|
||||||
|
stylesheet = "classpath:/xslt/org/hibernate/jdocbook/xslt/xhtml-single.xsl"
|
||||||
|
}
|
||||||
|
format('html') {
|
||||||
|
finalName = "index.html"
|
||||||
|
stylesheet = "classpath:/xslt/org/hibernate/jdocbook/xslt/xhtml.xsl"
|
||||||
|
}
|
||||||
|
masterSourceDocumentName="master.xml"
|
||||||
|
masterLanguage="en"
|
||||||
|
}
|
||||||
|
|
||||||
|
ideaModule {
|
||||||
|
excludeDirs += file("$buildDir/bundles")
|
||||||
|
testSourceDirs += file( 'src/matrix/java')
|
||||||
|
testSourceDirs += file( 'src/matrix/resources')
|
||||||
|
}
|
|
@ -22,25 +22,20 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.ejb;
|
package org.hibernate.ejb;
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_CACHEABLE;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_CACHE_MODE;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_CACHE_REGION;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_COMMENT;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_FETCH_SIZE;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_FLUSH_MODE;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_READONLY;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_TIMEOUT;
|
|
||||||
import static org.hibernate.ejb.QueryHints.SPEC_HINT_TIMEOUT;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.persistence.CacheRetrieveMode;
|
import javax.persistence.CacheRetrieveMode;
|
||||||
import javax.persistence.CacheStoreMode;
|
import javax.persistence.CacheStoreMode;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
import javax.persistence.TransactionRequiredException;
|
import javax.persistence.TransactionRequiredException;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
@ -51,7 +46,16 @@ import org.hibernate.ejb.util.CacheModeHelper;
|
||||||
import org.hibernate.ejb.util.ConfigurationHelper;
|
import org.hibernate.ejb.util.ConfigurationHelper;
|
||||||
import org.hibernate.ejb.util.LockModeTypeHelper;
|
import org.hibernate.ejb.util.LockModeTypeHelper;
|
||||||
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_CACHEABLE;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_CACHE_MODE;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_CACHE_REGION;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_COMMENT;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_FETCH_SIZE;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_FLUSH_MODE;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_READONLY;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_TIMEOUT;
|
||||||
|
import static org.hibernate.ejb.QueryHints.SPEC_HINT_TIMEOUT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intended as a base class providing convenience in implementing both {@link javax.persistence.Query} and
|
* Intended as a base class providing convenience in implementing both {@link javax.persistence.Query} and
|
||||||
|
@ -84,9 +88,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
*/
|
*/
|
||||||
protected abstract int internalExecuteUpdate();
|
protected abstract int internalExecuteUpdate();
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({ "ThrowableInstanceNeverThrown" })
|
@SuppressWarnings({ "ThrowableInstanceNeverThrown" })
|
||||||
public int executeUpdate() {
|
public int executeUpdate() {
|
||||||
try {
|
try {
|
||||||
|
@ -117,9 +119,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
*/
|
*/
|
||||||
protected abstract void applyMaxResults(int maxResults);
|
protected abstract void applyMaxResults(int maxResults);
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public TypedQuery<X> setMaxResults(int maxResult) {
|
public TypedQuery<X> setMaxResults(int maxResult) {
|
||||||
if ( maxResult < 0 ) {
|
if ( maxResult < 0 ) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -135,6 +135,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
return maxResults;
|
return maxResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxResults() {
|
public int getMaxResults() {
|
||||||
return maxResults == -1
|
return maxResults == -1
|
||||||
? Integer.MAX_VALUE // stupid spec... MAX_VALUE??
|
? Integer.MAX_VALUE // stupid spec... MAX_VALUE??
|
||||||
|
@ -150,6 +151,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
*/
|
*/
|
||||||
protected abstract void applyFirstResult(int firstResult);
|
protected abstract void applyFirstResult(int firstResult);
|
||||||
|
|
||||||
|
@Override
|
||||||
public TypedQuery<X> setFirstResult(int firstResult) {
|
public TypedQuery<X> setFirstResult(int firstResult) {
|
||||||
if ( firstResult < 0 ) {
|
if ( firstResult < 0 ) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -161,15 +163,14 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getFirstResult() {
|
public int getFirstResult() {
|
||||||
return firstResult;
|
return firstResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> hints;
|
private Map<String, Object> hints;
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public Map<String, Object> getHints() {
|
public Map<String, Object> getHints() {
|
||||||
return hints;
|
return hints;
|
||||||
}
|
}
|
||||||
|
@ -194,9 +195,8 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
|
|
||||||
protected abstract void applyAliasSpecificLockMode(String alias, LockMode lockMode);
|
protected abstract void applyAliasSpecificLockMode(String alias, LockMode lockMode);
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
@SuppressWarnings( {"deprecation"})
|
||||||
*/
|
|
||||||
public TypedQuery<X> setHint(String hintName, Object value) {
|
public TypedQuery<X> setHint(String hintName, Object value) {
|
||||||
boolean skipped = false;
|
boolean skipped = false;
|
||||||
try {
|
try {
|
||||||
|
@ -294,16 +294,20 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
public Set<String> getSupportedHints() {
|
public Set<String> getSupportedHints() {
|
||||||
return QueryHints.getDefinedHints();
|
return QueryHints.getDefinedHints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public abstract TypedQuery<X> setLockMode(javax.persistence.LockModeType lockModeType);
|
public abstract TypedQuery<X> setLockMode(javax.persistence.LockModeType lockModeType);
|
||||||
|
|
||||||
|
@Override
|
||||||
public abstract javax.persistence.LockModeType getLockMode();
|
public abstract javax.persistence.LockModeType getLockMode();
|
||||||
|
|
||||||
private FlushModeType jpaFlushMode;
|
private FlushModeType jpaFlushMode;
|
||||||
|
|
||||||
|
@Override
|
||||||
public TypedQuery<X> setFlushMode(FlushModeType jpaFlushMode) {
|
public TypedQuery<X> setFlushMode(FlushModeType jpaFlushMode) {
|
||||||
this.jpaFlushMode = jpaFlushMode;
|
this.jpaFlushMode = jpaFlushMode;
|
||||||
// TODO : treat as hint?
|
// TODO : treat as hint?
|
||||||
|
@ -316,10 +320,12 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
protected FlushModeType getSpecifiedFlushMode() {
|
protected FlushModeType getSpecifiedFlushMode() {
|
||||||
return jpaFlushMode;
|
return jpaFlushMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public FlushModeType getFlushMode() {
|
public FlushModeType getFlushMode() {
|
||||||
return jpaFlushMode != null
|
return jpaFlushMode != null
|
||||||
? jpaFlushMode
|
? jpaFlushMode
|
||||||
|
@ -328,57 +334,112 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
|
|
||||||
private Map parameterBindings;
|
private Map parameterBindings;
|
||||||
|
|
||||||
|
@SuppressWarnings( {"unchecked"})
|
||||||
protected void registerParameterBinding(Parameter parameter, Object value) {
|
protected void registerParameterBinding(Parameter parameter, Object value) {
|
||||||
if ( value != null && parameter.getParameterType() != null ) {
|
if ( parameter == null ) {
|
||||||
if ( Collection.class.isInstance( value ) ) {
|
throw new IllegalArgumentException( "parameter cannot be null" );
|
||||||
final Collection collection = (Collection) value;
|
|
||||||
// validate the elements...
|
|
||||||
for ( Object element : collection ) {
|
|
||||||
if ( ! parameter.getParameterType().isInstance( element ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameter value [" + element + "] was not matching type [" +
|
|
||||||
parameter.getParameterType().getName() + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( value.getClass().isArray() && value.getClass().equals( Object[].class ) ) {
|
|
||||||
final Object[] array = (Object[]) value;
|
|
||||||
for ( Object element : array ) {
|
|
||||||
if ( ! parameter.getParameterType().isInstance( element ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameter value [" + element + "] was not matching type [" +
|
|
||||||
parameter.getParameterType().getName() + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( ! parameter.getParameterType().isInstance( value ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameter value [" + value + "] was not matching type [" +
|
|
||||||
parameter.getParameterType().getName() + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateParameterBinding( parameter, value );
|
||||||
|
|
||||||
if ( parameterBindings == null ) {
|
if ( parameterBindings == null ) {
|
||||||
parameterBindings = new HashMap();
|
parameterBindings = new HashMap();
|
||||||
}
|
}
|
||||||
parameterBindings.put( parameter, value );
|
parameterBindings.put( parameter, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void validateParameterBinding(Parameter parameter, Object value) {
|
||||||
* {@inheritDoc}
|
if ( value == null || parameter.getParameterType() == null ) {
|
||||||
*/
|
// nothing we can check
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Collection.class.isInstance( value )
|
||||||
|
&& ! Collection.class.isAssignableFrom( parameter.getParameterType() ) ) {
|
||||||
|
// we have a collection passed in where we are expecting a non-collection.
|
||||||
|
// NOTE : this can happen in Hibernate's notion of "parameter list" binding
|
||||||
|
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
|
||||||
|
// will fall through to the main check.
|
||||||
|
validateCollectionValuedParameterMultiBinding( parameter, (Collection) value );
|
||||||
|
}
|
||||||
|
else if ( value.getClass().isArray() ) {
|
||||||
|
validateArrayValuedParameterBinding( parameter, value );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( ! parameter.getParameterType().isInstance( value ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Parameter value [%s] did not match expected type [%s]",
|
||||||
|
value,
|
||||||
|
parameter.getParameterType().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateCollectionValuedParameterMultiBinding(Parameter parameter, Collection value) {
|
||||||
|
// validate the elements...
|
||||||
|
for ( Object element : value ) {
|
||||||
|
if ( ! parameter.getParameterType().isInstance( element ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Parameter value element [%s] did not match expected type [%s]",
|
||||||
|
element,
|
||||||
|
parameter.getParameterType().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateArrayValuedParameterBinding(Parameter parameter, Object value) {
|
||||||
|
if ( ! parameter.getParameterType().isArray() ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Encountered array-valued parameter binding, but was expecting [%s]",
|
||||||
|
parameter.getParameterType().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value.getClass().getComponentType().isPrimitive() ) {
|
||||||
|
// we have a primitive array. we validate that the actual array has the component type (type odf elements)
|
||||||
|
// we expect based on the component type of the parameter specification
|
||||||
|
if ( ! parameter.getParameterType().getComponentType().isAssignableFrom( value.getClass().getComponentType() ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Primitive array-valued parameter bind value type [%s] did not match expected type [%s]",
|
||||||
|
value.getClass().getComponentType().getName(),
|
||||||
|
parameter.getParameterType().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we have an object array. Here we loop over the array and physically check each element against
|
||||||
|
// the type we expect based on the component type of the parameter specification
|
||||||
|
final Object[] array = (Object[]) value;
|
||||||
|
for ( Object element : array ) {
|
||||||
|
if ( ! parameter.getParameterType().getComponentType().isInstance( element ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Array-valued parameter value element [%s] did not match expected type [%s]",
|
||||||
|
element,
|
||||||
|
parameter.getParameterType().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isBound(Parameter<?> param) {
|
public boolean isBound(Parameter<?> param) {
|
||||||
return parameterBindings != null && parameterBindings.containsKey( param );
|
return parameterBindings != null && parameterBindings.containsKey( param );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public <T> T getParameterValue(Parameter<T> param) {
|
public <T> T getParameterValue(Parameter<T> param) {
|
||||||
if ( parameterBindings == null ) {
|
if ( parameterBindings == null ) {
|
||||||
|
@ -396,16 +457,12 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public Object getParameterValue(String name) {
|
public Object getParameterValue(String name) {
|
||||||
return getParameterValue( getParameter( name ) );
|
return getParameterValue( getParameter( name ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public Object getParameterValue(int position) {
|
public Object getParameterValue(int position) {
|
||||||
return getParameterValue( getParameter( position ) );
|
return getParameterValue( getParameter( position ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @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 javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity with multiple attributes of basic type for use in testing using those types/attributes
|
||||||
|
* in queries.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class MultiTypedBasicAttributesEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue( generator = "increment" )
|
||||||
|
@GenericGenerator( name = "increment", strategy = "increment" )
|
||||||
|
private Long id;
|
||||||
|
private byte[] someBytes;
|
||||||
|
private Byte[] someWrappedBytes;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getSomeBytes() {
|
||||||
|
return someBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSomeBytes(byte[] someBytes) {
|
||||||
|
this.someBytes = someBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Byte[] getSomeWrappedBytes() {
|
||||||
|
return someWrappedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSomeWrappedBytes(Byte[] someWrappedBytes) {
|
||||||
|
this.someWrappedBytes = someWrappedBytes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @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 javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.Parameter;
|
||||||
|
import javax.persistence.TypedQuery;
|
||||||
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
import javax.persistence.criteria.ParameterExpression;
|
||||||
|
import javax.persistence.criteria.Path;
|
||||||
|
import javax.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ParameterTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrimitiveArrayParameterBinding() {
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
CriteriaQuery<MultiTypedBasicAttributesEntity> criteria = em.getCriteriaBuilder()
|
||||||
|
.createQuery( MultiTypedBasicAttributesEntity.class );
|
||||||
|
Root<MultiTypedBasicAttributesEntity> rootEntity = criteria.from( MultiTypedBasicAttributesEntity.class );
|
||||||
|
Path<byte[]> someBytesPath = rootEntity.get( MultiTypedBasicAttributesEntity_.someBytes );
|
||||||
|
ParameterExpression<byte[]> param = em.getCriteriaBuilder().parameter( byte[].class, "theBytes" );
|
||||||
|
criteria.where( em.getCriteriaBuilder().equal( someBytesPath, param ) );
|
||||||
|
TypedQuery<MultiTypedBasicAttributesEntity> query = em.createQuery( criteria );
|
||||||
|
query.setParameter( param, new byte[] { 1,1,1 } );
|
||||||
|
query.getResultList();
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonPrimitiveArrayParameterBinding() {
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
CriteriaQuery<MultiTypedBasicAttributesEntity> criteria = em.getCriteriaBuilder()
|
||||||
|
.createQuery( MultiTypedBasicAttributesEntity.class );
|
||||||
|
Root<MultiTypedBasicAttributesEntity> rootEntity = criteria.from( MultiTypedBasicAttributesEntity.class );
|
||||||
|
Path<Byte[]> thePath = rootEntity.get( MultiTypedBasicAttributesEntity_.someWrappedBytes );
|
||||||
|
ParameterExpression<Byte[]> param = em.getCriteriaBuilder().parameter( Byte[].class, "theBytes" );
|
||||||
|
criteria.where( em.getCriteriaBuilder().equal( thePath, param ) );
|
||||||
|
TypedQuery<MultiTypedBasicAttributesEntity> query = em.createQuery( criteria );
|
||||||
|
query.setParameter( param, new Byte[] { Byte.valueOf((byte)1), Byte.valueOf((byte)1), Byte.valueOf((byte)1) } );
|
||||||
|
query.getResultList();
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { MultiTypedBasicAttributesEntity.class };
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,8 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.criterion.CriteriaQuery;
|
||||||
|
import org.hibernate.ejb.criteria.MultiTypedBasicAttributesEntity;
|
||||||
import org.hibernate.ejb.test.BaseEntityManagerFunctionalTestCase;
|
import org.hibernate.ejb.test.BaseEntityManagerFunctionalTestCase;
|
||||||
import org.hibernate.ejb.test.Distributor;
|
import org.hibernate.ejb.test.Distributor;
|
||||||
import org.hibernate.ejb.test.Item;
|
import org.hibernate.ejb.test.Item;
|
||||||
|
@ -571,7 +573,8 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
return new Class[]{
|
return new Class[]{
|
||||||
Item.class,
|
Item.class,
|
||||||
Distributor.class,
|
Distributor.class,
|
||||||
Wallet.class
|
Wallet.class,
|
||||||
|
MultiTypedBasicAttributesEntity.class
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue