/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed 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 *******************************************************************************/ package org.ebayopensource.turmeric.runtime.common.impl.utils; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import javax.xml.bind.annotation.XmlElement; import org.ebayopensource.turmeric.runtime.common.exceptions.ErrorDataFactory; import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceException; import org.ebayopensource.turmeric.runtime.common.registration.ClassLoaderRegistry; import org.ebayopensource.turmeric.runtime.errorlibrary.ErrorConstants; /** * @author ichernyshev */ public final class ReflectionUtils { private static final Logger LOG = Logger.getLogger(ReflectionUtils.class.getName()); private ReflectionUtils() { // no instances } public static <T> Class<T> loadClass(String className, Class<T> targetType, ClassLoader cl) throws ServiceException { return loadClass(className, targetType, false, cl); } static Pattern PROJECT_PATTERNS[] = { Pattern.compile("com\\.ebay\\.marketplace\\.services(\\.\\w+\\.)[\\.\\w]+"), Pattern.compile("com\\.ebay\\.marketplace(\\.\\w+\\.v1\\.)services\\.[\\.\\w]+") }; public static <T> Class<T> loadClass(String className, Class<T> targetType, boolean ignoreMissingClass, ClassLoader cl) throws ServiceException { String targetTypeName; if (targetType != null) { targetTypeName = targetType.getName(); } else { targetTypeName = "(unspecified assignment type)"; } StringBuffer infoLoad = new StringBuffer("CLASS: " + className); Class clazz = null; Throwable exception = null; Throwable exception2 = null; try { ClassLoader classLoader = ClassLoaderRegistry.instanceOf() .getClassLoaderForClass(ClassLoaderRegistry.getPackageName(className)); if (classLoader != null) { infoLoad.append(" - exact name"); clazz = Class.forName(className, true, classLoader); if (clazz != null) { infoLoad.append(". Found!\n"); } } else { try { clazz = Class.forName(className, true, ReflectionUtils.class.getClassLoader()); infoLoad.append(" - in this bundle. Found!\n"); } catch (NoClassDefFoundError err) { exception = err; } catch (ClassNotFoundException e) { exception = e; } if (clazz == null) { clazz = Class.forName(className, true, cl); infoLoad.append(" - use default (\"thread\") bundle). Found!\n"); } } ClassLoaderRegistry.instanceOf().writeToOut(infoLoad.toString()); } catch (NoClassDefFoundError err) { ClassLoaderRegistry.instanceOf().writeToOut( infoLoad.append(". Error: " + err.getMessage() + ". No found...\n").toString()); throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_FACTORY_INST_NOT_FOUND, ErrorConstants.ERRORDOMAIN, new Object[] {targetTypeName, className}), err); } catch (ClassNotFoundException e) { ClassLoaderRegistry.instanceOf().writeToOut( infoLoad.append(". Error: "+e.getMessage()+". No found...\n").toString()); if (ignoreMissingClass) { return null; } throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_FACTORY_INST_NOT_FOUND, ErrorConstants.ERRORDOMAIN, new Object[] {targetTypeName, className}), e); } if (targetType != null && !targetType.isAssignableFrom(clazz)) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_FACTORY_INST_CANNOT_CAST, ErrorConstants.ERRORDOMAIN, new Object[] {targetTypeName, className})); } @SuppressWarnings("unchecked") Class<T> result = clazz; return result; } public static <T> T createInstance(String className, Class<T> targetType, ClassLoader cl) throws ServiceException { return createInstance(className, targetType, cl, null, null); } public static <T> T createInstance(String className, Class<T> targetType, ClassLoader cl, Class[] paramTypes, Object[] params) throws ServiceException { Class<T> clazz = loadClass(className, targetType, cl); return createInstance(clazz, paramTypes, params); } public static <T> T createInstance(Class<T> clazz) throws ServiceException { return createInstance(clazz, null, null); } public static <T> T createInstance(Class<T> clazz, Class[] paramTypes, Object[] params) throws ServiceException { Object result; try { if (paramTypes != null) { Constructor con = clazz.getConstructor(paramTypes); result = con.newInstance(params); } else { result = clazz.newInstance(); } } catch (IllegalAccessException e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_FACTORY_INST_ILLEGAL_ACCESS, ErrorConstants.ERRORDOMAIN, new Object[] {clazz.getName()}), e); } catch (Exception e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_FACTORY_INST_EXCEPTION, ErrorConstants.ERRORDOMAIN, new Object[] {clazz.getName()}), e); } // type cast cannot be done, but we've checked isAssignableFrom @SuppressWarnings("unchecked") T result2 = (T)result; return result2; } public static Method findMatchingJavaMethod(Class<?> clz, String xmlElement) { //1. iterate thru all the methods of the java bean and find a matching // method w/ the same xmlElement name Method[] methods = clz.getDeclaredMethods(); String methodName = toGetMethodName(xmlElement); // look from property fields Field[] fields = clz.getDeclaredFields(); for (int i = 0; i<fields.length; i++) { XmlElement element = fields[i].getAnnotation(XmlElement.class); if (element != null) { // if there is a property-xml mapping, use that to check to find a match if (xmlElement.equalsIgnoreCase(element.name())) { // Found a match // System.out.println("matching name found property (map):" + xmlElement); // use this field name to find the corresponding method name return getMethodFromField(clz, fields[i]); } } } // if no matching found, search in methods for (int i = 0; i<methods.length; i++) { XmlElement element = methods[i].getAnnotation(XmlElement.class); if (element != null) { // if there is a property-xml mapping, use that to check to find a match // Also, it has to be a getter method.. so the prefix should be get if (xmlElement.equalsIgnoreCase(element.name()) && methods[i].getName().startsWith("get")) { // Found a match return methods[i]; } } else { // if there isn't, use the method name if (methodName.equalsIgnoreCase(methods[i].getName())) { // Found a match return methods[i]; } } } return null; } private static String toGetMethodName(String xmlElement) { String adjustedFieldName = xmlElement.toUpperCase().charAt(0) + xmlElement.substring(1); return "get" + adjustedFieldName; } public static Method getMethodFromField(Class<?> clz, Field f) { //String adjustedFieldName = f.getName().toUpperCase().charAt(0) + f.getName().substring(1); String methodName = toGetMethodName(f.getName()); Method m = null; try { m = clz.getMethod(methodName, (Class[]) null); } catch (SecurityException e) { LOG.log(Level.FINE, methodName, e); } catch (NoSuchMethodException e) { LOG.log(Level.FINE, methodName, e); } return m; } }