/* * 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.metamodel.source.annotations.xml.mocker; import java.beans.Introspector; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; import org.jboss.jandex.FieldInfo; import org.jboss.jandex.MethodInfo; import org.jboss.jandex.Type; import org.hibernate.HibernateException; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.jaxb.mapping.orm.JaxbCascadeType; import org.hibernate.metamodel.source.annotations.JPADotNames; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.classloading.spi.ClassLoaderService; /** * @author Strong Liu */ public class MockHelper { static final AnnotationValue[] EMPTY_ANNOTATION_VALUE_ARRAY = new AnnotationValue[0]; static final Type[] EMPTY_TYPE_ARRAY = new Type[0]; /** * util method for String Array attribute Annotation * * @param name * @param values * @param annotationValueList */ static void stringArrayValue(String name, List<String> values, List<AnnotationValue> annotationValueList) { if ( isNotEmpty( values ) ) { AnnotationValue[] annotationValues = new AnnotationValue[values.size()]; for ( int j = 0; j < values.size(); j++ ) { annotationValues[j] = stringValue( "", values.get( j ) ); } annotationValueList.add( AnnotationValue.createArrayValue( name, annotationValues ) ); } } /** * util method for single string attribute Annotation only */ static AnnotationValue[] stringValueArray(String name, String value) { return nullSafe( stringValue( name, value ) ); } private static AnnotationValue stringValue(String name, String value) { if ( StringHelper.isNotEmpty( value ) ) { return AnnotationValue.createStringValue( name, value ); } return null; } static void stringValue(String name, String value, List<AnnotationValue> annotationValueList) { addToCollectionIfNotNull( annotationValueList, stringValue( name, value ) ); } private static AnnotationValue integerValue(String name, Integer value) { if ( value == null ) { return null; } return AnnotationValue.createIntegerValue( name, value ); } static void integerValue(String name, Integer value, List<AnnotationValue> annotationValueList) { addToCollectionIfNotNull( annotationValueList, integerValue( name, value ) ); } static AnnotationValue[] booleanValueArray(String name, Boolean value) { return nullSafe( booleanValue( name, value ) ); } static void booleanValue(String name, Boolean value, List<AnnotationValue> annotationValueList) { addToCollectionIfNotNull( annotationValueList, booleanValue( name, value ) ); } private static AnnotationValue booleanValue(String name, Boolean value) { if ( value == null ) { return null; } return AnnotationValue.createBooleanValue( name, value ); } private static AnnotationValue classValue(String name, String className, ServiceRegistry serviceRegistry) { if ( StringHelper.isNotEmpty( className ) ) { return AnnotationValue.createClassValue( name, getType( className, serviceRegistry ) ); } return null; } static void classValue(String name, String className, List<AnnotationValue> list, ServiceRegistry serviceRegistry) { addToCollectionIfNotNull( list, classValue( name, className, serviceRegistry ) ); } static AnnotationValue[] classValueArray(String name, String className, ServiceRegistry serviceRegistry) { return nullSafe( classValue( name, className, serviceRegistry ) ); } static AnnotationValue nestedAnnotationValue(String name, AnnotationInstance value) { if ( value == null ) { return null; } return AnnotationValue.createNestedAnnotationValue( name, value ); } static void nestedAnnotationValue(String name, AnnotationInstance value, List<AnnotationValue> list) { addToCollectionIfNotNull( list, nestedAnnotationValue( name, value ) ); } private static AnnotationValue[] nullSafe(AnnotationValue value) { return value == null ? EMPTY_ANNOTATION_VALUE_ARRAY : new AnnotationValue[] { value }; } static void classArrayValue(String name, List<String> classNameList, List<AnnotationValue> list, ServiceRegistry serviceRegistry) { if ( isNotEmpty( classNameList ) ) { List<AnnotationValue> clazzValueList = new ArrayList<AnnotationValue>( classNameList.size() ); for ( String clazz : classNameList ) { addToCollectionIfNotNull( clazzValueList, classValue( "", clazz, serviceRegistry ) ); } list.add( AnnotationValue.createArrayValue( name, toArray( clazzValueList ) ) ); } } public static AnnotationValue[] toArray(List<AnnotationValue> list) { AnnotationValue[] values = EMPTY_ANNOTATION_VALUE_ARRAY; if ( isNotEmpty( list ) ) { values = list.toArray( new AnnotationValue[list.size()] ); } return values; } private static AnnotationValue enumValue(String name, DotName typeName, Enum value) { if ( value != null && StringHelper.isNotEmpty( value.toString() ) ) { return AnnotationValue.createEnumValue( name, typeName, value.toString() ); } return null; } static void cascadeValue(String name, JaxbCascadeType cascadeType, boolean isCascadePersistDefault, List<AnnotationValue> annotationValueList) { List<Enum> enumList = new ArrayList<Enum>(); if ( isCascadePersistDefault ) { enumList.add( javax.persistence.CascadeType.PERSIST ); } if ( cascadeType != null ) { if ( cascadeType.getCascadeAll() != null ) { enumList.add( javax.persistence.CascadeType.ALL ); } if ( cascadeType.getCascadePersist() != null && !isCascadePersistDefault ) { enumList.add( javax.persistence.CascadeType.PERSIST ); } if ( cascadeType.getCascadeMerge() != null ) { enumList.add( javax.persistence.CascadeType.MERGE ); } if ( cascadeType.getCascadeRemove() != null ) { enumList.add( javax.persistence.CascadeType.REMOVE ); } if ( cascadeType.getCascadeRefresh() != null ) { enumList.add( javax.persistence.CascadeType.REFRESH ); } if ( cascadeType.getCascadeDetach() != null ) { enumList.add( javax.persistence.CascadeType.DETACH ); } } if ( !enumList.isEmpty() ) { MockHelper.enumArrayValue( name, JPADotNames.CASCADE_TYPE, enumList, annotationValueList ); } } static void enumArrayValue(String name, DotName typeName, List<Enum> valueList, List<AnnotationValue> list) { if ( isNotEmpty( valueList ) ) { List<AnnotationValue> enumValueList = new ArrayList<AnnotationValue>( valueList.size() ); for ( Enum e : valueList ) { addToCollectionIfNotNull( enumValueList, enumValue( "", typeName, e ) ); } list.add( AnnotationValue.createArrayValue( name, toArray( enumValueList ) ) ); } } static void enumValue(String name, DotName typeName, Enum value, List<AnnotationValue> list) { addToCollectionIfNotNull( list, enumValue( name, typeName, value ) ); } static AnnotationValue[] enumValueArray(String name, DotName typeName, Enum value) { return nullSafe( enumValue( name, typeName, value ) ); } public static void addToCollectionIfNotNull(Collection collection, Object value) { if ( value != null && collection != null ) { collection.add( value ); } } /** * @param t1 can't be null * @param t2 can't be null */ public static boolean targetEquals(AnnotationTarget t1, AnnotationTarget t2) { if ( t1 == t2 ) { return true; } if ( t1 != null && t2 != null ) { if ( t1.getClass() == t2.getClass() ) { if ( t1.getClass() == ClassInfo.class ) { return ( (ClassInfo) t1 ).name().equals( ( (ClassInfo) t2 ).name() ); } else if ( t1.getClass() == MethodInfo.class ) { return ( (MethodInfo) t1 ).name().equals( ( (MethodInfo) t2 ).name() ); } else { return ( (FieldInfo) t1 ).name().equals( ( (FieldInfo) t2 ).name() ); } } } return false; } public static boolean isNotEmpty(Collection collection) { return collection != null && !collection.isEmpty(); } static AnnotationInstance create(DotName name, AnnotationTarget target, List<AnnotationValue> annotationValueList) { return create( name, target, toArray( annotationValueList ) ); } static String buildSafeClassName(String className, String defaultPackageName) { if ( className.indexOf( '.' ) < 0 && StringHelper.isNotEmpty( defaultPackageName ) ) { className = StringHelper.qualify( defaultPackageName, className ); } return className; } static AnnotationInstance create(DotName name, AnnotationTarget target, AnnotationValue[] values) { if ( values == null || values.length == 0 ) { values = EMPTY_ANNOTATION_VALUE_ARRAY; } return AnnotationInstance.create( name, target, addMockMark( values ) ); } private static AnnotationValue[] addMockMark(AnnotationValue[] values) { AnnotationValue[] newValues = new AnnotationValue[values.length + 1]; System.arraycopy( values, 0, newValues, 0, values.length ); newValues[values.length] = booleanValue( "isMocked", true ); return newValues; } private static MethodInfo getMethodInfo(ClassInfo classInfo, Method method) { Class returnTypeClass = method.getReturnType(); short access_flags = (short) method.getModifiers(); return MethodInfo.create( classInfo, method.getName(), getTypes( method.getParameterTypes() ), getType( returnTypeClass ), access_flags ); } enum TargetType {METHOD, FIELD, PROPERTY} static AnnotationTarget getTarget(ServiceRegistry serviceRegistry, ClassInfo classInfo, String name, TargetType type) { Class clazz = serviceRegistry.getService( ClassLoaderService.class ).classForName( classInfo.toString() ); switch ( type ) { case FIELD: Field field = getField( clazz, name ); if ( field == null ) { throw new HibernateException( "Unable to load field " + name + " of class " + clazz.getName() ); } return FieldInfo.create( classInfo, name, getType( field.getType() ), (short) ( field.getModifiers() ) ); case METHOD: Method method = getMethod( clazz, name ); if ( method == null ) { throw new HibernateException( "Unable to load method " + name + " of class " + clazz.getName() ); } return getMethodInfo( classInfo, method ); case PROPERTY: method = getterMethod( clazz, name ); if ( method == null ) { throw new HibernateException( "Unable to load property " + name + " of class " + clazz.getName() ); } return getMethodInfo( classInfo, method ); } throw new HibernateException( "" ); } //copied from org.hibernate.internal.util.ReflectHelper private static Method getterMethod(Class theClass, String propertyName) { Method[] methods = theClass.getDeclaredMethods(); Method.setAccessible( methods, true ); for ( Method method : methods ) { // if the method has parameters, skip it if ( method.getParameterTypes().length != 0 ) { continue; } // if the method is a "bridge", skip it if ( method.isBridge() ) { continue; } final String methodName = method.getName(); // try "get" if ( methodName.startsWith( "get" ) || methodName.startsWith( "has" ) ) { String testStdMethod = Introspector.decapitalize( methodName.substring( 3 ) ); String testOldMethod = methodName.substring( 3 ); if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) { return method; } } // if not "get", then try "is" if ( methodName.startsWith( "is" ) ) { String testStdMethod = Introspector.decapitalize( methodName.substring( 2 ) ); String testOldMethod = methodName.substring( 2 ); if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) { return method; } } } return null; } private static Method getMethod(Class theClass, String propertyName) { Method[] methods = theClass.getDeclaredMethods(); Method.setAccessible( methods, true ); for ( Method method : methods ) { // if the method has parameters, skip it if ( method.getParameterTypes().length != 0 ) { continue; } // if the method is a "bridge", skip it if ( method.isBridge() ) { continue; } final String methodName = method.getName(); if ( methodName.equals( propertyName ) ) { return method; } } return null; } private static Field getField(Class clazz, String name) { Field[] fields = clazz.getDeclaredFields(); Field.setAccessible( fields, true ); for ( Field field : fields ) { if ( field.getName().equals( name ) ) { return field; } } return null; } private static Type[] getTypes(Class[] classes) { if ( classes == null || classes.length == 0 ) { return EMPTY_TYPE_ARRAY; } Type[] types = new Type[classes.length]; for ( int i = 0; i < types.length; i++ ) { types[i] = getType( classes[i] ); } return types; } private static Type getType(String className, ServiceRegistry serviceRegistry) { return getType( serviceRegistry.getService( ClassLoaderService.class ).classForName( className ) ); } private static Type getType(Class clazz) { return Type.create( DotName.createSimple( clazz.getName() ), getTypeKind( clazz ) ); } private static Type.Kind getTypeKind(Class clazz) { Type.Kind kind; if ( clazz == Void.TYPE ) { kind = Type.Kind.VOID; } else if ( clazz.isPrimitive() ) { kind = Type.Kind.PRIMITIVE; } else if ( clazz.isArray() ) { kind = Type.Kind.ARRAY; } else { kind = Type.Kind.CLASS; } return kind; } }