Java tutorial
/* * (c) 2005 David B. Bracewell * * 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 com.davidbracewell.reflection; import com.davidbracewell.conversion.Cast; import com.davidbracewell.conversion.Convert; import com.davidbracewell.conversion.Val; import com.davidbracewell.string.StringUtils; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collections; import java.util.Set; /** * <code>Reflect</code> is a class that allows fluent use of reflection * * @author David B. Bracewell */ public class Reflect { private final Object object; private final Class<?> clazz; private final boolean accessAll; private Reflect(Object object, Class<?> clazz) { this(object, clazz, false); } private Reflect(Object object, Class<?> clazz, boolean accessAll) { this.object = object; this.clazz = clazz; this.accessAll = accessAll; } /** * Creates an instance of Reflect associated with an object * * @param object The object for reflection * @return The Reflect object */ public static Reflect onObject(Object object) { if (object == null) { return new Reflect(null, null); } return new Reflect(object, object.getClass()); } /** * Creates an instance of Reflect associated with a class * * @param clazz The class for reflection * @return The Reflect object */ public static Reflect onClass(Class<?> clazz) { return new Reflect(null, Preconditions.checkNotNull(clazz)); } /** * Creates an instance of Reflect associated with a class * * @param clazz The class for reflection as string * @return The Reflect object * @throws ClassNotFoundException the class not found exception */ public static Reflect onClass(String clazz) throws ClassNotFoundException { return new Reflect(null, ReflectionUtils.getClassForName(clazz)); } /** * Creates an instance Reflect for an object that gets constructed using the supplied constructor and arguments. * * @param constructor The constructor to call * @param allowPrivilegedAccess Allows access to all methods on the object or class * @param args The arguments to pass to the constructor * @return A Reflect wrapper around the constructed object * @throws ReflectionException Something went wrong constructing the object */ public static Reflect on(Constructor constructor, boolean allowPrivilegedAccess, Object... args) throws ReflectionException { Preconditions.checkNotNull(constructor); boolean accessible = constructor.isAccessible(); try { if (!accessible && allowPrivilegedAccess) { constructor.setAccessible(true); } if (args != null) { Class<?>[] parameterTypes = constructor.getParameterTypes(); for (int i = 0; i < args.length; i++) { args[i] = convertValueType(args[i], parameterTypes[i]); } } Object object = constructor.newInstance(args); return new Reflect(object, object.getClass(), allowPrivilegedAccess); } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new ReflectionException(e); } finally { if (!accessible && allowPrivilegedAccess) { constructor.setAccessible(false); } } } /** * Determines if a field with the given name is associated with the class * * @param name The field name * @return True if there is a field with the given name */ public boolean containsField(String name) { try { return clazz.getField(name) != null; } catch (NoSuchFieldException e) { return false; } } /** * Creates an instance Reflect for an object returned by invoking a method. * * @param method The method to call * @param owner The object to call the method on (null for static) * @param allowPrivilegedAccess Allows access to all methods on the object or class * @param args The arguments to pass to the constructor * @return A Reflect wrapper around the constructed object * @throws ReflectionException Something went wrong invoking the method */ public static Reflect on(Method method, Object owner, boolean allowPrivilegedAccess, Object... args) throws ReflectionException { Preconditions.checkNotNull(method); boolean accessible = method.isAccessible(); try { if (!accessible && allowPrivilegedAccess) { method.setAccessible(true); } Object[] convertedArgs = null; if (args != null) { convertedArgs = new Object[args.length]; Class<?>[] parameterTypes = method.getParameterTypes(); for (int i = 0; i < args.length; i++) { convertedArgs[i] = convertValueType(args[i], parameterTypes[i]); } } Object object = method.invoke(owner, convertedArgs); return new Reflect(object, object == null ? Void.class : object.getClass(), allowPrivilegedAccess); } catch (IllegalAccessException | InvocationTargetException e) { throw new ReflectionException(e); } finally { if (!accessible && allowPrivilegedAccess) { method.setAccessible(false); } } } private static Object convertValueType(Object value, Class<?> toClass) { if (Val.class.isAssignableFrom(toClass)) { return Cast.as(value, Val.class).as(toClass); } if (toClass.isAssignableFrom(value.getClass())) { return value; } Object out = Convert.convert(value, toClass); return out == null ? value : out; } /** * Allow privileged access. * * @return An new Reflect object based on the current one that allows privileged access to methods, fields, and * constructors. */ public Reflect allowPrivilegedAccess() { return new Reflect(object, clazz, true); } /** * Allow public access. * * @return An new Reflect object based on the current one that allows public access to methods, fields, and * constructors. */ public Reflect allowPublicAccess() { return new Reflect(object, clazz, false); } /** * Get t. * * @param <T> The object type * @return The object used in reflection or null if there is not one */ public <T> T get() { return Cast.as(object); } /** * Gets reflected class. * * @return Class information for what is being reflected on */ public Class<?> getReflectedClass() { return clazz; } /** * Creates an instance of the class being reflected using the no-argument constructor. * * @return A <code>Reflect</code> object to do further reflection * @throws ReflectionException Something went wrong constructing the object */ public Reflect create() throws ReflectionException { try { return on(clazz.getConstructor(), accessAll); } catch (NoSuchMethodException e) { if (accessAll) { try { return on(clazz.getDeclaredConstructor(), accessAll); } catch (NoSuchMethodException e2) { throw new ReflectionException(e2); } } throw new ReflectionException(e); } } /** * Creates an instance of the class being reflected using the most specific constructor available. * * @param args The arguments to the constructor. * @return A <code>Reflect</code> object to do further reflection * @throws ReflectionException Something went wrong constructing the object */ public Reflect create(Object... args) throws ReflectionException { return create(ReflectionUtils.getTypes(args), args); } /** * Create reflect. * * @param types the types * @param args the args * @return the reflect * @throws ReflectionException the reflection exception */ public Reflect create(Class[] types, Object... args) throws ReflectionException { try { return on(clazz.getConstructor(types), accessAll, args); } catch (NoSuchMethodException e) { for (Constructor constructor : getConstructors()) { if (ReflectionUtils.typesMatch(constructor.getParameterTypes(), types)) { return on(constructor, accessAll, args); } } throw new ReflectionException(e); } } /** * Gets constructors. * * @return The set of constructors for the object which is a combination of * and * if <code>allowPrivilegedAccess</code> * was called. */ public Set<Constructor<?>> getConstructors() { return Sets.union(Sets.newHashSet(clazz.getConstructors()), (accessAll ? Sets.newHashSet(clazz.getDeclaredConstructors()) : Collections.<Constructor<?>>emptySet())); } /** * Gets methods. * * @return The set of methods for the object which is a combination of * and * if <code>allowPrivilegedAccess</code> * was called. */ public Set<Method> getMethods() { return Sets.union(Sets.newHashSet(clazz.getMethods()), (accessAll ? Sets.newHashSet(clazz.getDeclaredMethods()) : Collections.<Method>emptySet())); } /** * Contains method. * * @param name the name * @return the boolean */ public boolean containsMethod(final String name) { if (StringUtils.isNullOrBlank(name)) { return false; } return !Iterables.isEmpty(Iterables.filter(getMethods(), new Predicate<Method>() { @Override public boolean apply(Method input) { return input != null && name.equals(input.getName()); } })); } /** * Gets methods. * * @param name the name * @param numParams the num params * @return the methods */ public Set<Method> getMethods(final String name, final int numParams) { if (StringUtils.isNullOrBlank(name) || numParams < 0) { return Collections.emptySet(); } return Sets.newHashSet(Iterables.filter(getMethods(), new Predicate<Method>() { @Override public boolean apply(Method input) { return input != null && name.equals(input.getName()) && input.getParameterTypes().length == numParams; } })); } /** * Invokes a method with a given name and arguments with the most specific method possible * * @param methodName The name of the method * @param args The arguments to the method * @return A Reflect object representing the results * @throws ReflectionException Something went wrong invoking the method */ public Reflect invoke(String methodName, Object... args) throws ReflectionException { Class[] types = ReflectionUtils.getTypes(args); try { return on(clazz.getMethod(methodName, types), object, accessAll, args); } catch (NoSuchMethodException e) { Method method = ReflectionUtils.bestMatchingMethod(getMethods(), methodName, types); if (method != null) { return on(method, object, accessAll, args); } throw new ReflectionException(e); } } /** * Sets the value of a field. Will perform conversion on the value if needed. * * @param fieldName The name of the field to set * @param value The value to set the field to * @return This instance of Reflect * @throws ReflectionException Something went wrong setting the value of field */ public Reflect set(String fieldName, Object value) throws ReflectionException { try { Field field = clazz.getField(fieldName); value = convertValueType(value, field.getType()); field.set(object, value); return this; } catch (IllegalAccessException | NoSuchFieldException e) { if (!accessAll) { throw new ReflectionException(e); } Field field = null; boolean accessible = true; try { field = clazz.getDeclaredField(fieldName); accessible = field.isAccessible(); field.setAccessible(true); value = convertValueType(value, field.getType()); field.set(object, value); return this; } catch (NoSuchFieldException | IllegalAccessException e2) { throw new ReflectionException(e); } finally { if (field != null && !accessible) { field.setAccessible(false); } } } } /** * Gets the value of a field. * * @param fieldName The name of the field to get * @return An instance of Reflect wrapping the result of the field value * @throws ReflectionException Something went wrong getting the value of field */ public Reflect get(String fieldName) throws ReflectionException { Field f = ReflectionUtils.getField(clazz, fieldName, accessAll); if (f == null) { Class<?> parent = clazz.getSuperclass(); while (f == null && parent != null) { f = ReflectionUtils.getField(parent, fieldName, accessAll); parent = parent.getSuperclass(); } } if (f == null) { throw new ReflectionException( new NoSuchFieldException(fieldName + " is not a valid field for " + clazz)); } boolean isAccessible = f.isAccessible(); try { if (accessAll) { f.setAccessible(true); } return onObject(f.get(object)); } catch (IllegalAccessException e) { e.printStackTrace(); throw new ReflectionException(e); } finally { f.setAccessible(isAccessible); } } /** * Gets fields. * * @return The set of fields for the object which is a combination of * and * if <code>allowPrivilegedAccess</code> * was called. */ public Set<Field> getFields() { Set<Field> fields = Sets.newHashSet(clazz.getFields()); if (accessAll) { Collections.addAll(fields, clazz.getDeclaredFields()); Class<?> parent = clazz.getSuperclass(); while (parent != null) { fields.addAll(Reflect.onClass(parent).allowPrivilegedAccess().getFields()); parent = parent.getSuperclass(); } } return fields; } @Override public String toString() { return object == null ? clazz.toString() : object.toString(); } }//END OF Reflect