com.squeakysand.commons.beans.BeanHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of squeakysand-commons Show documentation
Show all versions of squeakysand-commons Show documentation
Classes, interfaces and enums that assist with everyday Java development tasks.
The newest version!
/*
* Copyright 2010-2012 Craig S. Dickson (http://craigsdickson.com)
*
* 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 com.squeakysand.commons.beans;
import com.squeakysand.commons.lang.ToStringHelper;
import com.squeakysand.commons.util.CollectionUtils;
import com.squeakysand.commons.util.FilteredList;
import com.squeakysand.commons.util.Predicate;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility class providing common functionality related to working with JavaBeans.
*
* @author Craig S. Dickson
*/
public final class BeanHelper {
private static class PropertyMapNamePredicate implements Predicate> {
private List propertyNames;
public PropertyMapNamePredicate(String... propertyNames) {
this.propertyNames = Arrays.asList(propertyNames);
}
@Override
public boolean evaluate(Entry entry) {
return propertyNames.contains(entry.getKey());
}
}
private static Logger LOG = LoggerFactory.getLogger(BeanHelper.class);
public static void copyBeanProperties(Object sourceBean, Object targetBean) throws BeanHelperException {
Map sourcePropertyValues = getPropertyValues(sourceBean, true);
Set sourcePropertyNames = sourcePropertyValues.keySet();
List targetWriteableProperties = getWriteableProperties(targetBean.getClass());
for (PropertyDescriptor writeableProperty : targetWriteableProperties) {
String targetPropertyName = writeableProperty.getName();
if (sourcePropertyNames.contains(targetPropertyName)) {
Method setter = writeableProperty.getWriteMethod();
Object propertyValue = sourcePropertyValues.get(targetPropertyName);
try {
setter.invoke(targetBean, propertyValue);
} catch (IllegalAccessException e) {
throw new BeanHelperException(e.getMessage(), e);
} catch (IllegalArgumentException e) {
throw new BeanHelperException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new BeanHelperException(e.getMessage(), e);
}
}
}
}
/**
* Generates a String representation of the state of the JavaBean passed in. Includes only the read-write properties
* (equivalent to calling getPropertyString(o, false)).
*
* @param bean
* the JavaBean.
* @return a formatted String representing the values of the JavaBean properties of the bean.
*/
public static String getPropertiesString(Object bean) {
return getPropertiesString(bean, false);
}
/**
* Generates a String representation of the state of the JavaBean passed in.
*
* @param bean
* the JavaBean.
* @param includeReadOnlyProperties
* indicates if read-only properties should be included.
* @return a formatted String representing the values of the JavaBean properties of the bean.
*/
public static String getPropertiesString(Object bean, boolean includeReadOnlyProperties) {
if (bean == null) {
throw new IllegalArgumentException("parameter 'bean' cannot be null");
}
Map properties = null;
try {
properties = BeanHelper.getPropertyValues(bean, includeReadOnlyProperties);
} catch (BeanHelperException e) {
LOG.error(e.getMessage(), e);
}
StringBuilder sb = new StringBuilder("{");
if (properties != null) {
for (String key : properties.keySet()) {
sb.append(key);
sb.append(" : ");
Object value = properties.get(key);
String valueAsString = ToStringHelper.toString(value);
sb.append(valueAsString);
sb.append(", ");
}
// chop off the last comma separator
if (sb.length() > 1) {
sb.setLength(sb.length() - 2);
}
}
sb.append("}");
return sb.toString();
}
public static PropertyDescriptor getPropertyDescriptor(Class> klass, String propertyName) throws BeanHelperException {
PropertyDescriptor result = null;
List descriptors = getPropertyDescriptors(klass);
for (PropertyDescriptor descriptor : descriptors) {
if (descriptor.getName().equals(propertyName)) {
result = descriptor;
break;
}
}
return result;
}
/**
* @param element
* a setter or getter method.
* @return the associated PropertyDescriptor.
*/
public static PropertyDescriptor getPropertyDescriptor(ExecutableElement element) throws BeanHelperException {
PropertyDescriptor result = null;
String propertyName = getPropertyName(element);
LOG.debug("for element " + element.getSimpleName() + " property name is " + propertyName);
if (propertyName != null) {
String className = ((TypeElement) element.getEnclosingElement()).getQualifiedName().toString();
Class> klass = null;
try {
klass = Thread.currentThread().getContextClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
System.out.println("cnfe: " + e.getMessage());
LOG.error(e.getMessage(), e);
throw new BeanHelperException(e);
}
List properties = getPropertyDescriptors(klass);
for (PropertyDescriptor pd : properties) {
System.out.println("checking pd " + ToStringHelper.toString(pd));
if (pd.getName().equals(propertyName)) {
result = pd;
break;
}
}
}
System.out.println("for element " + element.getSimpleName() + " pd is " + ToStringHelper.toString(result));
return result;
}
public static PropertyDescriptor getPropertyDescriptor(Object bean, String propertyName) throws BeanHelperException {
return getPropertyDescriptor(bean.getClass(), propertyName);
}
public static List getPropertyDescriptors(Class> klass) throws BeanHelperException {
return getPropertyDescriptors(klass, PropertyDescriptorFilter.Include.ALL);
}
public static List getPropertyDescriptors(Class> klass, PropertyDescriptorFilter.Include includedProperties)
throws BeanHelperException {
PropertyDescriptor[] propertyDescriptors;
try {
propertyDescriptors = Introspector.getBeanInfo(klass).getPropertyDescriptors();
} catch (IntrospectionException e) {
throw new BeanHelperException(e);
}
List result = Arrays.asList(propertyDescriptors);
switch (includedProperties) {
case READABLE:
result = new FilteredList(result, PropertyDescriptorFilter.READABLE);
break;
case WRITEABLE:
result = new FilteredList(result, PropertyDescriptorFilter.WRITEABLE);
break;
case READ_WRITE:
result = new FilteredList(result, PropertyDescriptorFilter.READ_WRITE);
break;
default:
// the only other option is ALL, so we just return the result list "as is"
}
return result;
}
public static String getPropertyName(ExecutableElement element) {
String propertyName = null;
String methodName = element.getSimpleName().toString();
LOG.debug("for element " + element.getSimpleName() + " method name is " + methodName);
if (isPropertyGetter(element)) {
if (methodName.startsWith("is")) {
propertyName = Introspector.decapitalize(methodName.substring(2));
} else {
propertyName = Introspector.decapitalize(methodName.substring(3));
}
} else if (isPropertySetter(element)) {
LOG.debug("for element " + element.getSimpleName() + " is a property setter");
propertyName = Introspector.decapitalize(methodName.substring(3));
LOG.debug("for element " + element.getSimpleName() + " raw property name " + methodName.substring(3));
}
return propertyName;
}
public static List getPropertyNames(Class> klass) throws BeanHelperException {
return getPropertyNames(klass, PropertyDescriptorFilter.Include.ALL);
}
public static List getPropertyNames(Class> klass, PropertyDescriptorFilter.Include includedProperties) throws BeanHelperException {
List result = new ArrayList();
List properties = getPropertyDescriptors(klass, includedProperties);
for (PropertyDescriptor descriptor : properties) {
result.add(descriptor.getName());
}
// ignore the 'class' property inherited from the Object class
result.remove("class");
Collections.sort(result);
return result;
}
public static Object getPropertyValue(Object bean, String propertyName) throws BeanHelperException {
Object result = null;
PropertyDescriptor descriptor = getPropertyDescriptor(bean, propertyName);
if (descriptor == null) {
throw new BeanHelperException(String.format("property %s not found for class %s", propertyName, bean.getClass()));
}
Method getter = descriptor.getReadMethod();
if (getter == null) {
throw new BeanHelperException(String.format("property %s is not readable for class %s", propertyName, bean.getClass()));
}
try {
result = getter.invoke(bean, (Object[]) null);
} catch (IllegalAccessException e) {
throw new BeanHelperException(e.getMessage(), e);
} catch (IllegalArgumentException e) {
throw new BeanHelperException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new BeanHelperException(e.getMessage(), e);
}
return result;
}
/**
* Introspects the passed in object and returns a map of the bean's property names and their current values.
*
* @param bean
* the JavaBean to introspect.
* @return a Map, keys are the property names, values are the current values of those properties.
* @throws com.squeakysand.commons.beans.BeanHelperException
* if there are any problems during the introspection (e.g. security issues etc).
*/
public static Map getPropertyValues(Object bean) throws BeanHelperException {
return getPropertyValues(bean, true);
}
/**
* Introspects the passed in object and returns a map of the bean's property names and their current values.
*
* @param bean
* the JavaBean to introspect.
* @param includeReadOnlyProperties
* indicates if read-only properties (i.e. properties that do not have a setter method) should be
* included in the result.
* @return a Map, keys are the property names, values are the current values of those properties.
* @throws com.squeakysand.commons.beans.BeanHelperException
* if there are any problems during the introspection (e.g. security issues etc).
*/
public static Map getPropertyValues(Object bean, boolean includeReadOnlyProperties) throws BeanHelperException {
Map result = new TreeMap();
List properties = null;
Class> beanClass = bean.getClass();
if (includeReadOnlyProperties) {
properties = getPropertyDescriptors(beanClass, PropertyDescriptorFilter.Include.READABLE);
} else {
properties = getPropertyDescriptors(beanClass, PropertyDescriptorFilter.Include.READ_WRITE);
}
for (PropertyDescriptor descriptor : properties) {
try {
Method getter = descriptor.getReadMethod();
Object value = getter.invoke(bean, (Object[]) null);
result.put(descriptor.getName(), value);
} catch (IllegalAccessException e) {
LOG.info("unable to access property '{}' of class {} via reflection - change logging level to debug for more info", descriptor.getName(),
beanClass.getName());
LOG.debug(e.getLocalizedMessage(), e);
} catch (InvocationTargetException e) {
LOG.info("unable to access property '{}' of class {} via reflection - change logging level to debug for more info", descriptor.getName(),
beanClass.getName());
LOG.debug(e.getLocalizedMessage(), e);
}
}
// ignore the 'class' property inherited from the Object class
result.remove("class");
return result;
}
public static Map getPropertyValues(Object bean, boolean includeReadOnlyProperties, String... propertyNameFilter) throws BeanHelperException {
Map allPropertyValues = getPropertyValues(bean, includeReadOnlyProperties);
return CollectionUtils.filter(allPropertyValues, new PropertyMapNamePredicate(propertyNameFilter));
}
public static Map getPropertyValues(Object bean, String... propertyNameFilter) throws BeanHelperException {
return getPropertyValues(bean, true, propertyNameFilter);
}
public static List getReadableProperties(Class> klass) throws BeanHelperException {
return getPropertyDescriptors(klass, PropertyDescriptorFilter.Include.READABLE);
}
public static List getSetterMethods(Class> klass) throws BeanHelperException {
List result = new ArrayList();
List writeableProperties = getWriteableProperties(klass);
for (PropertyDescriptor propertyDescriptor : writeableProperties) {
Method setterMethod = propertyDescriptor.getWriteMethod();
result.add(setterMethod);
}
return result;
}
public static List getWriteableProperties(Class> klass) throws BeanHelperException {
return getPropertyDescriptors(klass, PropertyDescriptorFilter.Include.WRITEABLE);
}
public static boolean isPropertyGetter(ExecutableElement element) {
boolean result = false;
if ((element.getKind() == ElementKind.METHOD) && element.getModifiers().contains(Modifier.PUBLIC)) {
String methodName = element.getSimpleName().toString();
if (methodName.startsWith("is") && element.getReturnType().getKind().equals(TypeKind.BOOLEAN) && element.getParameters().isEmpty()) {
result = true;
} else if (methodName.startsWith("get") && element.getParameters().isEmpty()) {
result = true;
}
}
return result;
}
public static boolean isPropertySetter(ExecutableElement element) {
boolean result = false;
System.out.println("checking property setter status of " + element.getSimpleName());
if ((element.getKind() == ElementKind.METHOD) && element.getModifiers().contains(Modifier.PUBLIC)) {
System.out.println("for element " + element.getSimpleName() + " is a method and is public");
String methodName = element.getSimpleName().toString();
System.out.println("method namme: " + methodName + ", return type: " + element.getReturnType().getKind() + " equals " + TypeKind.VOID + " "
+ element.getReturnType().equals(TypeKind.VOID) + ", parameter size: " + element.getParameters().size());
if (methodName.startsWith("set") && element.getReturnType().getKind().equals(TypeKind.VOID) && (element.getParameters().size() == 1)) {
result = true;
}
}
return result;
}
private BeanHelper() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy