blob: 2275ec73883928bc7c7609c4e0a62264eb9a46cc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.ocm.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.beanutils.ConstructorUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.jackrabbit.ocm.exception.JcrMappingException;
import net.sf.cglib.proxy.Enhancer;
/**
* Utility class for handling reflection using BeanUtils.
*
* @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
*/
abstract public class ReflectionUtils {
// default the class loader to the load of this class
private static ClassLoader classLoader = ReflectionUtils.class.getClassLoader();
// key = interface class, value = default implementation for the interface
// TODO : inject this map when the object content manager is initialized
private static HashMap<Class, Class> defaultImplementation;
static {
defaultImplementation = new HashMap<Class, Class>();
defaultImplementation.put(Collection.class, ArrayList.class);
defaultImplementation.put(List.class, ArrayList.class);
defaultImplementation.put(Map.class, HashMap.class);
defaultImplementation.put(SortedMap.class, TreeMap.class);
defaultImplementation.put(Set.class, HashSet.class);
}
/**
* Sets the class loader to use in the {@link #forName(String)} method to
* load classes.
* <p>
* Care must be taken when using this method as when setting an improperly
* set up classloader, the mapper will not work again throwing tons of
* exceptions.
*
* @param newClassLoader The new class loader to use. This may be
* <code>null</code> in which case the system class loader will be used.
*/
public static void setClassLoader(ClassLoader newClassLoader) {
classLoader = newClassLoader;
}
/**
* Returns the class loader which is used by the {@link #forName(String)}
* method to load classes.
*
* @return The class loader used by {@link #forName(String)} or
* <code>null</code> if the system class loader is used.
*/
public static ClassLoader getClassLoader() {
return classLoader;
}
public static Object getNestedProperty(Object object, String fieldName) {
if (null == object) {
return null;
}
try {
return PropertyUtils.getNestedProperty(object, fieldName);
}
catch(IllegalAccessException e) {
throw new JcrMappingException("Cannot access property "
+ fieldName,
e);
}
catch(InvocationTargetException e) {
throw new JcrMappingException("Cannot access property "
+ fieldName,
e);
}
catch(NoSuchMethodException e) {
throw new JcrMappingException("Cannot access property "
+ fieldName,
e);
}
}
public static Class getPropertyType(Object object, String fieldName) {
try {
return PropertyUtils.getPropertyType(object, fieldName);
}
catch(Exception ex) {
throw new JcrMappingException("Cannot access property "
+ fieldName,
ex);
}
}
public static Object newInstance(Class clazz) {
try {
return clazz.newInstance();
}
catch(Exception ex) {
throw new JcrMappingException("Cannot create instance for class "
+ clazz,
ex);
}
}
/**
* @param className
* @param objects
* @return
*/
public static Object invokeConstructor(String className, Object[] params) {
try {
Class converterClass= forName(className);
return ConstructorUtils.invokeConstructor(converterClass, params);
}
catch(Exception ex) {
throw new JcrMappingException("Cannot create instance for class " + className, ex);
}
}
/**
* @param object
* @param fieldName
* @param path
*/
public static void setNestedProperty(Object object, String fieldName, Object value) {
try {
PropertyUtils.setNestedProperty(object, fieldName, value);
}
catch(Exception ex) {
String className = (object == null) ? "<null>" : object.getClass().getName();
throw new JcrMappingException("Cannot set the field " + fieldName + " in the class : " + className,
ex);
}
}
/**
* @param string
* @return
*/
public static Object newInstance(String clazz) {
try {
return forName(clazz).newInstance();
}
catch(Exception ex) {
throw new JcrMappingException("Cannot create instance for class " + clazz, ex);
}
}
/**
* @param elementClassName
* @return
*/
public static Class forName(String clazz) {
try {
return Class.forName(clazz, true, getClassLoader());
}
catch(Exception ex) {
throw new JcrMappingException("Cannot load class " + clazz, ex);
}
}
public static boolean isProxy(Class beanClass)
{
return Enhancer.isEnhanced(beanClass);
}
public static Class getBeanClass(Object bean)
{
Class beanClass = bean.getClass();
if (isProxy(beanClass))
{
//CGLIB specific
return beanClass.getSuperclass();
}
return beanClass;
}
/**
* Check if an class is implementing an specific interface.
*
* @param clazz
* @param interfaceClass
* @return true if the class is implementing the interface otherwise false
*/
public static boolean implementsInterface(Class clazz, Class interfaceClass) {
// Try to find the interface class in the interfaces list
if (clazz.getInterfaces() != null) {
for (Class foundInterface : clazz.getInterfaces()) {
if (foundInterface == interfaceClass
|| implementsInterface(foundInterface, interfaceClass)) {
return true;
}
}
}
// Try to find from the ancestors
if (clazz.getSuperclass() != null) {
return implementsInterface(clazz.getSuperclass(), interfaceClass);
}
return false;
}
/**
* Get the default implementation for an interface
* @param clazz The interface clazz
* @return The class matching to the interface default interface
*/
public static Class getDefaultImplementation(Class clazz)
{
if (! clazz.isInterface())
throw new JcrMappingException(clazz + " is not an interface");
return defaultImplementation.get(clazz);
}
public static boolean isAbstractClass(Class clazz)
{
return Modifier.isAbstract(clazz.getModifiers());
}
public static Class getAncestorClass(Class clazz)
{
Class ancestorClass = clazz.getSuperclass();
if (ancestorClass == Object.class)
return null;
else
return ancestorClass;
}
public static Class[] getInterfaces(Class clazz)
{
return clazz.getInterfaces();
}
}