All Downloads are FREE. Search and download functionalities are using the official Maven repository.

leap.lang.reflect.Reflection Maven / Gradle / Ivy

/*
 * Copyright 2013 the original author or authors.
 *
 * 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
 *
 * 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 leap.lang.reflect;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

import leap.lang.Args;
import leap.lang.Arrays2;
import leap.lang.Classes;
import leap.lang.Factory;
import leap.lang.Strings;
import leap.lang.exception.ObjectNotFoundException;
import leap.lang.exception.TooManyElementsException;

public class Reflection {
	
	private static ReflectMetadata metadata = Factory.newInstance(ReflectMetadata.class,ASMReflectMetadata.class);
	private static ReflectFactory  factory  = Factory.newInstance(ReflectFactory.class,ASMReflectFactory.class);
	
	protected static ReflectMetadata metadata(){
		return metadata;
	}
	
	protected static ReflectFactory factory(){
		return factory;
	}
	
	/**
	 * create a new instance of the given class.
	 */
	public static  T newInstance(Class clazz){
		return ReflectClass.of(clazz).newInstance();
	}
	
	/**
	 * create a new instance by the given constructor.
	 */
	public static  T newInstance(Constructor constructor){
		return newInstance(constructor, Arrays2.EMPTY_BOOLEAN_ARRAY);
	}
	
	/**
	 * create a new instance by the given constructor.
	 */
	public static  T newInstance(Constructor constructor,Object... args){
		try {
	        return constructor.newInstance(args);
        } catch (Exception e) {
        	handleException(e);
        	return null;
        }
	}
	
	public static String[] getParameterNames(Method method) {
		return metadata.getParameterNames(method);
	}
	
	public static String[] getParameterNames(Constructor constructor) {
		return metadata.getParameterNames(constructor);
		//return Arrays.stream(constructor.getParameters()).map((p) -> p.getName()).toArray((size) -> new String[size]);
	}
	
	/**
	 * returns all the declared fields of the given class and all the superclasses up to Object.
	 */
    public static List getFields(Class clazz){
        List fields = new ArrayList();
        
        for (Class search = clazz; search != null; search = search.getSuperclass()) {
            for(Field field : search.getDeclaredFields()){
            	fields.add(field) ;
            }
        }
        
        return fields;
    }
    
	public static String fullQualifyName(Method m){
		StringBuilder sb = new StringBuilder(50);
		sb.append(m.getDeclaringClass().getName()).append(".").append(m.getName());
		sb.append("(");
		
		Class[] paramTypes = m.getParameterTypes();
		for(int i=0;i 0){
				sb.append(",");
			}
			sb.append(paramTypes[i].getSimpleName());
		}
		sb.append(")");
		return sb.toString();
	}
	
	/**
	 * 
	 */
	public static Method getMethod(Class cls,String name) throws ObjectNotFoundException, TooManyElementsException {
		List methods = getMethods(cls,name);
		if(methods.isEmpty()){
			throw new ObjectNotFoundException("No such method '" + name + "' in class '" + cls.getName() + "'");
		}
		if(methods.size() > 1){
			throw new TooManyElementsException("There are " + methods.size() + " methods named '" + name + "' in class '" + cls.getName() + "'");
		}
		return methods.get(0);
	}
	
	/**
	 * @throws ObjectNotFoundException if class or method not found
	 */
	public static Method getMethodByFqName(String fqName) throws ObjectNotFoundException {
		int leftParenIndex = fqName.lastIndexOf('(');
		int separateIndex  = leftParenIndex != -1 ? fqName.lastIndexOf('.', leftParenIndex) : fqName.lastIndexOf('.');
		
		if(separateIndex > 0){
			String   className  = fqName.substring(0,separateIndex);
			String   methodName = fqName.substring(separateIndex+1,separateIndex != -1 ? separateIndex : fqName.length());
			String[] paramTypes = null;
			
			if(separateIndex != -1){
				paramTypes = Strings.split(fqName.substring(separateIndex+1,fqName.length()+1),",");
			}
			
			Class clazz = Classes.forName(className);
			
			List methods = getMethods(clazz,methodName);
			
			for(Method method : methods){
				if(null == paramTypes || paramTypes.length == 0){
					if(method.getParameterTypes().length == 0){
						return method;	
					}
				}else{
					if(method.getParameterTypes().length == paramTypes.length){
						
						boolean matched = true;
						
						for(int i=0;i typeClass = method.getParameterTypes()[i];
							String   typeName  = paramTypes[i];
							
							if(!(typeClass.getSimpleName().equals(typeName) || typeClass.getName().equals(typeName))){
								matched = false;
								break;
							}
						}
						
						if(matched){
							return method;
						}
					}
				}
			}
		}
		
		throw new ObjectNotFoundException("method '" + fqName + "' not found");
	}
	
	/**
	 * @throws ObjectNotFoundException if method not found
	 */
	public static Method getMethodByNameOrDesc(Class cls, String methodNameOrDesc) throws ObjectNotFoundException {
		int leftParenIndex = methodNameOrDesc.lastIndexOf('(');
		if(leftParenIndex < 0){
			return getMethod(cls, methodNameOrDesc);
		}
		
		int rightParenIndex = methodNameOrDesc.lastIndexOf(')');
		if(rightParenIndex != methodNameOrDesc.length() - 1){
			throw new IllegalArgumentException("Invalid method desc '" + methodNameOrDesc + "'");
		}
		
		String methodName = methodNameOrDesc.substring(0,leftParenIndex);
		String paramsDesc = methodNameOrDesc.substring(leftParenIndex+1,methodNameOrDesc.length() - 1);
		
		String[] paramTypes = Strings.split(paramsDesc,",");
		
		List methods = getMethods(cls,methodName);
		
		for(Method method : methods){
			if(null == paramTypes || paramTypes.length == 0){
				if(method.getParameterTypes().length == 0){
					return method;	
				}
			}else{
				if(method.getParameterTypes().length == paramTypes.length){
					
					boolean matched = true;
					
					for(int i=0;i typeClass = method.getParameterTypes()[i];
						String   typeName  = paramTypes[i];
						
						if(!(typeClass.getSimpleName().equals(typeName) || typeClass.getName().equals(typeName))){
							matched = false;
							break;
						}
					}
					
					if(matched){
						return method;
					}
				}
			}
		}
		
		throw new ObjectNotFoundException("Method '" + methodNameOrDesc + "' not found in class '" + cls.getName() + "'");
	}
    
	/**
	 * returns all the declared methods of the given class and all the superclasses up to Object.
	 * 
	 * 

* * synthetic method will be ignored. */ public static List getMethods(Class clazz){ List methods = new ArrayList(); for(Method method : clazz.getMethods()) { methods.add(method); } for (Class search = clazz; search != null; search = search.getSuperclass()) { for(Method method : search.getDeclaredMethods()){ if(Modifier.isPublic(method.getModifiers())) { continue; } if(methods.contains(method)) { continue; } //ignore synthetic method if(!method.isSynthetic()){ methods.add(method) ; } } } return methods; } /** * returns all the declared methods match the given name of the given class and all the superclasses up to Object. */ public static List getMethods(Class clazz,String name){ List methods = new ArrayList(); for(Method method : clazz.getMethods()) { if(method.getName().equals(name)) { methods.add(method); } } for (Class search = clazz; search != null; search = search.getSuperclass()) { for(Method method : search.getDeclaredMethods()){ if(Modifier.isPublic(method.getModifiers())) { continue; } if(method.getName().equals(name) && !methods.contains(method)){ methods.add(method) ; } } } return methods; } /** * Handle the given reflection exception. Should only be called if no checked exception is expected to be thrown by * the target method. * *

* Throws the underlying RuntimeException or Error in case of an InvocationTargetException with such a root cause. * Throws an IllegalStateException with an appropriate message else. * * @param ex the reflection exception to handle */ public static void handleException(Exception ex) { if (ex instanceof InvocationTargetException) { Throwable cause = ((InvocationTargetException) ex).getTargetException(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } if (cause instanceof Error) { throw (Error) cause; } throw new ReflectException(ex); } if (ex instanceof NoSuchMethodException) { throw new IllegalStateException("Method not found: " + ex.getMessage()); } if (ex instanceof NoSuchFieldException) { throw new IllegalStateException("Field not found: " + ex.getMessage()); } if (ex instanceof IllegalAccessException) { throw new IllegalStateException("Illegal access method or field: " + ex.getMessage()); } if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } throw new ReflectException(ex); } /** * Attempt to find a {@link Method} on the supplied class with the supplied name and no parameters. * * Searches all superclasses up to Object. * *

* Returns null if no {@link Method} can be found. * * @param clazz the class to introspect * @param name the name of the method * @return the Method object, or null if none found */ public static Method findMethod(Class clazz, String name) { return findMethod(clazz, name, Arrays2.EMPTY_CLASS_ARRAY); } /** * */ public static Method findFirstDeclaredMethod(Class cls,String name){ for(Method m : cls.getDeclaredMethods()){ if(m.getName().equals(name)){ return m; } } return null; } /** * Attempt to find a {@link Method} on the supplied class with the supplied name and parameter types. * * Searches all superclasses up to Object. * *

* Returns null if no {@link Method} can be found. * * @param clazz the class to introspect * @param name the name of the method * @param paramTypes the parameter types of the method (may be null to indicate any signature) * * @return the Method object, or null if none found */ public static Method findMethod(Class clazz, String name, Class... paramTypes) { Args.notNull(clazz, "clazz"); Args.notNull(name, "method name"); Class searchType = clazz; while (searchType != null) { Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods()); for (Method method : methods) { if (name.equals(method.getName()) && (paramTypes == null || Arrays2.equals(paramTypes, method.getParameterTypes()))) { return method; } } searchType = searchType.getSuperclass(); } return null; } /** * Attempt to find a {@link Method} on the supplied class with the supplied name and parameter types. * * Searches all superclasses up to Object. * *

* Returns null if no {@link Method} can be found. * * @param clazz the class to introspect * @param name the name of the method * @param paramTypeNames the parameter type names of the method (may be null to indicate any signature) * * @return the Method object, or null if none found */ public static Method findMethod(Class clazz, String name, String... paramTypeNames) { Args.notNull(clazz, "clazz"); Args.notNull(name, "method name"); Class searchType = clazz; while (searchType != null) { Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods()); for (Method method : methods) { if (name.equals(method.getName())){ if(null == paramTypeNames || paramTypeNames.length == 0){ if(method.getParameterTypes().length == 0){ return method; } }else{ if(method.getParameterTypes().length == paramTypeNames.length){ boolean matched = true; for(int i=0;i typeClass = method.getParameterTypes()[i]; String typeName = paramTypeNames[i]; if(!(typeClass.getSimpleName().equals(typeName) || typeClass.getName().equals(typeName))){ matched = false; break; } } if(matched){ return method; } } } } } searchType = searchType.getSuperclass(); } return null; } /** * Attempt to find a {@link Field field} on the supplied {@link Class} with the supplied name. * * Searches all superclasses up to {@link Object}. * * @param clazz the class to introspect * @param name the name of the field * @return the corresponding Field object, or null if not found */ public static Field findField(Class clazz, String name) { return findField(clazz, name, null); } /** * Attempt to find a {@link Field field} on the supplied {@link Class} with the supplied name and/or * {@link Class type}. * * Searches all superclasses up to {@link Object}. * * @param clazz the class to introspect * @param name the name of the field (may be null if type is specified) * @param type the type of the field (may be null if name is specified) * @return the corresponding Field object, or null if not found */ public static Field findField(Class clazz, String name, Class type) { Args.notNull(clazz, "clazz"); Args.assertTrue(name != null || type != null, "Either name or type of the field must be specified"); Class searchType = clazz; while (!Object.class.equals(searchType) && searchType != null) { Field[] fields = searchType.getDeclaredFields(); for (Field field : fields) { if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) { return field; } } searchType = searchType.getSuperclass(); } return null; } /** * Invoke the specified {@link Method} against the supplied target object with no Args. The target object can * be null when invoking a static {@link Method}. * * @param method the method to invoke * @param target the target object to invoke the method on * @return the invocation result, if any * @see #invokeMethod(java.lang.reflect.Method, Object, Object[]) */ public static Object invokeMethod(Method method, Object target) { return invokeMethod(method, target, Arrays2.EMPTY_OBJECT_ARRAY); } /** * Invoke the specified {@link Method} against the supplied target object with the supplied Args. The target * object can be null when invoking a static {@link Method}. * * @param method the method to invoke * @param target the target object to invoke the method on * @param args the invocation Arguments (may be null) * @return the invocation result, if any */ public static Object invokeMethod(Method method, Object target, Object... args) { try { if(!method.isAccessible()){ method.setAccessible(true); } return method.invoke(target, args); } catch (Exception ex) { handleException(ex); throw new ReflectException(ex.getMessage(), ex); } } /** * Get the field represented by the supplied {@link Field field object} on the * specified {@link Object target object}. In accordance with {@link Field#get(Object)} * semantics, the returned value is automatically wrapped if the underlying field * has a primitive type. * * @param field the field to get * @param target the target object from which to get the field * @return the field's current value */ public static Object getFieldValue(Object target,Field field) { try { return field.get(target); } catch (IllegalAccessException ex) { handleException(ex); throw new ReflectException("Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage()); } } protected Reflection(){ } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy