Skip to content

Commit

Permalink
HHH-8498 - Full ConstructorResult handling
Browse files Browse the repository at this point in the history
  • Loading branch information
sebersole committed Sep 17, 2013
1 parent 4b2667c commit a2881b3
Show file tree
Hide file tree
Showing 12 changed files with 664 additions and 423 deletions.
Expand Up @@ -45,6 +45,7 @@
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.type.PrimitiveWrapperHelper;

/**
* No idea.
Expand Down Expand Up @@ -141,50 +142,7 @@ private boolean areTypeMatch(Class converterDefinedType, Class propertyType) {
}

return converterDefinedType.equals( propertyType )
|| arePrimitiveWrapperEquivalents( converterDefinedType, propertyType );
}

private boolean arePrimitiveWrapperEquivalents(Class converterDefinedType, Class propertyType) {
if ( converterDefinedType.isPrimitive() ) {
return getWrapperEquivalent( converterDefinedType ).equals( propertyType );
}
else if ( propertyType.isPrimitive() ) {
return getWrapperEquivalent( propertyType ).equals( converterDefinedType );
}
return false;
}

private static Class getWrapperEquivalent(Class primitive) {
if ( ! primitive.isPrimitive() ) {
throw new AssertionFailure( "Passed type for which to locate wrapper equivalent was not a primitive" );
}

if ( boolean.class.equals( primitive ) ) {
return Boolean.class;
}
else if ( char.class.equals( primitive ) ) {
return Character.class;
}
else if ( byte.class.equals( primitive ) ) {
return Byte.class;
}
else if ( short.class.equals( primitive ) ) {
return Short.class;
}
else if ( int.class.equals( primitive ) ) {
return Integer.class;
}
else if ( long.class.equals( primitive ) ) {
return Long.class;
}
else if ( float.class.equals( primitive ) ) {
return Float.class;
}
else if ( double.class.equals( primitive ) ) {
return Double.class;
}

throw new AssertionFailure( "Unexpected primitive type (VOID most likely) passed to getWrapperEquivalent" );
|| PrimitiveWrapperHelper.arePrimitiveWrapperEquivalents( converterDefinedType, propertyType );
}

@Override
Expand Down
Expand Up @@ -211,7 +211,10 @@ public static <X> PrimitiveWrapperDescriptor<X> getDescriptorByPrimitiveType(Cla
return (PrimitiveWrapperDescriptor<X>) DoubleDescriptor.INSTANCE;
}

// most likely void.class, which we can't really handle here
if ( void.class == primitiveClazz ) {
throw new IllegalArgumentException( "void, as primitive type, has no wrapper equivalent" );
}

throw new IllegalArgumentException( "Unrecognized primitive type class : " + primitiveClazz.getName() );
}

Expand Down Expand Up @@ -266,4 +269,14 @@ public static boolean isWrapper(Class<?> clazz) {
return false;
}
}

public static boolean arePrimitiveWrapperEquivalents(Class converterDefinedType, Class propertyType) {
if ( converterDefinedType.isPrimitive() ) {
return getDescriptorByPrimitiveType( converterDefinedType ).getWrapperClass().equals( propertyType );
}
else if ( propertyType.isPrimitive() ) {
return getDescriptorByPrimitiveType( propertyType ).getWrapperClass().equals( converterDefinedType );
}
return false;
}
}
Expand Up @@ -22,13 +22,13 @@
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.loader.custom;
package org.hibernate.loader.custom;
import org.hibernate.LockMode;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.EntityAliases;

/**
* Spefically a fetch return that refers to a collection association.
* Specifically a fetch return that refers to a collection association.
*
* @author Steve Ebersole
*/
Expand Down
@@ -0,0 +1,124 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.loader.custom;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.type.PrimitiveWrapperHelper;
import org.hibernate.type.Type;

/**
* Represents a {@link javax.persistence.ConstructorResult} within the custom query.
*
* @author Steve Ebersole
*/
public class ConstructorResultColumnProcessor implements ResultColumnProcessor {
private final Class targetClass;
private final ScalarResultColumnProcessor[] scalarProcessors;

private Constructor constructor;

public ConstructorResultColumnProcessor(Class targetClass, ScalarResultColumnProcessor[] scalarProcessors) {
this.targetClass = targetClass;
this.scalarProcessors = scalarProcessors;
}

@Override
public void performDiscovery(JdbcResultMetadata metadata, List<Type> types, List<String> aliases) throws SQLException {
final List<Type> localTypes = new ArrayList<Type>();
for ( ScalarResultColumnProcessor scalar : scalarProcessors ) {
scalar.performDiscovery( metadata, localTypes, aliases );
}

types.addAll( localTypes );

constructor = resolveConstructor( targetClass, localTypes );
}

@Override
public Object extract(Object[] data, ResultSet resultSet, SessionImplementor session)
throws SQLException, HibernateException {
if ( constructor == null ) {
throw new IllegalStateException( "Constructor to call was null" );
}

final Object[] args = new Object[ scalarProcessors.length ];
for ( int i = 0; i < scalarProcessors.length; i++ ) {
args[i] = scalarProcessors[i].extract( data, resultSet, session );
}

try {
return constructor.newInstance( args );
}
catch (InvocationTargetException e) {
throw new HibernateException(
String.format( "Unable to call %s constructor", constructor.getDeclaringClass() ),
e
);
}
catch (Exception e) {
throw new HibernateException(
String.format( "Unable to call %s constructor", constructor.getDeclaringClass() ),
e
);
}
}

private static Constructor resolveConstructor(Class targetClass, List<Type> types) {
for ( Constructor constructor : targetClass.getConstructors() ) {
final Class[] argumentTypes = constructor.getParameterTypes();
if ( argumentTypes.length != types.size() ) {
continue;
}

boolean allMatched = true;
for ( int i = 0; i < argumentTypes.length; i++ ) {
if ( ! areAssignmentCompatible( argumentTypes[i], types.get( i ).getReturnedClass() ) ) {
allMatched = false;
break;
}
}
if ( !allMatched ) {
continue;
}

return constructor;
}

throw new IllegalArgumentException( "Could not locate appropriate constructor on class : " + targetClass.getName() );
}

@SuppressWarnings("unchecked")
private static boolean areAssignmentCompatible(Class argumentType, Class typeReturnedClass) {
return argumentType.isAssignableFrom( typeReturnedClass )
|| PrimitiveWrapperHelper.arePrimitiveWrapperEquivalents( argumentType, typeReturnedClass );
}
}
Expand Up @@ -23,52 +23,18 @@
*/
package org.hibernate.loader.custom;

import java.lang.reflect.Constructor;

/**
* A return representing a {@link javax.persistence.ConstructorResult}
*
* @author Steve Ebersole
*/
public class ConstructorReturn implements Return {
private final Class targetClass;
private final ScalarReturn[] scalars;

// private final Constructor constructor;

public ConstructorReturn(Class targetClass, ScalarReturn[] scalars) {
this.targetClass = targetClass;
this.scalars = scalars;

// constructor = resolveConstructor( targetClass, scalars );
}

private static Constructor resolveConstructor(Class targetClass, ScalarReturn[] scalars) {
for ( Constructor constructor : targetClass.getConstructors() ) {
final Class[] argumentTypes = constructor.getParameterTypes();
if ( argumentTypes.length != scalars.length ) {
continue;
}

boolean allMatched = true;
for ( int i = 0; i < argumentTypes.length; i++ ) {
if ( areAssignmentCompatible( argumentTypes[i], scalars[i].getType().getReturnedClass() ) ) {
allMatched = false;
break;
}
}
if ( !allMatched ) {
continue;
}

return constructor;
}

throw new IllegalArgumentException( "Could not locate appropriate constructor on class : " + targetClass.getName() );
}

@SuppressWarnings("unchecked")
private static boolean areAssignmentCompatible(Class argumentType, Class typeReturnedClass) {
// todo : add handling for primitive/wrapper equivalents
return argumentType.isAssignableFrom( typeReturnedClass );
}

public Class getTargetClass() {
Expand All @@ -78,8 +44,4 @@ public Class getTargetClass() {
public ScalarReturn[] getScalars() {
return scalars;
}

// public Constructor getConstructor() {
// return constructor;
// }
}

0 comments on commit a2881b3

Please sign in to comment.