diff --git a/hibernate-types-4/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java b/hibernate-types-4/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java index aed11cc99..8ccc6a1ab 100644 --- a/hibernate-types-4/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java +++ b/hibernate-types-4/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java @@ -1,20 +1,37 @@ package com.vladmihalcea.hibernate.type; import com.vladmihalcea.hibernate.type.util.Configuration; +import com.vladmihalcea.hibernate.type.util.ReflectionUtils; +import org.dom4j.Node; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.metamodel.relational.Size; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.Type; +import org.hibernate.type.descriptor.java.IncomparableComparator; import org.hibernate.usertype.UserType; import java.io.Serializable; +import java.lang.reflect.Method; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Map; /** * Very convenient base class for implementing immutable object types using Hibernate {@link UserType}. + *

+ * The {@link ImmutableType} implements the {@link Type} interface too, so you can pass all + * types extending the {@link ImmutableType} to the {@link org.hibernate.SQLQuery#addScalar(String, Type)} + * method to fix the No Dialect mapping for JDBC type issues. * * @author Vlad Mihalcea */ -public abstract class ImmutableType implements UserType { +public abstract class ImmutableType implements UserType, Type { private final Configuration configuration; @@ -34,7 +51,7 @@ protected ImmutableType(Class clazz) { /** * Initialization constructor taking the {@link Class} and {@link Configuration} objects. * - * @param clazz the entity attribute {@link Class} type to be handled + * @param clazz the entity attribute {@link Class} type to be handled * @param configuration custom {@link Configuration} object. */ protected ImmutableType(Class clazz, Configuration configuration) { @@ -44,12 +61,40 @@ protected ImmutableType(Class clazz, Configuration configuration) { /** * Get the current {@link Configuration} object. + * * @return the current {@link Configuration} object. */ protected Configuration getConfiguration() { return configuration; } + /** + * Get the column value from the JDBC {@link ResultSet}. + * + * @param rs JDBC {@link ResultSet} + * @param names database column name + * @param session current Hibernate {@link org.hibernate.Session} + * @param owner current Hibernate {@link org.hibernate.SessionFactory} + * @return column value + * @throws SQLException in case of failure + */ + protected abstract T get(ResultSet rs, String[] names, + SessionImplementor session, Object owner) throws SQLException; + + /** + * Set the column value on the provided JDBC {@link PreparedStatement}. + * + * @param st JDBC {@link PreparedStatement} + * @param value database column value + * @param index database column index + * @param session current Hibernate {@link org.hibernate.Session} + * @throws SQLException in case of failure + */ + protected abstract void set(PreparedStatement st, T value, int index, + SessionImplementor session) throws SQLException; + + /* Methods inherited from the {@link UserType} interface */ + @Override public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws SQLException { @@ -62,13 +107,6 @@ public void nullSafeSet(PreparedStatement st, Object value, int index, set(st, clazz.cast(value), index, session); } - protected abstract T get(ResultSet rs, String[] names, - SessionImplementor session, Object owner) throws SQLException; - - protected abstract void set(PreparedStatement st, T value, int index, - SessionImplementor session) throws SQLException; - - @Override public Class returnedClass() { return clazz; @@ -108,4 +146,196 @@ public Object assemble(Serializable cached, Object owner) { public Object replace(Object o, Object target, Object owner) { return o; } + + /* Methods inherited from the {@link Type} interface */ + + @Override + public boolean isAssociationType() { + return false; + } + + @Override + public boolean isCollectionType() { + return false; + } + + @Override + public boolean isEntityType() { + return false; + } + + @Override + public boolean isAnyType() { + return false; + } + + @Override + public boolean isComponentType() { + return false; + } + + @Override + public int getColumnSpan(Mapping mapping) throws MappingException { + return 1; + } + + @Override + public int[] sqlTypes(Mapping mapping) throws MappingException { + return sqlTypes(); + } + + @Override + public Size[] dictatedSizes(Mapping mapping) throws MappingException { + return new Size[]{new Size()}; + } + + @Override + public Size[] defaultSizes(Mapping mapping) throws MappingException { + return dictatedSizes(mapping); + } + + @Override + public Class getReturnedClass() { + return returnedClass(); + } + + @Override + public boolean isSame(Object x, Object y) throws HibernateException { + return equals(x, y); + } + + @Override + public boolean isEqual(Object x, Object y) throws HibernateException { + return equals(x, y); + } + + @Override + public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) throws HibernateException { + return equals(x, y); + } + + @Override + public int getHashCode(Object x) throws HibernateException { + return hashCode(x); + } + + @Override + public int getHashCode(Object x, SessionFactoryImplementor factory) throws HibernateException { + return hashCode(x); + } + + @Override + public int compare(Object x, Object y) { + return IncomparableComparator.INSTANCE.compare(x, y); + } + + @Override + public final boolean isDirty(Object old, Object current, SessionImplementor session) { + return isDirty(old, current); + } + + @Override + public final boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) { + return checkable[0] && isDirty(old, current); + } + + protected final boolean isDirty(Object old, Object current) { + return !isSame(old, current); + } + + @Override + public boolean isModified(Object dbState, Object currentState, boolean[] checkable, SessionImplementor session) throws HibernateException { + return isDirty(dbState, currentState); + } + + @Override + public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner) throws HibernateException, SQLException { + return get(rs, new String[]{name}, session, owner); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session) throws HibernateException, SQLException { + set(st, returnedClass().cast(value), index, session); + } + + @Override + public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException { + return String.valueOf(value); + } + + @Override + public String getName() { + return getClass().getSimpleName(); + } + + @Override + public Object deepCopy(Object value, SessionFactoryImplementor factory) throws HibernateException { + return deepCopy(value); + } + + @Override + public Serializable disassemble(Object value, SessionImplementor session, Object owner) throws HibernateException { + return disassemble(value); + } + + @Override + public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException { + return assemble(cached, session); + } + + @Override + public void beforeAssemble(Serializable cached, SessionImplementor session) { + + } + + @Override + public Object hydrate(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { + return nullSafeGet(rs, names, session, owner); + } + + @Override + public Object resolve(Object value, SessionImplementor session, Object owner) throws HibernateException { + return value; + } + + @Override + public Object semiResolve(Object value, SessionImplementor session, Object owner) throws HibernateException { + return value; + } + + @Override + public Type getSemiResolvedType(SessionFactoryImplementor factory) { + return this; + } + + @Override + public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache) throws HibernateException { + return replace(original, target, owner); + } + + @Override + public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache, ForeignKeyDirection foreignKeyDirection) throws HibernateException { + return replace(original, target, owner); + } + + @Override + public boolean[] toColumnNullness(Object value, Mapping mapping) { + return value == null ? ArrayHelper.FALSE : ArrayHelper.TRUE; + } + + @Override + public boolean isXMLElement() { + return false; + } + + @Override + public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) throws HibernateException { + node.setText(toLoggableString(value, factory)); + } + + @Override + public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException { + Method valueOfMethod = ReflectionUtils.getMethodOrNull(clazz, "valueOf", String.class); + return valueOfMethod != null ? ReflectionUtils.invokeStaticMethod(valueOfMethod, xml.getText()) : null; + } } \ No newline at end of file diff --git a/hibernate-types-4/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java b/hibernate-types-4/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java index e8fceeee6..03ffe2eaf 100644 --- a/hibernate-types-4/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java +++ b/hibernate-types-4/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java @@ -1,8 +1,5 @@ package com.vladmihalcea.hibernate.type.util; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -15,58 +12,144 @@ */ public final class ReflectionUtils { - public static final String GETTER_PREFIX = "get"; - public static final String SETTER_PREFIX = "set"; - private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtils.class); + private static final String GETTER_PREFIX = "get"; + + private static final String SETTER_PREFIX = "set"; + /** + * Prevent any instantiation. + */ private ReflectionUtils() { - throw new UnsupportedOperationException("ReflectionUtils is not instantiable!"); + throw new UnsupportedOperationException("The " + getClass() + " is not instantiable!"); } /** - * Instantiate object + * Instantiate a new {@link Object} of the provided type. * - * @param className Class for object to instantiate - * @param field type - * @return field value + * @param className The fully-qualified Java class name of the {@link Object} to instantiate + * @param class type + * @return new Java {@link Object} of the provided type */ public static T newInstance(String className) { try { Class clazz = Class.forName(className); - return (T) clazz.newInstance(); + return newInstance(clazz); } catch (ClassNotFoundException e) { - throw handleException(className, e); + throw handleException(e); + } + } + + /** + * Instantiate a new {@link Object} of the provided type. + * + * @param clazz The Java {@link Class} of the {@link Object} to instantiate + * @param class type + * @return new Java {@link Object} of the provided type + */ + @SuppressWarnings("unchecked") + public static T newInstance(Class clazz) { + try { + return (T) clazz.newInstance(); } catch (InstantiationException e) { - throw handleException(className, e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(className, e); + throw handleException(e); } } /** - * Get target object field value + * Get the {@link Field} with the given name belonging to the provided Java {@link Class}. * - * @param target target object + * @param targetClass the provided Java {@link Class} the field belongs to + * @param fieldName the {@link Field} name + * @return the {@link Field} matching the given name + */ + public static Field getField(Class targetClass, String fieldName) { + Field field = null; + + try { + field = targetClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + try { + field = targetClass.getField(fieldName); + } catch (NoSuchFieldException ignore) { + } + + if (!targetClass.getSuperclass().equals(Object.class)) { + return getField(targetClass.getSuperclass(), fieldName); + } else { + throw handleException(e); + } + } finally { + if (field != null) { + field.setAccessible(true); + } + } + + return field; + } + + /** + * Get the {@link Field} with the given name belonging to the provided Java {@link Class} or {@code null} + * if no {@link Field} was found. + * + * @param targetClass the provided Java {@link Class} the field belongs to + * @param fieldName the {@link Field} name + * @return the {@link Field} matching the given name or {@code null} + */ + public static Field getFieldOrNull(Class targetClass, String fieldName) { + try { + Field field = targetClass.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException e) { + return null; + } + } + + /** + * Get the value of the field matching the given name and belonging to target {@link Object}. + * + * @param target target {@link Object} whose field we are retrieving the value from * @param fieldName field name * @param field type * @return field value */ public static T getFieldValue(Object target, String fieldName) { try { - Field field = target.getClass().getDeclaredField(fieldName); + Field field = getField(target.getClass(), fieldName); field.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) field.get(target); return returnValue; - } catch (NoSuchFieldException e) { - throw handleException(fieldName, e); } catch (IllegalAccessException e) { - throw handleException(fieldName, e); + throw handleException(e); } } /** - * Set target object field value + * Get the value of the field matching the given name and belonging to target {@link Object} or {@code null} + * if no {@link Field} was found.. + * + * @param target target {@link Object} whose field we are retrieving the value from + * @param fieldName field name + * @param field type + * @return field value matching the given name or {@code null} + */ + public static T getFieldValueOrNull(Object target, String fieldName) { + try { + Field field = getField(target.getClass(), fieldName); + field.setAccessible(true); + @SuppressWarnings("unchecked") + T returnValue = (T) field.get(target); + return returnValue; + } catch (IllegalAccessException e) { + return null; + } + } + + /** + * Set the value of the field matching the given name and belonging to target {@link Object}. * * @param target target object * @param fieldName field name @@ -78,24 +161,52 @@ public static void setFieldValue(Object target, String fieldName, Object value) field.setAccessible(true); field.set(target, value); } catch (NoSuchFieldException e) { - throw handleException(fieldName, e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(fieldName, e); + throw handleException(e); } } /** - * Get target method + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Object}. * - * @param target target object + * @param target target {@link Object} * @param methodName method name * @param parameterTypes method parameter types - * @return return value + * @return return {@link Method} matching the provided signature */ public static Method getMethod(Object target, String methodName, Class... parameterTypes) { return getMethod(target.getClass(), methodName, parameterTypes); } + /** + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Object} or {@code null} if no {@link Method} was found. + * + * @param target target {@link Object} + * @param methodName method name + * @param parameterTypes method parameter types + * @return return {@link Method} matching the provided signature or {@code null} + */ + public static Method getMethodOrNull(Object target, String methodName, Class... parameterTypes) { + try { + return getMethod(target.getClass(), methodName, parameterTypes); + } catch (RuntimeException e) { + return null; + } + } + + /** + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Class}. + * + * @param targetClass target {@link Class} + * @param methodName method name + * @param parameterTypes method parameter types + * @return the {@link Method} matching the provided signature + */ + @SuppressWarnings("unchecked") public static Method getMethod(Class targetClass, String methodName, Class... parameterTypes) { try { return targetClass.getDeclaredMethod(methodName, parameterTypes); @@ -105,22 +216,22 @@ public static Method getMethod(Class targetClass, String methodName, Class... pa } catch (NoSuchMethodException ignore) { } - if(!targetClass.getSuperclass().equals(Object.class)) { + if (!targetClass.getSuperclass().equals(Object.class)) { return getMethod(targetClass.getSuperclass(), methodName, parameterTypes); - } - else { - throw handleException(methodName, e); + } else { + throw handleException(e); } } } /** - * Check if target class has the given method + * Check if the provided Java {@link Class} contains a method matching + * the given signature (name and parameter types). * - * @param targetClass target class + * @param targetClass target {@link Class} * @param methodName method name * @param parameterTypes method parameter types - * @return method availability + * @return the provided Java {@link Class} contains a method with the given signature */ public static boolean hasMethod(Class targetClass, String methodName, Class... parameterTypes) { try { @@ -132,162 +243,198 @@ public static boolean hasMethod(Class targetClass, String methodName, Class.. } /** - * Get setter method + * Get the property setter {@link Method} with the given signature (name and parameter types) + * belonging to the provided Java {@link Object}. * - * @param target target object - * @param property property - * @param parameterType setter parameter type - * @return setter method + * @param target target {@link Object} + * @param propertyName property name + * @param parameterType setter property type + * @return the setter {@link Method} matching the provided signature */ - public static Method getSetter(Object target, String property, Class parameterType) { - String setterMethodName = SETTER_PREFIX + property.substring(0, 1).toUpperCase() + property.substring(1); + public static Method getSetter(Object target, String propertyName, Class parameterType) { + String setterMethodName = SETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); Method setter = getMethod(target, setterMethodName, parameterType); setter.setAccessible(true); return setter; } /** - * Get getter method + * Get the property getter {@link Method} with the given name belonging to + * the provided Java {@link Object}. * - * @param target target object - * @param property property - * @return setter method + * @param target target {@link Object} + * @param propertyName property name + * @return the getter {@link Method} matching the provided name */ - public static Method getGetter(Object target, String property) { - String getterMethodName = GETTER_PREFIX + property.substring(0, 1).toUpperCase() + property.substring(1); + public static Method getGetter(Object target, String propertyName) { + String getterMethodName = GETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); Method getter = getMethod(target, getterMethodName); getter.setAccessible(true); return getter; } /** - * Invoke target method + * Invoke the provided {@link Method} on the given Java {@link Object}. * - * @param target target object whose method we are invoking - * @param method method to invoke - * @param parameters method parameters - * @param return value object type - * @return return value + * @param target target {@link Object} whose method we are invoking + * @param method method to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the {@link Method} invocation */ - public static T invoke(Object target, Method method, Object... parameters) { + public static T invokeMethod(Object target, Method method, Object... parameters) { try { method.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) method.invoke(target, parameters); return returnValue; } catch (InvocationTargetException e) { - throw handleException(method.getName(), e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(method.getName(), e); + throw handleException(e); } } /** - * Invoke getter method with the given parameter + * Invoke the method with the provided signature (name and parameter types) + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param return value object type - * @return return value + * @param target target {@link Object} whose method we are invoking + * @param methodName method name to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the method invocation */ - public static T invokeGetter(Object target, String property) { - Method setter = getGetter(target, property); + public static T invokeMethod(Object target, String methodName, Object... parameters) { + try { + Class[] parameterClasses = new Class[parameters.length]; + + for (int i = 0; i < parameters.length; i++) { + parameterClasses[i] = parameters[i].getClass(); + } + + Method method = getMethod(target, methodName, parameterClasses); + method.setAccessible(true); + @SuppressWarnings("unchecked") + T returnValue = (T) method.invoke(target, parameters); + return returnValue; + } catch (InvocationTargetException e) { + throw handleException(e); + } catch (IllegalAccessException e) { + throw handleException(e); + } + } + + /** + * Invoke the property getter with the provided name on the given Java {@link Object}. + * + * @param target target {@link Object} whose property getter we are invoking + * @param propertyName property name whose getter we are invoking + * @param return value object type + * @return the value return by the getter invocation + */ + public static T invokeGetter(Object target, String propertyName) { + Method setter = getGetter(target, propertyName); try { return (T) setter.invoke(target); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the property setter with the provided signature (name and parameter types) + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, Object parameter) { - Method setter = getSetter(target, property, parameter.getClass()); + public static void invokeSetter(Object target, String propertyName, Object parameter) { + Method setter = getSetter(target, propertyName, parameter.getClass()); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the {@link boolean} property setter with the provided name + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter {@link boolean} parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, boolean parameter) { - Method setter = getSetter(target, property, boolean.class); + public static void invokeSetter(Object target, String propertyName, boolean parameter) { + Method setter = getSetter(target, propertyName, boolean.class); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the {@link int} property setter with the provided name + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter {@link int} parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, int parameter) { - Method setter = getSetter(target, property, int.class); + public static void invokeSetter(Object target, String propertyName, int parameter) { + Method setter = getSetter(target, propertyName, int.class); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke static Class method + * Invoke the {@code static} {@link Method} with the provided parameters. * - * @param method method to invoke - * @param parameters method parameters - * @param return value object type - * @return return value + * @param method target {@code static} {@link Method} to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the method invocation */ - public static T invokeStatic(Method method, Object... parameters) { + public static T invokeStaticMethod(Method method, Object... parameters) { try { method.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) method.invoke(null, parameters); return returnValue; } catch (InvocationTargetException e) { - throw handleException(method.getName(), e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(method.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Get the Java {@link Class} with the given fully-qualified name. * - * @param className class name to be retrieved - * @param return value object type - * @return Java {@link Class} object instance + * @param className the Java {@link Class} name to be retrieved + * @param {@link Class} type + * @return the Java {@link Class} object */ + @SuppressWarnings("unchecked") public static Class getClass(String className) { try { return (Class) Class.forName(className); } catch (ClassNotFoundException e) { - throw handleException(className, e); + throw handleException(e); } } @@ -309,74 +456,113 @@ public static Class getClassOrNull(String className) { } /** - * Handle {@link NoSuchFieldException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Get the Java Wrapper {@link Class} associated to the given primitive type. * - * @param fieldName field name - * @param e exception - * @return wrapped exception + * @param clazz primitive class + * @return the Java Wrapper {@link Class} + */ + public static Class getWrapperClass(Class clazz) { + if (!clazz.isPrimitive()) + return clazz; + + if (clazz == Integer.TYPE) + return Integer.class; + if (clazz == Long.TYPE) + return Long.class; + if (clazz == Boolean.TYPE) + return Boolean.class; + if (clazz == Byte.TYPE) + return Byte.class; + if (clazz == Character.TYPE) + return Character.class; + if (clazz == Float.TYPE) + return Float.class; + if (clazz == Double.TYPE) + return Double.class; + if (clazz == Short.TYPE) + return Short.class; + if (clazz == Void.TYPE) + return Void.class; + + return clazz; + } + + /** + * Get the first super class matching the provided package name. + * + * @param clazz Java class + * @param packageName package name + * @param class generic type + * @return the first super class matching the provided package name or {@code null}. + */ + public static Class getFirstSuperClassFromPackage(Class clazz, String packageName) { + if (clazz.getPackage().getName().equals(packageName)) { + return clazz; + } else { + Class superClass = clazz.getSuperclass(); + return (superClass == null || superClass.equals(Object.class)) ? + null : + (Class) getFirstSuperClassFromPackage(superClass, packageName); + } + } + + /** + * Handle the {@link NoSuchFieldException} by rethrowing it as an {@link IllegalArgumentException}. + * + * @param e the original {@link NoSuchFieldException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String fieldName, NoSuchFieldException e) { - LOGGER.error("Couldn't find field " + fieldName, e); + private static IllegalArgumentException handleException(NoSuchFieldException e) { return new IllegalArgumentException(e); } /** - * Handle {@link NoSuchMethodException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link NoSuchMethodException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param methodName method name - * @param e exception - * @return wrapped exception + * @param e the original {@link NoSuchMethodException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String methodName, NoSuchMethodException e) { - LOGGER.error("Couldn't find method " + methodName, e); + private static IllegalArgumentException handleException(NoSuchMethodException e) { return new IllegalArgumentException(e); } /** - * Handle {@link IllegalAccessException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link IllegalAccessException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param memberName member name - * @param e exception - * @return wrapped exception + * @param e the original {@link IllegalAccessException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String memberName, IllegalAccessException e) { - LOGGER.error("Couldn't access member " + memberName, e); + private static IllegalArgumentException handleException(IllegalAccessException e) { return new IllegalArgumentException(e); } /** - * Handle {@link InvocationTargetException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link InvocationTargetException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param methodName method name - * @param e exception - * @return wrapped exception + * @param e the original {@link InvocationTargetException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String methodName, InvocationTargetException e) { - LOGGER.error("Couldn't invoke method " + methodName, e); + private static IllegalArgumentException handleException(InvocationTargetException e) { return new IllegalArgumentException(e); } /** - * Handle {@link ClassNotFoundException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link ClassNotFoundException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param className class name - * @param e exception - * @return wrapped exception + * @param e the original {@link ClassNotFoundException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String className, ClassNotFoundException e) { - LOGGER.error("Couldn't find class " + className, e); + private static IllegalArgumentException handleException(ClassNotFoundException e) { return new IllegalArgumentException(e); } /** - * Handle {@link InstantiationException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link InstantiationException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param className class name - * @param e exception - * @return wrapped exception + * @param e the original {@link InstantiationException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String className, InstantiationException e) { - LOGGER.error("Couldn't instantiate class " + className, e); + private static IllegalArgumentException handleException(InstantiationException e) { return new IllegalArgumentException(e); } } diff --git a/hibernate-types-43/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java b/hibernate-types-43/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java index aed11cc99..514cd1f44 100644 --- a/hibernate-types-43/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java +++ b/hibernate-types-43/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java @@ -1,20 +1,37 @@ package com.vladmihalcea.hibernate.type; import com.vladmihalcea.hibernate.type.util.Configuration; +import com.vladmihalcea.hibernate.type.util.ReflectionUtils; +import org.dom4j.Node; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.metamodel.relational.Size; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.Type; +import org.hibernate.type.descriptor.java.IncomparableComparator; import org.hibernate.usertype.UserType; import java.io.Serializable; +import java.lang.reflect.Method; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Map; /** * Very convenient base class for implementing immutable object types using Hibernate {@link UserType}. + *

+ * The {@link ImmutableType} implements the {@link Type} interface too, so you can pass all + * types extending the {@link ImmutableType} to the {@link org.hibernate.SQLQuery#addScalar(String, Type)} + * method to fix the No Dialect mapping for JDBC type issues. * * @author Vlad Mihalcea */ -public abstract class ImmutableType implements UserType { +public abstract class ImmutableType implements UserType, Type { private final Configuration configuration; @@ -34,7 +51,7 @@ protected ImmutableType(Class clazz) { /** * Initialization constructor taking the {@link Class} and {@link Configuration} objects. * - * @param clazz the entity attribute {@link Class} type to be handled + * @param clazz the entity attribute {@link Class} type to be handled * @param configuration custom {@link Configuration} object. */ protected ImmutableType(Class clazz, Configuration configuration) { @@ -44,12 +61,40 @@ protected ImmutableType(Class clazz, Configuration configuration) { /** * Get the current {@link Configuration} object. + * * @return the current {@link Configuration} object. */ protected Configuration getConfiguration() { return configuration; } + /** + * Get the column value from the JDBC {@link ResultSet}. + * + * @param rs JDBC {@link ResultSet} + * @param names database column name + * @param session current Hibernate {@link org.hibernate.Session} + * @param owner current Hibernate {@link org.hibernate.SessionFactory} + * @return column value + * @throws SQLException in case of failure + */ + protected abstract T get(ResultSet rs, String[] names, + SessionImplementor session, Object owner) throws SQLException; + + /** + * Set the column value on the provided JDBC {@link PreparedStatement}. + * + * @param st JDBC {@link PreparedStatement} + * @param value database column value + * @param index database column index + * @param session current Hibernate {@link org.hibernate.Session} + * @throws SQLException in case of failure + */ + protected abstract void set(PreparedStatement st, T value, int index, + SessionImplementor session) throws SQLException; + + /* Methods inherited from the {@link UserType} interface */ + @Override public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws SQLException { @@ -62,13 +107,6 @@ public void nullSafeSet(PreparedStatement st, Object value, int index, set(st, clazz.cast(value), index, session); } - protected abstract T get(ResultSet rs, String[] names, - SessionImplementor session, Object owner) throws SQLException; - - protected abstract void set(PreparedStatement st, T value, int index, - SessionImplementor session) throws SQLException; - - @Override public Class returnedClass() { return clazz; @@ -108,4 +146,196 @@ public Object assemble(Serializable cached, Object owner) { public Object replace(Object o, Object target, Object owner) { return o; } + + /* Methods inherited from the {@link Type} interface */ + + @Override + public boolean isAssociationType() { + return false; + } + + @Override + public boolean isCollectionType() { + return false; + } + + @Override + public boolean isEntityType() { + return false; + } + + @Override + public boolean isAnyType() { + return false; + } + + @Override + public boolean isComponentType() { + return false; + } + + @Override + public int getColumnSpan(Mapping mapping) throws MappingException { + return 1; + } + + @Override + public int[] sqlTypes(Mapping mapping) throws MappingException { + return sqlTypes(); + } + + @Override + public Size[] dictatedSizes(Mapping mapping) throws MappingException { + return new Size[]{new Size()}; + } + + @Override + public Size[] defaultSizes(Mapping mapping) throws MappingException { + return dictatedSizes(mapping); + } + + @Override + public Class getReturnedClass() { + return returnedClass(); + } + + @Override + public boolean isSame(Object x, Object y) throws HibernateException { + return equals(x, y); + } + + @Override + public boolean isEqual(Object x, Object y) throws HibernateException { + return equals(x, y); + } + + @Override + public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) throws HibernateException { + return equals(x, y); + } + + @Override + public int getHashCode(Object x) throws HibernateException { + return hashCode(x); + } + + @Override + public int getHashCode(Object x, SessionFactoryImplementor factory) throws HibernateException { + return hashCode(x); + } + + @Override + public int compare(Object x, Object y) { + return IncomparableComparator.INSTANCE.compare(x, y); + } + + @Override + public final boolean isDirty(Object old, Object current, SessionImplementor session) { + return isDirty(old, current); + } + + @Override + public final boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) { + return checkable[0] && isDirty(old, current); + } + + protected final boolean isDirty(Object old, Object current) { + return !isSame(old, current); + } + + @Override + public boolean isModified(Object dbState, Object currentState, boolean[] checkable, SessionImplementor session) throws HibernateException { + return isDirty(dbState, currentState); + } + + @Override + public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner) throws HibernateException, SQLException { + return get(rs, new String[]{name}, session, owner); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session) throws HibernateException, SQLException { + set(st, returnedClass().cast(value), index, session); + } + + @Override + public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException { + return String.valueOf(value); + } + + @Override + public String getName() { + return getClass().getSimpleName(); + } + + @Override + public Object deepCopy(Object value, SessionFactoryImplementor factory) throws HibernateException { + return deepCopy(value); + } + + @Override + public Serializable disassemble(Object value, SessionImplementor session, Object owner) throws HibernateException { + return disassemble(value); + } + + @Override + public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException { + return assemble(cached, session); + } + + @Override + public void beforeAssemble(Serializable cached, SessionImplementor session) { + + } + + @Override + public Object hydrate(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { + return nullSafeGet(rs, names, session, owner); + } + + @Override + public Object resolve(Object value, SessionImplementor session, Object owner) throws HibernateException { + return value; + } + + @Override + public Object semiResolve(Object value, SessionImplementor session, Object owner) throws HibernateException { + return value; + } + + @Override + public Type getSemiResolvedType(SessionFactoryImplementor factory) { + return this; + } + + @Override + public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache) throws HibernateException { + return replace(original, target, owner); + } + + @Override + public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache, ForeignKeyDirection foreignKeyDirection) throws HibernateException { + return replace(original, target, owner); + } + + @Override + public boolean[] toColumnNullness(Object value, Mapping mapping) { + return value == null ? ArrayHelper.FALSE : ArrayHelper.TRUE; + } + + @Override + public boolean isXMLElement() { + return false; + } + + @Override + public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) throws HibernateException { + node.setText(toLoggableString(value, factory)); + } + + @Override + public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException { + Method valueOfMethod = ReflectionUtils.getMethodOrNull(clazz, "valueOf", String.class); + return valueOfMethod != null ? ReflectionUtils.invokeStaticMethod(valueOfMethod, xml.getText()) : null; + } } \ No newline at end of file diff --git a/hibernate-types-43/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java b/hibernate-types-43/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java index e8fceeee6..03ffe2eaf 100644 --- a/hibernate-types-43/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java +++ b/hibernate-types-43/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java @@ -1,8 +1,5 @@ package com.vladmihalcea.hibernate.type.util; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -15,58 +12,144 @@ */ public final class ReflectionUtils { - public static final String GETTER_PREFIX = "get"; - public static final String SETTER_PREFIX = "set"; - private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtils.class); + private static final String GETTER_PREFIX = "get"; + + private static final String SETTER_PREFIX = "set"; + /** + * Prevent any instantiation. + */ private ReflectionUtils() { - throw new UnsupportedOperationException("ReflectionUtils is not instantiable!"); + throw new UnsupportedOperationException("The " + getClass() + " is not instantiable!"); } /** - * Instantiate object + * Instantiate a new {@link Object} of the provided type. * - * @param className Class for object to instantiate - * @param field type - * @return field value + * @param className The fully-qualified Java class name of the {@link Object} to instantiate + * @param class type + * @return new Java {@link Object} of the provided type */ public static T newInstance(String className) { try { Class clazz = Class.forName(className); - return (T) clazz.newInstance(); + return newInstance(clazz); } catch (ClassNotFoundException e) { - throw handleException(className, e); + throw handleException(e); + } + } + + /** + * Instantiate a new {@link Object} of the provided type. + * + * @param clazz The Java {@link Class} of the {@link Object} to instantiate + * @param class type + * @return new Java {@link Object} of the provided type + */ + @SuppressWarnings("unchecked") + public static T newInstance(Class clazz) { + try { + return (T) clazz.newInstance(); } catch (InstantiationException e) { - throw handleException(className, e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(className, e); + throw handleException(e); } } /** - * Get target object field value + * Get the {@link Field} with the given name belonging to the provided Java {@link Class}. * - * @param target target object + * @param targetClass the provided Java {@link Class} the field belongs to + * @param fieldName the {@link Field} name + * @return the {@link Field} matching the given name + */ + public static Field getField(Class targetClass, String fieldName) { + Field field = null; + + try { + field = targetClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + try { + field = targetClass.getField(fieldName); + } catch (NoSuchFieldException ignore) { + } + + if (!targetClass.getSuperclass().equals(Object.class)) { + return getField(targetClass.getSuperclass(), fieldName); + } else { + throw handleException(e); + } + } finally { + if (field != null) { + field.setAccessible(true); + } + } + + return field; + } + + /** + * Get the {@link Field} with the given name belonging to the provided Java {@link Class} or {@code null} + * if no {@link Field} was found. + * + * @param targetClass the provided Java {@link Class} the field belongs to + * @param fieldName the {@link Field} name + * @return the {@link Field} matching the given name or {@code null} + */ + public static Field getFieldOrNull(Class targetClass, String fieldName) { + try { + Field field = targetClass.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException e) { + return null; + } + } + + /** + * Get the value of the field matching the given name and belonging to target {@link Object}. + * + * @param target target {@link Object} whose field we are retrieving the value from * @param fieldName field name * @param field type * @return field value */ public static T getFieldValue(Object target, String fieldName) { try { - Field field = target.getClass().getDeclaredField(fieldName); + Field field = getField(target.getClass(), fieldName); field.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) field.get(target); return returnValue; - } catch (NoSuchFieldException e) { - throw handleException(fieldName, e); } catch (IllegalAccessException e) { - throw handleException(fieldName, e); + throw handleException(e); } } /** - * Set target object field value + * Get the value of the field matching the given name and belonging to target {@link Object} or {@code null} + * if no {@link Field} was found.. + * + * @param target target {@link Object} whose field we are retrieving the value from + * @param fieldName field name + * @param field type + * @return field value matching the given name or {@code null} + */ + public static T getFieldValueOrNull(Object target, String fieldName) { + try { + Field field = getField(target.getClass(), fieldName); + field.setAccessible(true); + @SuppressWarnings("unchecked") + T returnValue = (T) field.get(target); + return returnValue; + } catch (IllegalAccessException e) { + return null; + } + } + + /** + * Set the value of the field matching the given name and belonging to target {@link Object}. * * @param target target object * @param fieldName field name @@ -78,24 +161,52 @@ public static void setFieldValue(Object target, String fieldName, Object value) field.setAccessible(true); field.set(target, value); } catch (NoSuchFieldException e) { - throw handleException(fieldName, e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(fieldName, e); + throw handleException(e); } } /** - * Get target method + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Object}. * - * @param target target object + * @param target target {@link Object} * @param methodName method name * @param parameterTypes method parameter types - * @return return value + * @return return {@link Method} matching the provided signature */ public static Method getMethod(Object target, String methodName, Class... parameterTypes) { return getMethod(target.getClass(), methodName, parameterTypes); } + /** + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Object} or {@code null} if no {@link Method} was found. + * + * @param target target {@link Object} + * @param methodName method name + * @param parameterTypes method parameter types + * @return return {@link Method} matching the provided signature or {@code null} + */ + public static Method getMethodOrNull(Object target, String methodName, Class... parameterTypes) { + try { + return getMethod(target.getClass(), methodName, parameterTypes); + } catch (RuntimeException e) { + return null; + } + } + + /** + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Class}. + * + * @param targetClass target {@link Class} + * @param methodName method name + * @param parameterTypes method parameter types + * @return the {@link Method} matching the provided signature + */ + @SuppressWarnings("unchecked") public static Method getMethod(Class targetClass, String methodName, Class... parameterTypes) { try { return targetClass.getDeclaredMethod(methodName, parameterTypes); @@ -105,22 +216,22 @@ public static Method getMethod(Class targetClass, String methodName, Class... pa } catch (NoSuchMethodException ignore) { } - if(!targetClass.getSuperclass().equals(Object.class)) { + if (!targetClass.getSuperclass().equals(Object.class)) { return getMethod(targetClass.getSuperclass(), methodName, parameterTypes); - } - else { - throw handleException(methodName, e); + } else { + throw handleException(e); } } } /** - * Check if target class has the given method + * Check if the provided Java {@link Class} contains a method matching + * the given signature (name and parameter types). * - * @param targetClass target class + * @param targetClass target {@link Class} * @param methodName method name * @param parameterTypes method parameter types - * @return method availability + * @return the provided Java {@link Class} contains a method with the given signature */ public static boolean hasMethod(Class targetClass, String methodName, Class... parameterTypes) { try { @@ -132,162 +243,198 @@ public static boolean hasMethod(Class targetClass, String methodName, Class.. } /** - * Get setter method + * Get the property setter {@link Method} with the given signature (name and parameter types) + * belonging to the provided Java {@link Object}. * - * @param target target object - * @param property property - * @param parameterType setter parameter type - * @return setter method + * @param target target {@link Object} + * @param propertyName property name + * @param parameterType setter property type + * @return the setter {@link Method} matching the provided signature */ - public static Method getSetter(Object target, String property, Class parameterType) { - String setterMethodName = SETTER_PREFIX + property.substring(0, 1).toUpperCase() + property.substring(1); + public static Method getSetter(Object target, String propertyName, Class parameterType) { + String setterMethodName = SETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); Method setter = getMethod(target, setterMethodName, parameterType); setter.setAccessible(true); return setter; } /** - * Get getter method + * Get the property getter {@link Method} with the given name belonging to + * the provided Java {@link Object}. * - * @param target target object - * @param property property - * @return setter method + * @param target target {@link Object} + * @param propertyName property name + * @return the getter {@link Method} matching the provided name */ - public static Method getGetter(Object target, String property) { - String getterMethodName = GETTER_PREFIX + property.substring(0, 1).toUpperCase() + property.substring(1); + public static Method getGetter(Object target, String propertyName) { + String getterMethodName = GETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); Method getter = getMethod(target, getterMethodName); getter.setAccessible(true); return getter; } /** - * Invoke target method + * Invoke the provided {@link Method} on the given Java {@link Object}. * - * @param target target object whose method we are invoking - * @param method method to invoke - * @param parameters method parameters - * @param return value object type - * @return return value + * @param target target {@link Object} whose method we are invoking + * @param method method to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the {@link Method} invocation */ - public static T invoke(Object target, Method method, Object... parameters) { + public static T invokeMethod(Object target, Method method, Object... parameters) { try { method.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) method.invoke(target, parameters); return returnValue; } catch (InvocationTargetException e) { - throw handleException(method.getName(), e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(method.getName(), e); + throw handleException(e); } } /** - * Invoke getter method with the given parameter + * Invoke the method with the provided signature (name and parameter types) + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param return value object type - * @return return value + * @param target target {@link Object} whose method we are invoking + * @param methodName method name to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the method invocation */ - public static T invokeGetter(Object target, String property) { - Method setter = getGetter(target, property); + public static T invokeMethod(Object target, String methodName, Object... parameters) { + try { + Class[] parameterClasses = new Class[parameters.length]; + + for (int i = 0; i < parameters.length; i++) { + parameterClasses[i] = parameters[i].getClass(); + } + + Method method = getMethod(target, methodName, parameterClasses); + method.setAccessible(true); + @SuppressWarnings("unchecked") + T returnValue = (T) method.invoke(target, parameters); + return returnValue; + } catch (InvocationTargetException e) { + throw handleException(e); + } catch (IllegalAccessException e) { + throw handleException(e); + } + } + + /** + * Invoke the property getter with the provided name on the given Java {@link Object}. + * + * @param target target {@link Object} whose property getter we are invoking + * @param propertyName property name whose getter we are invoking + * @param return value object type + * @return the value return by the getter invocation + */ + public static T invokeGetter(Object target, String propertyName) { + Method setter = getGetter(target, propertyName); try { return (T) setter.invoke(target); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the property setter with the provided signature (name and parameter types) + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, Object parameter) { - Method setter = getSetter(target, property, parameter.getClass()); + public static void invokeSetter(Object target, String propertyName, Object parameter) { + Method setter = getSetter(target, propertyName, parameter.getClass()); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the {@link boolean} property setter with the provided name + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter {@link boolean} parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, boolean parameter) { - Method setter = getSetter(target, property, boolean.class); + public static void invokeSetter(Object target, String propertyName, boolean parameter) { + Method setter = getSetter(target, propertyName, boolean.class); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the {@link int} property setter with the provided name + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter {@link int} parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, int parameter) { - Method setter = getSetter(target, property, int.class); + public static void invokeSetter(Object target, String propertyName, int parameter) { + Method setter = getSetter(target, propertyName, int.class); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke static Class method + * Invoke the {@code static} {@link Method} with the provided parameters. * - * @param method method to invoke - * @param parameters method parameters - * @param return value object type - * @return return value + * @param method target {@code static} {@link Method} to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the method invocation */ - public static T invokeStatic(Method method, Object... parameters) { + public static T invokeStaticMethod(Method method, Object... parameters) { try { method.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) method.invoke(null, parameters); return returnValue; } catch (InvocationTargetException e) { - throw handleException(method.getName(), e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(method.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Get the Java {@link Class} with the given fully-qualified name. * - * @param className class name to be retrieved - * @param return value object type - * @return Java {@link Class} object instance + * @param className the Java {@link Class} name to be retrieved + * @param {@link Class} type + * @return the Java {@link Class} object */ + @SuppressWarnings("unchecked") public static Class getClass(String className) { try { return (Class) Class.forName(className); } catch (ClassNotFoundException e) { - throw handleException(className, e); + throw handleException(e); } } @@ -309,74 +456,113 @@ public static Class getClassOrNull(String className) { } /** - * Handle {@link NoSuchFieldException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Get the Java Wrapper {@link Class} associated to the given primitive type. * - * @param fieldName field name - * @param e exception - * @return wrapped exception + * @param clazz primitive class + * @return the Java Wrapper {@link Class} + */ + public static Class getWrapperClass(Class clazz) { + if (!clazz.isPrimitive()) + return clazz; + + if (clazz == Integer.TYPE) + return Integer.class; + if (clazz == Long.TYPE) + return Long.class; + if (clazz == Boolean.TYPE) + return Boolean.class; + if (clazz == Byte.TYPE) + return Byte.class; + if (clazz == Character.TYPE) + return Character.class; + if (clazz == Float.TYPE) + return Float.class; + if (clazz == Double.TYPE) + return Double.class; + if (clazz == Short.TYPE) + return Short.class; + if (clazz == Void.TYPE) + return Void.class; + + return clazz; + } + + /** + * Get the first super class matching the provided package name. + * + * @param clazz Java class + * @param packageName package name + * @param class generic type + * @return the first super class matching the provided package name or {@code null}. + */ + public static Class getFirstSuperClassFromPackage(Class clazz, String packageName) { + if (clazz.getPackage().getName().equals(packageName)) { + return clazz; + } else { + Class superClass = clazz.getSuperclass(); + return (superClass == null || superClass.equals(Object.class)) ? + null : + (Class) getFirstSuperClassFromPackage(superClass, packageName); + } + } + + /** + * Handle the {@link NoSuchFieldException} by rethrowing it as an {@link IllegalArgumentException}. + * + * @param e the original {@link NoSuchFieldException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String fieldName, NoSuchFieldException e) { - LOGGER.error("Couldn't find field " + fieldName, e); + private static IllegalArgumentException handleException(NoSuchFieldException e) { return new IllegalArgumentException(e); } /** - * Handle {@link NoSuchMethodException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link NoSuchMethodException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param methodName method name - * @param e exception - * @return wrapped exception + * @param e the original {@link NoSuchMethodException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String methodName, NoSuchMethodException e) { - LOGGER.error("Couldn't find method " + methodName, e); + private static IllegalArgumentException handleException(NoSuchMethodException e) { return new IllegalArgumentException(e); } /** - * Handle {@link IllegalAccessException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link IllegalAccessException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param memberName member name - * @param e exception - * @return wrapped exception + * @param e the original {@link IllegalAccessException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String memberName, IllegalAccessException e) { - LOGGER.error("Couldn't access member " + memberName, e); + private static IllegalArgumentException handleException(IllegalAccessException e) { return new IllegalArgumentException(e); } /** - * Handle {@link InvocationTargetException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link InvocationTargetException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param methodName method name - * @param e exception - * @return wrapped exception + * @param e the original {@link InvocationTargetException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String methodName, InvocationTargetException e) { - LOGGER.error("Couldn't invoke method " + methodName, e); + private static IllegalArgumentException handleException(InvocationTargetException e) { return new IllegalArgumentException(e); } /** - * Handle {@link ClassNotFoundException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link ClassNotFoundException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param className class name - * @param e exception - * @return wrapped exception + * @param e the original {@link ClassNotFoundException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String className, ClassNotFoundException e) { - LOGGER.error("Couldn't find class " + className, e); + private static IllegalArgumentException handleException(ClassNotFoundException e) { return new IllegalArgumentException(e); } /** - * Handle {@link InstantiationException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link InstantiationException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param className class name - * @param e exception - * @return wrapped exception + * @param e the original {@link InstantiationException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String className, InstantiationException e) { - LOGGER.error("Couldn't instantiate class " + className, e); + private static IllegalArgumentException handleException(InstantiationException e) { return new IllegalArgumentException(e); } } diff --git a/hibernate-types-5/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java b/hibernate-types-5/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java index aed11cc99..1bc5cf4a0 100644 --- a/hibernate-types-5/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java +++ b/hibernate-types-5/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java @@ -1,20 +1,34 @@ package com.vladmihalcea.hibernate.type; import com.vladmihalcea.hibernate.type.util.Configuration; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.jdbc.Size; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.Type; +import org.hibernate.type.descriptor.java.IncomparableComparator; import org.hibernate.usertype.UserType; import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Map; /** * Very convenient base class for implementing immutable object types using Hibernate {@link UserType}. + *

+ * The {@link ImmutableType} implements the {@link Type} interface too, so you can pass all + * types extending the {@link ImmutableType} to the {@link org.hibernate.SQLQuery#addScalar(String, Type)} + * method to fix the No Dialect mapping for JDBC type issues. * * @author Vlad Mihalcea */ -public abstract class ImmutableType implements UserType { +public abstract class ImmutableType implements UserType, Type { private final Configuration configuration; @@ -34,7 +48,7 @@ protected ImmutableType(Class clazz) { /** * Initialization constructor taking the {@link Class} and {@link Configuration} objects. * - * @param clazz the entity attribute {@link Class} type to be handled + * @param clazz the entity attribute {@link Class} type to be handled * @param configuration custom {@link Configuration} object. */ protected ImmutableType(Class clazz, Configuration configuration) { @@ -44,12 +58,40 @@ protected ImmutableType(Class clazz, Configuration configuration) { /** * Get the current {@link Configuration} object. + * * @return the current {@link Configuration} object. */ protected Configuration getConfiguration() { return configuration; } + /** + * Get the column value from the JDBC {@link ResultSet}. + * + * @param rs JDBC {@link ResultSet} + * @param names database column name + * @param session current Hibernate {@link org.hibernate.Session} + * @param owner current Hibernate {@link org.hibernate.SessionFactory} + * @return column value + * @throws SQLException in case of failure + */ + protected abstract T get(ResultSet rs, String[] names, + SessionImplementor session, Object owner) throws SQLException; + + /** + * Set the column value on the provided JDBC {@link PreparedStatement}. + * + * @param st JDBC {@link PreparedStatement} + * @param value database column value + * @param index database column index + * @param session current Hibernate {@link org.hibernate.Session} + * @throws SQLException in case of failure + */ + protected abstract void set(PreparedStatement st, T value, int index, + SessionImplementor session) throws SQLException; + + /* Methods inherited from the {@link UserType} interface */ + @Override public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws SQLException { @@ -62,13 +104,6 @@ public void nullSafeSet(PreparedStatement st, Object value, int index, set(st, clazz.cast(value), index, session); } - protected abstract T get(ResultSet rs, String[] names, - SessionImplementor session, Object owner) throws SQLException; - - protected abstract void set(PreparedStatement st, T value, int index, - SessionImplementor session) throws SQLException; - - @Override public Class returnedClass() { return clazz; @@ -108,4 +143,180 @@ public Object assemble(Serializable cached, Object owner) { public Object replace(Object o, Object target, Object owner) { return o; } + + /* Methods inherited from the {@link Type} interface */ + + @Override + public boolean isAssociationType() { + return false; + } + + @Override + public boolean isCollectionType() { + return false; + } + + @Override + public boolean isEntityType() { + return false; + } + + @Override + public boolean isAnyType() { + return false; + } + + @Override + public boolean isComponentType() { + return false; + } + + @Override + public int getColumnSpan(Mapping mapping) throws MappingException { + return 1; + } + + @Override + public int[] sqlTypes(Mapping mapping) throws MappingException { + return sqlTypes(); + } + + @Override + public Size[] dictatedSizes(Mapping mapping) throws MappingException { + return new Size[]{new Size()}; + } + + @Override + public Size[] defaultSizes(Mapping mapping) throws MappingException { + return dictatedSizes(mapping); + } + + @Override + public Class getReturnedClass() { + return returnedClass(); + } + + @Override + public boolean isSame(Object x, Object y) throws HibernateException { + return equals(x, y); + } + + @Override + public boolean isEqual(Object x, Object y) throws HibernateException { + return equals(x, y); + } + + @Override + public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) throws HibernateException { + return equals(x, y); + } + + @Override + public int getHashCode(Object x) throws HibernateException { + return hashCode(x); + } + + @Override + public int getHashCode(Object x, SessionFactoryImplementor factory) throws HibernateException { + return hashCode(x); + } + + @Override + public int compare(Object x, Object y) { + return IncomparableComparator.INSTANCE.compare(x, y); + } + + @Override + public final boolean isDirty(Object old, Object current, SessionImplementor session) { + return isDirty(old, current); + } + + @Override + public final boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) { + return checkable[0] && isDirty(old, current); + } + + protected final boolean isDirty(Object old, Object current) { + return !isSame(old, current); + } + + @Override + public boolean isModified(Object dbState, Object currentState, boolean[] checkable, SessionImplementor session) throws HibernateException { + return isDirty(dbState, currentState); + } + + @Override + public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner) throws HibernateException, SQLException { + return get(rs, new String[]{name}, session, owner); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session) throws HibernateException, SQLException { + set(st, returnedClass().cast(value), index, session); + } + + @Override + public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException { + return String.valueOf(value); + } + + @Override + public String getName() { + return getClass().getSimpleName(); + } + + @Override + public Object deepCopy(Object value, SessionFactoryImplementor factory) throws HibernateException { + return deepCopy(value); + } + + @Override + public Serializable disassemble(Object value, SessionImplementor session, Object owner) throws HibernateException { + return disassemble(value); + } + + @Override + public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException { + return assemble(cached, session); + } + + @Override + public void beforeAssemble(Serializable cached, SessionImplementor session) { + + } + + @Override + public Object hydrate(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { + return nullSafeGet(rs, names, session, owner); + } + + @Override + public Object resolve(Object value, SessionImplementor session, Object owner) throws HibernateException { + return value; + } + + @Override + public Object semiResolve(Object value, SessionImplementor session, Object owner) throws HibernateException { + return value; + } + + @Override + public Type getSemiResolvedType(SessionFactoryImplementor factory) { + return this; + } + + @Override + public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache) throws HibernateException { + return replace(original, target, owner); + } + + @Override + public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache, ForeignKeyDirection foreignKeyDirection) throws HibernateException { + return replace(original, target, owner); + } + + @Override + public boolean[] toColumnNullness(Object value, Mapping mapping) { + return value == null ? ArrayHelper.FALSE : ArrayHelper.TRUE; + } } \ No newline at end of file diff --git a/hibernate-types-5/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java b/hibernate-types-5/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java index e8fceeee6..03ffe2eaf 100644 --- a/hibernate-types-5/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java +++ b/hibernate-types-5/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java @@ -1,8 +1,5 @@ package com.vladmihalcea.hibernate.type.util; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -15,58 +12,144 @@ */ public final class ReflectionUtils { - public static final String GETTER_PREFIX = "get"; - public static final String SETTER_PREFIX = "set"; - private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtils.class); + private static final String GETTER_PREFIX = "get"; + + private static final String SETTER_PREFIX = "set"; + /** + * Prevent any instantiation. + */ private ReflectionUtils() { - throw new UnsupportedOperationException("ReflectionUtils is not instantiable!"); + throw new UnsupportedOperationException("The " + getClass() + " is not instantiable!"); } /** - * Instantiate object + * Instantiate a new {@link Object} of the provided type. * - * @param className Class for object to instantiate - * @param field type - * @return field value + * @param className The fully-qualified Java class name of the {@link Object} to instantiate + * @param class type + * @return new Java {@link Object} of the provided type */ public static T newInstance(String className) { try { Class clazz = Class.forName(className); - return (T) clazz.newInstance(); + return newInstance(clazz); } catch (ClassNotFoundException e) { - throw handleException(className, e); + throw handleException(e); + } + } + + /** + * Instantiate a new {@link Object} of the provided type. + * + * @param clazz The Java {@link Class} of the {@link Object} to instantiate + * @param class type + * @return new Java {@link Object} of the provided type + */ + @SuppressWarnings("unchecked") + public static T newInstance(Class clazz) { + try { + return (T) clazz.newInstance(); } catch (InstantiationException e) { - throw handleException(className, e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(className, e); + throw handleException(e); } } /** - * Get target object field value + * Get the {@link Field} with the given name belonging to the provided Java {@link Class}. * - * @param target target object + * @param targetClass the provided Java {@link Class} the field belongs to + * @param fieldName the {@link Field} name + * @return the {@link Field} matching the given name + */ + public static Field getField(Class targetClass, String fieldName) { + Field field = null; + + try { + field = targetClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + try { + field = targetClass.getField(fieldName); + } catch (NoSuchFieldException ignore) { + } + + if (!targetClass.getSuperclass().equals(Object.class)) { + return getField(targetClass.getSuperclass(), fieldName); + } else { + throw handleException(e); + } + } finally { + if (field != null) { + field.setAccessible(true); + } + } + + return field; + } + + /** + * Get the {@link Field} with the given name belonging to the provided Java {@link Class} or {@code null} + * if no {@link Field} was found. + * + * @param targetClass the provided Java {@link Class} the field belongs to + * @param fieldName the {@link Field} name + * @return the {@link Field} matching the given name or {@code null} + */ + public static Field getFieldOrNull(Class targetClass, String fieldName) { + try { + Field field = targetClass.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException e) { + return null; + } + } + + /** + * Get the value of the field matching the given name and belonging to target {@link Object}. + * + * @param target target {@link Object} whose field we are retrieving the value from * @param fieldName field name * @param field type * @return field value */ public static T getFieldValue(Object target, String fieldName) { try { - Field field = target.getClass().getDeclaredField(fieldName); + Field field = getField(target.getClass(), fieldName); field.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) field.get(target); return returnValue; - } catch (NoSuchFieldException e) { - throw handleException(fieldName, e); } catch (IllegalAccessException e) { - throw handleException(fieldName, e); + throw handleException(e); } } /** - * Set target object field value + * Get the value of the field matching the given name and belonging to target {@link Object} or {@code null} + * if no {@link Field} was found.. + * + * @param target target {@link Object} whose field we are retrieving the value from + * @param fieldName field name + * @param field type + * @return field value matching the given name or {@code null} + */ + public static T getFieldValueOrNull(Object target, String fieldName) { + try { + Field field = getField(target.getClass(), fieldName); + field.setAccessible(true); + @SuppressWarnings("unchecked") + T returnValue = (T) field.get(target); + return returnValue; + } catch (IllegalAccessException e) { + return null; + } + } + + /** + * Set the value of the field matching the given name and belonging to target {@link Object}. * * @param target target object * @param fieldName field name @@ -78,24 +161,52 @@ public static void setFieldValue(Object target, String fieldName, Object value) field.setAccessible(true); field.set(target, value); } catch (NoSuchFieldException e) { - throw handleException(fieldName, e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(fieldName, e); + throw handleException(e); } } /** - * Get target method + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Object}. * - * @param target target object + * @param target target {@link Object} * @param methodName method name * @param parameterTypes method parameter types - * @return return value + * @return return {@link Method} matching the provided signature */ public static Method getMethod(Object target, String methodName, Class... parameterTypes) { return getMethod(target.getClass(), methodName, parameterTypes); } + /** + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Object} or {@code null} if no {@link Method} was found. + * + * @param target target {@link Object} + * @param methodName method name + * @param parameterTypes method parameter types + * @return return {@link Method} matching the provided signature or {@code null} + */ + public static Method getMethodOrNull(Object target, String methodName, Class... parameterTypes) { + try { + return getMethod(target.getClass(), methodName, parameterTypes); + } catch (RuntimeException e) { + return null; + } + } + + /** + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Class}. + * + * @param targetClass target {@link Class} + * @param methodName method name + * @param parameterTypes method parameter types + * @return the {@link Method} matching the provided signature + */ + @SuppressWarnings("unchecked") public static Method getMethod(Class targetClass, String methodName, Class... parameterTypes) { try { return targetClass.getDeclaredMethod(methodName, parameterTypes); @@ -105,22 +216,22 @@ public static Method getMethod(Class targetClass, String methodName, Class... pa } catch (NoSuchMethodException ignore) { } - if(!targetClass.getSuperclass().equals(Object.class)) { + if (!targetClass.getSuperclass().equals(Object.class)) { return getMethod(targetClass.getSuperclass(), methodName, parameterTypes); - } - else { - throw handleException(methodName, e); + } else { + throw handleException(e); } } } /** - * Check if target class has the given method + * Check if the provided Java {@link Class} contains a method matching + * the given signature (name and parameter types). * - * @param targetClass target class + * @param targetClass target {@link Class} * @param methodName method name * @param parameterTypes method parameter types - * @return method availability + * @return the provided Java {@link Class} contains a method with the given signature */ public static boolean hasMethod(Class targetClass, String methodName, Class... parameterTypes) { try { @@ -132,162 +243,198 @@ public static boolean hasMethod(Class targetClass, String methodName, Class.. } /** - * Get setter method + * Get the property setter {@link Method} with the given signature (name and parameter types) + * belonging to the provided Java {@link Object}. * - * @param target target object - * @param property property - * @param parameterType setter parameter type - * @return setter method + * @param target target {@link Object} + * @param propertyName property name + * @param parameterType setter property type + * @return the setter {@link Method} matching the provided signature */ - public static Method getSetter(Object target, String property, Class parameterType) { - String setterMethodName = SETTER_PREFIX + property.substring(0, 1).toUpperCase() + property.substring(1); + public static Method getSetter(Object target, String propertyName, Class parameterType) { + String setterMethodName = SETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); Method setter = getMethod(target, setterMethodName, parameterType); setter.setAccessible(true); return setter; } /** - * Get getter method + * Get the property getter {@link Method} with the given name belonging to + * the provided Java {@link Object}. * - * @param target target object - * @param property property - * @return setter method + * @param target target {@link Object} + * @param propertyName property name + * @return the getter {@link Method} matching the provided name */ - public static Method getGetter(Object target, String property) { - String getterMethodName = GETTER_PREFIX + property.substring(0, 1).toUpperCase() + property.substring(1); + public static Method getGetter(Object target, String propertyName) { + String getterMethodName = GETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); Method getter = getMethod(target, getterMethodName); getter.setAccessible(true); return getter; } /** - * Invoke target method + * Invoke the provided {@link Method} on the given Java {@link Object}. * - * @param target target object whose method we are invoking - * @param method method to invoke - * @param parameters method parameters - * @param return value object type - * @return return value + * @param target target {@link Object} whose method we are invoking + * @param method method to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the {@link Method} invocation */ - public static T invoke(Object target, Method method, Object... parameters) { + public static T invokeMethod(Object target, Method method, Object... parameters) { try { method.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) method.invoke(target, parameters); return returnValue; } catch (InvocationTargetException e) { - throw handleException(method.getName(), e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(method.getName(), e); + throw handleException(e); } } /** - * Invoke getter method with the given parameter + * Invoke the method with the provided signature (name and parameter types) + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param return value object type - * @return return value + * @param target target {@link Object} whose method we are invoking + * @param methodName method name to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the method invocation */ - public static T invokeGetter(Object target, String property) { - Method setter = getGetter(target, property); + public static T invokeMethod(Object target, String methodName, Object... parameters) { + try { + Class[] parameterClasses = new Class[parameters.length]; + + for (int i = 0; i < parameters.length; i++) { + parameterClasses[i] = parameters[i].getClass(); + } + + Method method = getMethod(target, methodName, parameterClasses); + method.setAccessible(true); + @SuppressWarnings("unchecked") + T returnValue = (T) method.invoke(target, parameters); + return returnValue; + } catch (InvocationTargetException e) { + throw handleException(e); + } catch (IllegalAccessException e) { + throw handleException(e); + } + } + + /** + * Invoke the property getter with the provided name on the given Java {@link Object}. + * + * @param target target {@link Object} whose property getter we are invoking + * @param propertyName property name whose getter we are invoking + * @param return value object type + * @return the value return by the getter invocation + */ + public static T invokeGetter(Object target, String propertyName) { + Method setter = getGetter(target, propertyName); try { return (T) setter.invoke(target); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the property setter with the provided signature (name and parameter types) + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, Object parameter) { - Method setter = getSetter(target, property, parameter.getClass()); + public static void invokeSetter(Object target, String propertyName, Object parameter) { + Method setter = getSetter(target, propertyName, parameter.getClass()); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the {@link boolean} property setter with the provided name + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter {@link boolean} parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, boolean parameter) { - Method setter = getSetter(target, property, boolean.class); + public static void invokeSetter(Object target, String propertyName, boolean parameter) { + Method setter = getSetter(target, propertyName, boolean.class); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the {@link int} property setter with the provided name + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter {@link int} parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, int parameter) { - Method setter = getSetter(target, property, int.class); + public static void invokeSetter(Object target, String propertyName, int parameter) { + Method setter = getSetter(target, propertyName, int.class); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke static Class method + * Invoke the {@code static} {@link Method} with the provided parameters. * - * @param method method to invoke - * @param parameters method parameters - * @param return value object type - * @return return value + * @param method target {@code static} {@link Method} to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the method invocation */ - public static T invokeStatic(Method method, Object... parameters) { + public static T invokeStaticMethod(Method method, Object... parameters) { try { method.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) method.invoke(null, parameters); return returnValue; } catch (InvocationTargetException e) { - throw handleException(method.getName(), e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(method.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Get the Java {@link Class} with the given fully-qualified name. * - * @param className class name to be retrieved - * @param return value object type - * @return Java {@link Class} object instance + * @param className the Java {@link Class} name to be retrieved + * @param {@link Class} type + * @return the Java {@link Class} object */ + @SuppressWarnings("unchecked") public static Class getClass(String className) { try { return (Class) Class.forName(className); } catch (ClassNotFoundException e) { - throw handleException(className, e); + throw handleException(e); } } @@ -309,74 +456,113 @@ public static Class getClassOrNull(String className) { } /** - * Handle {@link NoSuchFieldException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Get the Java Wrapper {@link Class} associated to the given primitive type. * - * @param fieldName field name - * @param e exception - * @return wrapped exception + * @param clazz primitive class + * @return the Java Wrapper {@link Class} + */ + public static Class getWrapperClass(Class clazz) { + if (!clazz.isPrimitive()) + return clazz; + + if (clazz == Integer.TYPE) + return Integer.class; + if (clazz == Long.TYPE) + return Long.class; + if (clazz == Boolean.TYPE) + return Boolean.class; + if (clazz == Byte.TYPE) + return Byte.class; + if (clazz == Character.TYPE) + return Character.class; + if (clazz == Float.TYPE) + return Float.class; + if (clazz == Double.TYPE) + return Double.class; + if (clazz == Short.TYPE) + return Short.class; + if (clazz == Void.TYPE) + return Void.class; + + return clazz; + } + + /** + * Get the first super class matching the provided package name. + * + * @param clazz Java class + * @param packageName package name + * @param class generic type + * @return the first super class matching the provided package name or {@code null}. + */ + public static Class getFirstSuperClassFromPackage(Class clazz, String packageName) { + if (clazz.getPackage().getName().equals(packageName)) { + return clazz; + } else { + Class superClass = clazz.getSuperclass(); + return (superClass == null || superClass.equals(Object.class)) ? + null : + (Class) getFirstSuperClassFromPackage(superClass, packageName); + } + } + + /** + * Handle the {@link NoSuchFieldException} by rethrowing it as an {@link IllegalArgumentException}. + * + * @param e the original {@link NoSuchFieldException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String fieldName, NoSuchFieldException e) { - LOGGER.error("Couldn't find field " + fieldName, e); + private static IllegalArgumentException handleException(NoSuchFieldException e) { return new IllegalArgumentException(e); } /** - * Handle {@link NoSuchMethodException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link NoSuchMethodException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param methodName method name - * @param e exception - * @return wrapped exception + * @param e the original {@link NoSuchMethodException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String methodName, NoSuchMethodException e) { - LOGGER.error("Couldn't find method " + methodName, e); + private static IllegalArgumentException handleException(NoSuchMethodException e) { return new IllegalArgumentException(e); } /** - * Handle {@link IllegalAccessException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link IllegalAccessException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param memberName member name - * @param e exception - * @return wrapped exception + * @param e the original {@link IllegalAccessException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String memberName, IllegalAccessException e) { - LOGGER.error("Couldn't access member " + memberName, e); + private static IllegalArgumentException handleException(IllegalAccessException e) { return new IllegalArgumentException(e); } /** - * Handle {@link InvocationTargetException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link InvocationTargetException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param methodName method name - * @param e exception - * @return wrapped exception + * @param e the original {@link InvocationTargetException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String methodName, InvocationTargetException e) { - LOGGER.error("Couldn't invoke method " + methodName, e); + private static IllegalArgumentException handleException(InvocationTargetException e) { return new IllegalArgumentException(e); } /** - * Handle {@link ClassNotFoundException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link ClassNotFoundException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param className class name - * @param e exception - * @return wrapped exception + * @param e the original {@link ClassNotFoundException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String className, ClassNotFoundException e) { - LOGGER.error("Couldn't find class " + className, e); + private static IllegalArgumentException handleException(ClassNotFoundException e) { return new IllegalArgumentException(e); } /** - * Handle {@link InstantiationException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link InstantiationException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param className class name - * @param e exception - * @return wrapped exception + * @param e the original {@link InstantiationException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String className, InstantiationException e) { - LOGGER.error("Couldn't instantiate class " + className, e); + private static IllegalArgumentException handleException(InstantiationException e) { return new IllegalArgumentException(e); } } diff --git a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java index 556a3a2af..0dc11aae9 100644 --- a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java +++ b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/ImmutableType.java @@ -1,20 +1,34 @@ package com.vladmihalcea.hibernate.type; import com.vladmihalcea.hibernate.type.util.Configuration; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.jdbc.Size; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.Type; +import org.hibernate.type.descriptor.java.IncomparableComparator; import org.hibernate.usertype.UserType; import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Map; /** * Very convenient base class for implementing immutable object types using Hibernate {@link UserType}. + *

+ * The {@link ImmutableType} implements the {@link Type} interface too, so you can pass all + * types extending the {@link ImmutableType} to the {@link org.hibernate.query.NativeQuery#addScalar(String, Type)} + * method to fix the No Dialect mapping for JDBC type issues. * * @author Vlad Mihalcea */ -public abstract class ImmutableType implements UserType { +public abstract class ImmutableType implements UserType, Type { private final Configuration configuration; @@ -34,7 +48,7 @@ protected ImmutableType(Class clazz) { /** * Initialization constructor taking the {@link Class} and {@link Configuration} objects. * - * @param clazz the entity attribute {@link Class} type to be handled + * @param clazz the entity attribute {@link Class} type to be handled * @param configuration custom {@link Configuration} object. */ protected ImmutableType(Class clazz, Configuration configuration) { @@ -44,12 +58,40 @@ protected ImmutableType(Class clazz, Configuration configuration) { /** * Get the current {@link Configuration} object. + * * @return the current {@link Configuration} object. */ protected Configuration getConfiguration() { return configuration; } + /** + * Get the column value from the JDBC {@link ResultSet}. + * + * @param rs JDBC {@link ResultSet} + * @param names database column name + * @param session current Hibernate {@link org.hibernate.Session} + * @param owner current Hibernate {@link SessionFactoryImplementor} + * @return column value + * @throws SQLException in case of failure + */ + protected abstract T get(ResultSet rs, String[] names, + SharedSessionContractImplementor session, Object owner) throws SQLException; + + /** + * Set the column value on the provided JDBC {@link PreparedStatement}. + * + * @param st JDBC {@link PreparedStatement} + * @param value database column value + * @param index database column index + * @param session current Hibernate {@link org.hibernate.Session} + * @throws SQLException in case of failure + */ + protected abstract void set(PreparedStatement st, T value, int index, + SharedSessionContractImplementor session) throws SQLException; + + /* Methods inherited from the {@link UserType} interface */ + @Override public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { @@ -62,13 +104,6 @@ public void nullSafeSet(PreparedStatement st, Object value, int index, set(st, clazz.cast(value), index, session); } - protected abstract T get(ResultSet rs, String[] names, - SharedSessionContractImplementor session, Object owner) throws SQLException; - - protected abstract void set(PreparedStatement st, T value, int index, - SharedSessionContractImplementor session) throws SQLException; - - @Override public Class returnedClass() { return clazz; @@ -108,4 +143,180 @@ public Object assemble(Serializable cached, Object owner) { public Object replace(Object o, Object target, Object owner) { return o; } + + /* Methods inherited from the {@link Type} interface */ + + @Override + public boolean isAssociationType() { + return false; + } + + @Override + public boolean isCollectionType() { + return false; + } + + @Override + public boolean isEntityType() { + return false; + } + + @Override + public boolean isAnyType() { + return false; + } + + @Override + public boolean isComponentType() { + return false; + } + + @Override + public int getColumnSpan(Mapping mapping) throws MappingException { + return 1; + } + + @Override + public int[] sqlTypes(Mapping mapping) throws MappingException { + return sqlTypes(); + } + + @Override + public Size[] dictatedSizes(Mapping mapping) throws MappingException { + return new Size[]{new Size()}; + } + + @Override + public Size[] defaultSizes(Mapping mapping) throws MappingException { + return dictatedSizes(mapping); + } + + @Override + public Class getReturnedClass() { + return returnedClass(); + } + + @Override + public boolean isSame(Object x, Object y) throws HibernateException { + return equals(x, y); + } + + @Override + public boolean isEqual(Object x, Object y) throws HibernateException { + return equals(x, y); + } + + @Override + public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) throws HibernateException { + return equals(x, y); + } + + @Override + public int getHashCode(Object x) throws HibernateException { + return hashCode(x); + } + + @Override + public int getHashCode(Object x, SessionFactoryImplementor factory) throws HibernateException { + return hashCode(x); + } + + @Override + public int compare(Object x, Object y) { + return IncomparableComparator.INSTANCE.compare(x, y); + } + + @Override + public final boolean isDirty(Object old, Object current, SharedSessionContractImplementor session) { + return isDirty(old, current); + } + + @Override + public final boolean isDirty(Object old, Object current, boolean[] checkable, SharedSessionContractImplementor session) { + return checkable[0] && isDirty(old, current); + } + + protected final boolean isDirty(Object old, Object current) { + return !isSame(old, current); + } + + @Override + public boolean isModified(Object dbState, Object currentState, boolean[] checkable, SharedSessionContractImplementor session) throws HibernateException { + return isDirty(dbState, currentState); + } + + @Override + public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException { + return get(rs, new String[]{name}, session, owner); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session) throws HibernateException, SQLException { + set(st, returnedClass().cast(value), index, session); + } + + @Override + public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException { + return String.valueOf(value); + } + + @Override + public String getName() { + return getClass().getSimpleName(); + } + + @Override + public Object deepCopy(Object value, SessionFactoryImplementor factory) throws HibernateException { + return deepCopy(value); + } + + @Override + public Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException { + return disassemble(value); + } + + @Override + public Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) throws HibernateException { + return assemble(cached, session); + } + + @Override + public void beforeAssemble(Serializable cached, SharedSessionContractImplementor session) { + + } + + @Override + public Object hydrate(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException { + return nullSafeGet(rs, names, session, owner); + } + + @Override + public Object resolve(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException { + return value; + } + + @Override + public Object semiResolve(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException { + return value; + } + + @Override + public Type getSemiResolvedType(SessionFactoryImplementor factory) { + return this; + } + + @Override + public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) throws HibernateException { + return replace(original, target, owner); + } + + @Override + public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache, ForeignKeyDirection foreignKeyDirection) throws HibernateException { + return replace(original, target, owner); + } + + @Override + public boolean[] toColumnNullness(Object value, Mapping mapping) { + return value == null ? ArrayHelper.FALSE : ArrayHelper.TRUE; + } } \ No newline at end of file diff --git a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/basic/NullableCharacterType.java b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/basic/NullableCharacterType.java index 1ed82ee18..951a10ade 100644 --- a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/basic/NullableCharacterType.java +++ b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/basic/NullableCharacterType.java @@ -1,12 +1,21 @@ package com.vladmihalcea.hibernate.type.basic; import com.vladmihalcea.hibernate.type.ImmutableType; +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.jdbc.Size; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.Type; +import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; +import java.util.Map; /** * Maps an {@link Character} to a nullable CHAR column type. diff --git a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java index e8fceeee6..03ffe2eaf 100644 --- a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java +++ b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/util/ReflectionUtils.java @@ -1,8 +1,5 @@ package com.vladmihalcea.hibernate.type.util; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -15,58 +12,144 @@ */ public final class ReflectionUtils { - public static final String GETTER_PREFIX = "get"; - public static final String SETTER_PREFIX = "set"; - private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtils.class); + private static final String GETTER_PREFIX = "get"; + + private static final String SETTER_PREFIX = "set"; + /** + * Prevent any instantiation. + */ private ReflectionUtils() { - throw new UnsupportedOperationException("ReflectionUtils is not instantiable!"); + throw new UnsupportedOperationException("The " + getClass() + " is not instantiable!"); } /** - * Instantiate object + * Instantiate a new {@link Object} of the provided type. * - * @param className Class for object to instantiate - * @param field type - * @return field value + * @param className The fully-qualified Java class name of the {@link Object} to instantiate + * @param class type + * @return new Java {@link Object} of the provided type */ public static T newInstance(String className) { try { Class clazz = Class.forName(className); - return (T) clazz.newInstance(); + return newInstance(clazz); } catch (ClassNotFoundException e) { - throw handleException(className, e); + throw handleException(e); + } + } + + /** + * Instantiate a new {@link Object} of the provided type. + * + * @param clazz The Java {@link Class} of the {@link Object} to instantiate + * @param class type + * @return new Java {@link Object} of the provided type + */ + @SuppressWarnings("unchecked") + public static T newInstance(Class clazz) { + try { + return (T) clazz.newInstance(); } catch (InstantiationException e) { - throw handleException(className, e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(className, e); + throw handleException(e); } } /** - * Get target object field value + * Get the {@link Field} with the given name belonging to the provided Java {@link Class}. * - * @param target target object + * @param targetClass the provided Java {@link Class} the field belongs to + * @param fieldName the {@link Field} name + * @return the {@link Field} matching the given name + */ + public static Field getField(Class targetClass, String fieldName) { + Field field = null; + + try { + field = targetClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + try { + field = targetClass.getField(fieldName); + } catch (NoSuchFieldException ignore) { + } + + if (!targetClass.getSuperclass().equals(Object.class)) { + return getField(targetClass.getSuperclass(), fieldName); + } else { + throw handleException(e); + } + } finally { + if (field != null) { + field.setAccessible(true); + } + } + + return field; + } + + /** + * Get the {@link Field} with the given name belonging to the provided Java {@link Class} or {@code null} + * if no {@link Field} was found. + * + * @param targetClass the provided Java {@link Class} the field belongs to + * @param fieldName the {@link Field} name + * @return the {@link Field} matching the given name or {@code null} + */ + public static Field getFieldOrNull(Class targetClass, String fieldName) { + try { + Field field = targetClass.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException e) { + return null; + } + } + + /** + * Get the value of the field matching the given name and belonging to target {@link Object}. + * + * @param target target {@link Object} whose field we are retrieving the value from * @param fieldName field name * @param field type * @return field value */ public static T getFieldValue(Object target, String fieldName) { try { - Field field = target.getClass().getDeclaredField(fieldName); + Field field = getField(target.getClass(), fieldName); field.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) field.get(target); return returnValue; - } catch (NoSuchFieldException e) { - throw handleException(fieldName, e); } catch (IllegalAccessException e) { - throw handleException(fieldName, e); + throw handleException(e); } } /** - * Set target object field value + * Get the value of the field matching the given name and belonging to target {@link Object} or {@code null} + * if no {@link Field} was found.. + * + * @param target target {@link Object} whose field we are retrieving the value from + * @param fieldName field name + * @param field type + * @return field value matching the given name or {@code null} + */ + public static T getFieldValueOrNull(Object target, String fieldName) { + try { + Field field = getField(target.getClass(), fieldName); + field.setAccessible(true); + @SuppressWarnings("unchecked") + T returnValue = (T) field.get(target); + return returnValue; + } catch (IllegalAccessException e) { + return null; + } + } + + /** + * Set the value of the field matching the given name and belonging to target {@link Object}. * * @param target target object * @param fieldName field name @@ -78,24 +161,52 @@ public static void setFieldValue(Object target, String fieldName, Object value) field.setAccessible(true); field.set(target, value); } catch (NoSuchFieldException e) { - throw handleException(fieldName, e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(fieldName, e); + throw handleException(e); } } /** - * Get target method + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Object}. * - * @param target target object + * @param target target {@link Object} * @param methodName method name * @param parameterTypes method parameter types - * @return return value + * @return return {@link Method} matching the provided signature */ public static Method getMethod(Object target, String methodName, Class... parameterTypes) { return getMethod(target.getClass(), methodName, parameterTypes); } + /** + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Object} or {@code null} if no {@link Method} was found. + * + * @param target target {@link Object} + * @param methodName method name + * @param parameterTypes method parameter types + * @return return {@link Method} matching the provided signature or {@code null} + */ + public static Method getMethodOrNull(Object target, String methodName, Class... parameterTypes) { + try { + return getMethod(target.getClass(), methodName, parameterTypes); + } catch (RuntimeException e) { + return null; + } + } + + /** + * Get the {@link Method} with the given signature (name and parameter types) belonging to + * the provided Java {@link Class}. + * + * @param targetClass target {@link Class} + * @param methodName method name + * @param parameterTypes method parameter types + * @return the {@link Method} matching the provided signature + */ + @SuppressWarnings("unchecked") public static Method getMethod(Class targetClass, String methodName, Class... parameterTypes) { try { return targetClass.getDeclaredMethod(methodName, parameterTypes); @@ -105,22 +216,22 @@ public static Method getMethod(Class targetClass, String methodName, Class... pa } catch (NoSuchMethodException ignore) { } - if(!targetClass.getSuperclass().equals(Object.class)) { + if (!targetClass.getSuperclass().equals(Object.class)) { return getMethod(targetClass.getSuperclass(), methodName, parameterTypes); - } - else { - throw handleException(methodName, e); + } else { + throw handleException(e); } } } /** - * Check if target class has the given method + * Check if the provided Java {@link Class} contains a method matching + * the given signature (name and parameter types). * - * @param targetClass target class + * @param targetClass target {@link Class} * @param methodName method name * @param parameterTypes method parameter types - * @return method availability + * @return the provided Java {@link Class} contains a method with the given signature */ public static boolean hasMethod(Class targetClass, String methodName, Class... parameterTypes) { try { @@ -132,162 +243,198 @@ public static boolean hasMethod(Class targetClass, String methodName, Class.. } /** - * Get setter method + * Get the property setter {@link Method} with the given signature (name and parameter types) + * belonging to the provided Java {@link Object}. * - * @param target target object - * @param property property - * @param parameterType setter parameter type - * @return setter method + * @param target target {@link Object} + * @param propertyName property name + * @param parameterType setter property type + * @return the setter {@link Method} matching the provided signature */ - public static Method getSetter(Object target, String property, Class parameterType) { - String setterMethodName = SETTER_PREFIX + property.substring(0, 1).toUpperCase() + property.substring(1); + public static Method getSetter(Object target, String propertyName, Class parameterType) { + String setterMethodName = SETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); Method setter = getMethod(target, setterMethodName, parameterType); setter.setAccessible(true); return setter; } /** - * Get getter method + * Get the property getter {@link Method} with the given name belonging to + * the provided Java {@link Object}. * - * @param target target object - * @param property property - * @return setter method + * @param target target {@link Object} + * @param propertyName property name + * @return the getter {@link Method} matching the provided name */ - public static Method getGetter(Object target, String property) { - String getterMethodName = GETTER_PREFIX + property.substring(0, 1).toUpperCase() + property.substring(1); + public static Method getGetter(Object target, String propertyName) { + String getterMethodName = GETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); Method getter = getMethod(target, getterMethodName); getter.setAccessible(true); return getter; } /** - * Invoke target method + * Invoke the provided {@link Method} on the given Java {@link Object}. * - * @param target target object whose method we are invoking - * @param method method to invoke - * @param parameters method parameters - * @param return value object type - * @return return value + * @param target target {@link Object} whose method we are invoking + * @param method method to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the {@link Method} invocation */ - public static T invoke(Object target, Method method, Object... parameters) { + public static T invokeMethod(Object target, Method method, Object... parameters) { try { method.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) method.invoke(target, parameters); return returnValue; } catch (InvocationTargetException e) { - throw handleException(method.getName(), e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(method.getName(), e); + throw handleException(e); } } /** - * Invoke getter method with the given parameter + * Invoke the method with the provided signature (name and parameter types) + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param return value object type - * @return return value + * @param target target {@link Object} whose method we are invoking + * @param methodName method name to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the method invocation */ - public static T invokeGetter(Object target, String property) { - Method setter = getGetter(target, property); + public static T invokeMethod(Object target, String methodName, Object... parameters) { + try { + Class[] parameterClasses = new Class[parameters.length]; + + for (int i = 0; i < parameters.length; i++) { + parameterClasses[i] = parameters[i].getClass(); + } + + Method method = getMethod(target, methodName, parameterClasses); + method.setAccessible(true); + @SuppressWarnings("unchecked") + T returnValue = (T) method.invoke(target, parameters); + return returnValue; + } catch (InvocationTargetException e) { + throw handleException(e); + } catch (IllegalAccessException e) { + throw handleException(e); + } + } + + /** + * Invoke the property getter with the provided name on the given Java {@link Object}. + * + * @param target target {@link Object} whose property getter we are invoking + * @param propertyName property name whose getter we are invoking + * @param return value object type + * @return the value return by the getter invocation + */ + public static T invokeGetter(Object target, String propertyName) { + Method setter = getGetter(target, propertyName); try { return (T) setter.invoke(target); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the property setter with the provided signature (name and parameter types) + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, Object parameter) { - Method setter = getSetter(target, property, parameter.getClass()); + public static void invokeSetter(Object target, String propertyName, Object parameter) { + Method setter = getSetter(target, propertyName, parameter.getClass()); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the {@link boolean} property setter with the provided name + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter {@link boolean} parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, boolean parameter) { - Method setter = getSetter(target, property, boolean.class); + public static void invokeSetter(Object target, String propertyName, boolean parameter) { + Method setter = getSetter(target, propertyName, boolean.class); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Invoke the {@link int} property setter with the provided name + * on the given Java {@link Object}. * - * @param target target object - * @param property property - * @param parameter setter parameter + * @param target target {@link Object} whose property setter we are invoking + * @param propertyName property name whose setter we are invoking + * @param parameter {@link int} parameter passed to the setter call */ - public static void invokeSetter(Object target, String property, int parameter) { - Method setter = getSetter(target, property, int.class); + public static void invokeSetter(Object target, String propertyName, int parameter) { + Method setter = getSetter(target, propertyName, int.class); try { setter.invoke(target, parameter); } catch (IllegalAccessException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } catch (InvocationTargetException e) { - throw handleException(setter.getName(), e); + throw handleException(e); } } /** - * Invoke static Class method + * Invoke the {@code static} {@link Method} with the provided parameters. * - * @param method method to invoke - * @param parameters method parameters - * @param return value object type - * @return return value + * @param method target {@code static} {@link Method} to invoke + * @param parameters parameters passed to the method call + * @param return value object type + * @return the value return by the method invocation */ - public static T invokeStatic(Method method, Object... parameters) { + public static T invokeStaticMethod(Method method, Object... parameters) { try { method.setAccessible(true); @SuppressWarnings("unchecked") T returnValue = (T) method.invoke(null, parameters); return returnValue; } catch (InvocationTargetException e) { - throw handleException(method.getName(), e); + throw handleException(e); } catch (IllegalAccessException e) { - throw handleException(method.getName(), e); + throw handleException(e); } } /** - * Invoke setter method with the given parameter + * Get the Java {@link Class} with the given fully-qualified name. * - * @param className class name to be retrieved - * @param return value object type - * @return Java {@link Class} object instance + * @param className the Java {@link Class} name to be retrieved + * @param {@link Class} type + * @return the Java {@link Class} object */ + @SuppressWarnings("unchecked") public static Class getClass(String className) { try { return (Class) Class.forName(className); } catch (ClassNotFoundException e) { - throw handleException(className, e); + throw handleException(e); } } @@ -309,74 +456,113 @@ public static Class getClassOrNull(String className) { } /** - * Handle {@link NoSuchFieldException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Get the Java Wrapper {@link Class} associated to the given primitive type. * - * @param fieldName field name - * @param e exception - * @return wrapped exception + * @param clazz primitive class + * @return the Java Wrapper {@link Class} + */ + public static Class getWrapperClass(Class clazz) { + if (!clazz.isPrimitive()) + return clazz; + + if (clazz == Integer.TYPE) + return Integer.class; + if (clazz == Long.TYPE) + return Long.class; + if (clazz == Boolean.TYPE) + return Boolean.class; + if (clazz == Byte.TYPE) + return Byte.class; + if (clazz == Character.TYPE) + return Character.class; + if (clazz == Float.TYPE) + return Float.class; + if (clazz == Double.TYPE) + return Double.class; + if (clazz == Short.TYPE) + return Short.class; + if (clazz == Void.TYPE) + return Void.class; + + return clazz; + } + + /** + * Get the first super class matching the provided package name. + * + * @param clazz Java class + * @param packageName package name + * @param class generic type + * @return the first super class matching the provided package name or {@code null}. + */ + public static Class getFirstSuperClassFromPackage(Class clazz, String packageName) { + if (clazz.getPackage().getName().equals(packageName)) { + return clazz; + } else { + Class superClass = clazz.getSuperclass(); + return (superClass == null || superClass.equals(Object.class)) ? + null : + (Class) getFirstSuperClassFromPackage(superClass, packageName); + } + } + + /** + * Handle the {@link NoSuchFieldException} by rethrowing it as an {@link IllegalArgumentException}. + * + * @param e the original {@link NoSuchFieldException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String fieldName, NoSuchFieldException e) { - LOGGER.error("Couldn't find field " + fieldName, e); + private static IllegalArgumentException handleException(NoSuchFieldException e) { return new IllegalArgumentException(e); } /** - * Handle {@link NoSuchMethodException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link NoSuchMethodException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param methodName method name - * @param e exception - * @return wrapped exception + * @param e the original {@link NoSuchMethodException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String methodName, NoSuchMethodException e) { - LOGGER.error("Couldn't find method " + methodName, e); + private static IllegalArgumentException handleException(NoSuchMethodException e) { return new IllegalArgumentException(e); } /** - * Handle {@link IllegalAccessException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link IllegalAccessException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param memberName member name - * @param e exception - * @return wrapped exception + * @param e the original {@link IllegalAccessException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String memberName, IllegalAccessException e) { - LOGGER.error("Couldn't access member " + memberName, e); + private static IllegalArgumentException handleException(IllegalAccessException e) { return new IllegalArgumentException(e); } /** - * Handle {@link InvocationTargetException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link InvocationTargetException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param methodName method name - * @param e exception - * @return wrapped exception + * @param e the original {@link InvocationTargetException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String methodName, InvocationTargetException e) { - LOGGER.error("Couldn't invoke method " + methodName, e); + private static IllegalArgumentException handleException(InvocationTargetException e) { return new IllegalArgumentException(e); } /** - * Handle {@link ClassNotFoundException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link ClassNotFoundException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param className class name - * @param e exception - * @return wrapped exception + * @param e the original {@link ClassNotFoundException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String className, ClassNotFoundException e) { - LOGGER.error("Couldn't find class " + className, e); + private static IllegalArgumentException handleException(ClassNotFoundException e) { return new IllegalArgumentException(e); } /** - * Handle {@link InstantiationException} by logging it and rethrown it as a {@link IllegalArgumentException} + * Handle the {@link InstantiationException} by rethrowing it as an {@link IllegalArgumentException}. * - * @param className class name - * @param e exception - * @return wrapped exception + * @param e the original {@link InstantiationException} + * @return the {@link IllegalArgumentException} wrapping exception */ - private static IllegalArgumentException handleException(String className, InstantiationException e) { - LOGGER.error("Couldn't instantiate class " + className, e); + private static IllegalArgumentException handleException(InstantiationException e) { return new IllegalArgumentException(e); } }