com.googlecode.blaisemath.internal.Reflection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of blaise-common Show documentation
Show all versions of blaise-common Show documentation
Common utilities shared across Blaise projects.
package com.googlecode.blaisemath.internal;
/*-
* #%L
* blaise-common
* --
* Copyright (C) 2014 - 2019 Elisha Peterson
* --
* 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.
* #L%
*/
import java.beans.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.Objects.requireNonNull;
/**
* Some general utilities for working with Java types.
*
* @author Elisha Peterson
*/
public class Reflection {
private static final Logger LOG = Logger.getLogger(Reflection.class.getName());
private static final String FAIL_NEW_MSG = "Failed to invoke constructor";
private static final String FAIL_INVOKE_MSG = "Failed to invoke read method";
private static final String NO_READ_MSG = "No read method available";
private static final String NO_WRITE_MSG = "No write method available";
// utility class
private Reflection() {
}
//region BeanInfo UTILITIES
/**
* Retrieves the BeanInfo for a Class
* @param cls class
* @return bean info
*/
public static BeanInfo beanInfo(Class> cls) {
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(cls);
} catch (IntrospectionException ex) {
LOG.log(Level.WARNING, "Error in bean introspection for class " + cls, ex);
}
return beanInfo;
}
/**
* Return an {@link PropertyDescriptor} for the specified object property.
* @param cls the object class
* @param propName the object's property
* @return the descriptor
* @throws IllegalArgumentException if there is no property with that name in the bean's class
*/
public static PropertyDescriptor propertyDescriptor(Class> cls, String propName) {
for (PropertyDescriptor pd : beanInfo(cls).getPropertyDescriptors()) {
if (pd.getName().equals(propName)) {
return pd;
}
}
throw new IllegalArgumentException("Unable to find property " + propName + " in the class " + cls);
}
/**
* Return an {@link IndexedPropertyDescriptor} for the specified object property.
* @param cls the object class
* @param propName the object's property
* @return the indexed descriptor
* @throws IllegalArgumentException if there is no indexed property with that name in the bean's class
*/
public static IndexedPropertyDescriptor indexedPropertyDescriptor(Class> cls, String propName) {
for (PropertyDescriptor pd : beanInfo(cls).getPropertyDescriptors()) {
if (pd.getName().equals(propName) && pd instanceof IndexedPropertyDescriptor) {
return (IndexedPropertyDescriptor) pd;
}
}
throw new IllegalArgumentException("Unable to find property " + propName + " in the class " + cls);
}
/**
* Execute read method by property descriptor. Returns null if there's an error, or if the read method returns null.
* @param parent object
* @param pd property descriptor
* @return result
*/
public static Object tryInvokeRead(Object parent, PropertyDescriptor pd) {
requireNonNull(parent);
if (pd.getReadMethod() == null) {
LOG.log(Level.FINE, NO_READ_MSG);
return null;
}
try {
return pd.getReadMethod().invoke(parent);
} catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) {
LOG.log(Level.FINE, FAIL_INVOKE_MSG, ex);
}
return null;
}
/**
* Execute write method by property descriptor. Returns null if there's an error, or if the read method returns null.
* @param parent object
* @param pd property descriptor
* @param val value to write
* @return true if successfully written
*/
public static boolean tryInvokeWrite(Object parent, PropertyDescriptor pd, Object val) {
requireNonNull(parent);
if (pd.getWriteMethod() == null) {
LOG.log(Level.FINE, NO_WRITE_MSG);
return false;
}
try {
pd.getWriteMethod().invoke(parent, val);
return true;
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
LOG.log(Level.FINE, FAIL_INVOKE_MSG, ex);
}
return false;
}
/**
* Execute read method by indexed property descriptor. Returns null if there's an error, or if the read method returns null.
* @param parent object
* @param pd property descriptor
* @param index index of property to write
* @return result
*/
public static Object tryInvokeIndexedRead(Object parent, IndexedPropertyDescriptor pd, int index) {
requireNonNull(parent);
if (pd.getIndexedReadMethod() == null) {
LOG.log(Level.FINE, NO_READ_MSG);
return null;
}
try {
return pd.getIndexedReadMethod().invoke(parent, index);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
LOG.log(Level.FINE, FAIL_INVOKE_MSG, ex);
}
return null;
}
/**
* Execute write method by indexed property descriptor. Returns null if there's an error, or if the read method returns null.
* @param parent object
* @param pd property descriptor
* @param index index of property
* @param value value for index
*/
public static void tryInvokeIndexedWrite(Object parent, IndexedPropertyDescriptor pd, int index, Object value) {
requireNonNull(parent);
if (pd.getIndexedWriteMethod() == null) {
LOG.log(Level.FINE, NO_WRITE_MSG);
return;
}
try {
pd.getIndexedWriteMethod().invoke(parent, index, value);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
LOG.log(Level.FINE, FAIL_INVOKE_MSG, ex);
}
}
//endregion
//region METHOD LOOKUPS
/**
* Utility method to lookup a public constructor, returning an empty optional if not found or security issue.
* @param type class type
* @param paramTypes method parameters
* @return constructor if found
*/
public static Optional constructor(Class> type, Class... paramTypes) {
try {
Constructor c = type.getConstructor(paramTypes);
if (Modifier.isPublic(c.getModifiers())) {
return Optional.of(c);
}
} catch (NoSuchMethodException | SecurityException ex) {
LOG.log(Level.FINEST, "Not found", ex);
}
return Optional.empty();
}
/**
* Utility method to lookup a public static method, returning an empty optional if not found or security issue.
* @param type class type
* @param name method name
* @param paramTypes method parameters
* @return method if found
*/
public static Optional staticMethod(Class> type, String name, Class... paramTypes) {
try {
Method m = type.getMethod(name, paramTypes);
if (Modifier.isStatic(m.getModifiers()) && Modifier.isPublic(m.getModifiers())) {
return Optional.of(m);
}
} catch (NoSuchMethodException | SecurityException ex) {
LOG.log(Level.FINEST, "Not found", ex);
}
return Optional.empty();
}
/**
* Utility method to lookup a public static method by one of several possible names, returning an empty optional if
* not found or security issue.
* @param type class type
* @param names possible names
* @param paramTypes method parameters
* @return method if found
*/
public static Optional staticMethod(Class type, String[] names, Class... paramTypes) {
for (String n : names) {
Optional m = staticMethod(type, n, paramTypes);
if (m.isPresent()) {
return m;
}
}
return Optional.empty();
}
//endregion
//region METHOD INVOCATION
/**
* Executes default constructor to return object of given type, if possible.
* @param type
* @param cls type to construct
* @return new instance, or null if unable to instantiate
*/
@SuppressWarnings("unchecked")
public static T tryInvokeNew(Class cls) {
Constructor con = null;
try {
con = cls.getDeclaredConstructor();
} catch (NoSuchMethodException ex) {
LOG.log(Level.FINE, "There is no no-arg constructor for " + cls, ex);
} catch (SecurityException ex) {
LOG.log(Level.FINE, "Unable to get no-arg constructor for " + cls, ex);
}
if (con == null && Number.class.isAssignableFrom(cls)) {
return cls == Integer.class ? (T) (Integer) 0
: cls == Double.class ? (T) (Double) 0.0
: cls == Float.class ? (T) (Float) 0f
: cls == Long.class ? (T) (Long) 0L
: cls == Short.class ? (T) (Short) (short) 0
: cls == Byte.class ? (T) (Byte) (byte) 0
: cls == Character.class ? (T) (Character) (char) 0
: cls == Boolean.class ? (T) Boolean.TRUE
: null;
}
if (con != null) {
try {
return con.newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
LOG.log(Level.FINE, FAIL_NEW_MSG, ex);
}
}
return null;
}
/**
* Execute read method by property name. Returns null if there's an error, if no read method, or the read method returns null.
* @param parent object
* @param property name of property
* @return result or read method, where null may indicate a failure to read
*/
public static Object tryInvokeRead(Object parent, String property) {
requireNonNull(parent);
return tryInvokeRead(parent, propertyDescriptor(parent.getClass(), property));
}
/**
* Execute write method by property descriptor. Returns null if there's an error, or if the read method returns null.
* @param parent object
* @param property name of property
* @param val value to write
* @return true if successfully written
*/
public static boolean tryInvokeWrite(Object parent, String property, Object val) {
requireNonNull(parent);
return tryInvokeWrite(parent, propertyDescriptor(parent.getClass(), property), val);
}
//endregion
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy