From 31219e25d7b4b232705de5af92a6043e2277a793 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 25 Mar 2013 09:42:27 -0500 Subject: [PATCH] HHH-8107 - JandexHelper.getValue() returns Boolean instead of boolean, causing ClassCastException --- .../util/type/PrimitiveWrapperHelper.java | 269 ++++++++++++++++++ .../source/annotations/JandexHelper.java | 8 +- .../annotations/util/JandexHelperTest.java | 35 +++ 3 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/internal/util/type/PrimitiveWrapperHelper.java diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/type/PrimitiveWrapperHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/type/PrimitiveWrapperHelper.java new file mode 100644 index 0000000000..f8a9e73cf5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/type/PrimitiveWrapperHelper.java @@ -0,0 +1,269 @@ +/* + * 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.internal.util.type; + +/** + * Helper for primitive/wrapper utilities. + * + * @author Steve Ebersole + */ +public class PrimitiveWrapperHelper { + /** + * Describes a particular primitive/wrapper combo + */ + public static interface PrimitiveWrapperDescriptor { + public Class getPrimitiveClass(); + public Class getWrapperClass(); + } + + public static class BooleanDescriptor implements PrimitiveWrapperDescriptor { + public static final BooleanDescriptor INSTANCE = new BooleanDescriptor(); + + private BooleanDescriptor() { + } + + @Override + public Class getPrimitiveClass() { + return boolean.class; + } + + @Override + public Class getWrapperClass() { + return Boolean.class; + } + } + + public static class CharacterDescriptor implements PrimitiveWrapperDescriptor { + public static final CharacterDescriptor INSTANCE = new CharacterDescriptor(); + + private CharacterDescriptor() { + } + + @Override + public Class getPrimitiveClass() { + return char.class; + } + + @Override + public Class getWrapperClass() { + return Character.class; + } + } + + public static class ByteDescriptor implements PrimitiveWrapperDescriptor { + public static final ByteDescriptor INSTANCE = new ByteDescriptor(); + + private ByteDescriptor() { + } + + @Override + public Class getPrimitiveClass() { + return byte.class; + } + + @Override + public Class getWrapperClass() { + return Byte.class; + } + } + + public static class ShortDescriptor implements PrimitiveWrapperDescriptor { + public static final ShortDescriptor INSTANCE = new ShortDescriptor(); + + private ShortDescriptor() { + } + + @Override + public Class getPrimitiveClass() { + return short.class; + } + + @Override + public Class getWrapperClass() { + return Short.class; + } + } + + public static class IntegerDescriptor implements PrimitiveWrapperDescriptor { + public static final IntegerDescriptor INSTANCE = new IntegerDescriptor(); + + private IntegerDescriptor() { + } + + @Override + public Class getPrimitiveClass() { + return int.class; + } + + @Override + public Class getWrapperClass() { + return Integer.class; + } + } + + public static class LongDescriptor implements PrimitiveWrapperDescriptor { + public static final LongDescriptor INSTANCE = new LongDescriptor(); + + private LongDescriptor() { + } + + @Override + public Class getPrimitiveClass() { + return long.class; + } + + @Override + public Class getWrapperClass() { + return Long.class; + } + } + + public static class FloatDescriptor implements PrimitiveWrapperDescriptor { + public static final FloatDescriptor INSTANCE = new FloatDescriptor(); + + private FloatDescriptor() { + } + + @Override + public Class getPrimitiveClass() { + return float.class; + } + + @Override + public Class getWrapperClass() { + return Float.class; + } + } + + public static class DoubleDescriptor implements PrimitiveWrapperDescriptor { + public static final DoubleDescriptor INSTANCE = new DoubleDescriptor(); + + private DoubleDescriptor() { + } + + @Override + public Class getPrimitiveClass() { + return double.class; + } + + @Override + public Class getWrapperClass() { + return Double.class; + } + } + + @SuppressWarnings("unchecked") + public static PrimitiveWrapperDescriptor getDescriptorByPrimitiveType(Class primitiveClazz) { + if ( ! primitiveClazz.isPrimitive() ) { + throw new IllegalArgumentException( "Given class is not a primitive type : " + primitiveClazz.getName() ); + } + + if ( boolean.class == primitiveClazz ) { + return (PrimitiveWrapperDescriptor) BooleanDescriptor.INSTANCE; + } + + if ( char.class == primitiveClazz ) { + return (PrimitiveWrapperDescriptor) CharacterDescriptor.INSTANCE; + } + + if ( byte.class == primitiveClazz ) { + return (PrimitiveWrapperDescriptor) ByteDescriptor.INSTANCE; + } + + if ( short.class == primitiveClazz ) { + return (PrimitiveWrapperDescriptor) ShortDescriptor.INSTANCE; + } + + if ( int.class == primitiveClazz ) { + return (PrimitiveWrapperDescriptor) IntegerDescriptor.INSTANCE; + } + + if ( long.class == primitiveClazz ) { + return (PrimitiveWrapperDescriptor) LongDescriptor.INSTANCE; + } + + if ( float.class == primitiveClazz ) { + return (PrimitiveWrapperDescriptor) FloatDescriptor.INSTANCE; + } + + if ( double.class == primitiveClazz ) { + return (PrimitiveWrapperDescriptor) DoubleDescriptor.INSTANCE; + } + + // most likely void.class, which we can't really handle here + throw new IllegalArgumentException( "Unrecognized primitive type class : " + primitiveClazz.getName() ); + } + + @SuppressWarnings("unchecked") + public static PrimitiveWrapperDescriptor getDescriptorByWrapperType(Class wrapperClass) { + if ( wrapperClass.isPrimitive() ) { + throw new IllegalArgumentException( "Given class is a primitive type : " + wrapperClass.getName() ); + } + + if ( Boolean.class.equals( wrapperClass ) ) { + return (PrimitiveWrapperDescriptor) BooleanDescriptor.INSTANCE; + } + + if ( Character.class == wrapperClass ) { + return (PrimitiveWrapperDescriptor) CharacterDescriptor.INSTANCE; + } + + if ( Byte.class == wrapperClass ) { + return (PrimitiveWrapperDescriptor) ByteDescriptor.INSTANCE; + } + + if ( Short.class == wrapperClass ) { + return (PrimitiveWrapperDescriptor) ShortDescriptor.INSTANCE; + } + + if ( Integer.class == wrapperClass ) { + return (PrimitiveWrapperDescriptor) IntegerDescriptor.INSTANCE; + } + + if ( Long.class == wrapperClass ) { + return (PrimitiveWrapperDescriptor) LongDescriptor.INSTANCE; + } + + if ( Float.class == wrapperClass ) { + return (PrimitiveWrapperDescriptor) FloatDescriptor.INSTANCE; + } + + if ( Double.class == wrapperClass ) { + return (PrimitiveWrapperDescriptor) DoubleDescriptor.INSTANCE; + } + + // most likely void.class, which we can't really handle here + throw new IllegalArgumentException( "Unrecognized wrapper type class : " + wrapperClass.getName() ); + } + + public static boolean isWrapper(Class clazz) { + try { + getDescriptorByWrapperType( clazz ); + return true; + } + catch (Exception e) { + return false; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/JandexHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/JandexHelper.java index fd527435b7..cf48b624d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/JandexHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/JandexHelper.java @@ -46,6 +46,7 @@ import org.jboss.jandex.Type; import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.internal.util.type.PrimitiveWrapperHelper; /** * Utility methods for working with the jandex annotation index. @@ -95,6 +96,10 @@ public class JandexHelper { ); } + if ( type.isPrimitive() ) { + type = PrimitiveWrapperHelper.getDescriptorByPrimitiveType( type ).getWrapperClass(); + } + // try getting the untyped value from Jandex AnnotationValue annotationValue = annotation.value( element ); @@ -113,7 +118,8 @@ public class JandexHelper { element, annotation.name(), type.getName() - ) + ), + e ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/JandexHelperTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/JandexHelperTest.java index 9817f8281a..10edc54a44 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/JandexHelperTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/JandexHelperTest.java @@ -23,11 +23,15 @@ */ package org.hibernate.metamodel.source.annotations.util; +import java.net.MalformedURLException; +import java.net.URL; import java.util.List; import java.util.Map; +import javax.persistence.AttributeConverter; import javax.persistence.AttributeOverride; import javax.persistence.Basic; import javax.persistence.Column; +import javax.persistence.Converter; import javax.persistence.Entity; import javax.persistence.LockModeType; import javax.persistence.NamedQuery; @@ -42,6 +46,7 @@ import org.junit.Before; import org.junit.Test; import org.hibernate.AssertionFailure; +import org.hibernate.HibernateException; import org.hibernate.annotations.NamedNativeQuery; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.metamodel.source.annotations.HibernateDotNames; @@ -244,6 +249,36 @@ public class JandexHelperTest extends BaseUnitTestCase { } } + + @Test + public void testPrimitiveAnnotationAttributeTypes() { + @Converter( autoApply = true ) + class MyConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(URL attribute) { + return attribute.toExternalForm(); + } + + @Override + public URL convertToEntityAttribute(String dbData) { + try { + return new URL( dbData ); + } + catch (MalformedURLException e) { + throw new HibernateException( "Could not convert string [" + dbData + "] to url", e ); + } + } + } + + Index index = JandexHelper.indexForClass( classLoaderService, MyConverter.class ); + List annotationInstances = index.getAnnotations( JPADotNames.CONVERTER ); + assertTrue( annotationInstances.size() == 1 ); + AnnotationInstance annotationInstance = annotationInstances.get( 0 ); + + boolean value = JandexHelper.getValue( annotationInstance, "autoApply", boolean.class ); + Assert.assertTrue( value ); + } }