org.onetwo.common.reflect.Intro Maven / Gradle / Ivy
package org.onetwo.common.reflect;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.ReentrantLock;
import org.onetwo.common.annotation.AnnotationUtils;
import org.onetwo.common.convert.Types;
import org.onetwo.common.exception.BaseException;
import org.onetwo.common.utils.Assert;
import org.onetwo.common.utils.JFishFieldInfoImpl;
import org.onetwo.common.utils.JFishProperty;
import org.onetwo.common.utils.JFishPropertyInfoImpl;
import org.onetwo.common.utils.LangUtils;
import org.onetwo.common.utils.StringUtils;
import org.onetwo.common.utils.TypeJudge;
import org.onetwo.common.utils.list.It;
import org.onetwo.common.utils.list.JFishList;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
public class Intro {
public static Intro wrap(Class clazz){
Intro intro = new Intro(clazz);
return intro;
}
public static final String JAVASSIST_KEY = "_$$_javassist_";
public static final String READMETHOD_KEY = "get";
public static final String BOOLEAN_READMETHOD_KEY = "is";
public static final String WRITEMETHOD_KEY = "set";
private final Class clazz;
private final Map propertyDescriptors;
private Map _fieldMaps;
private ReentrantLock _fieldLock = new ReentrantLock();
// private List allFields;
private Map _allFieldMap;
private ReentrantLock _allFieldLock = new ReentrantLock();
private LoadingCache fieldInfoCaches = CacheBuilder.newBuilder()
.build(new CacheLoader() {
@Override
public JFishFieldInfoImpl load(String propName) throws Exception {
Field field = getField(propName);
return new JFishFieldInfoImpl(clazz, field);
}
});
private LoadingCache propertyInfoCaches = CacheBuilder.newBuilder()
.build(new CacheLoader() {
@Override
public JFishPropertyInfoImpl load(String propName) throws Exception {
PropertyDescriptor pd = getProperty(propName);
return new JFishPropertyInfoImpl(clazz, pd);
}
});
public Intro(Class clazz) {
Assert.notNull(clazz);
this.clazz = clazz;
this.propertyDescriptors = loadPropertyDescriptors();
// this.fields = loadFields();
}
public Class> getClazz() {
return clazz;
}
private Map loadPropertyDescriptors(){
if(clazz==Object.class || clazz.isInterface() || clazz.isPrimitive())
return Collections.emptyMap();
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(clazz, Object.class);
} catch (Exception e) {
throw new BaseException(e);
}
PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
Map maps = new LinkedHashMap();
for(PropertyDescriptor prop : props){
maps.put(prop.getName(), prop);
}
return Collections.unmodifiableMap(maps);
}
public List getAllFields() {
_loadAllFields();
return JFishList.wrap(_allFieldMap.values());
}
public List getAllPropertyNames() {
return JFishList.wrap(propertyDescriptors.keySet());
}
@SuppressWarnings("unchecked")
public List getPropertyNames(final Class extends Annotation>... ignoreAnnotation){
return getPropertyDescriptors(ignoreAnnotation).getPropertyList("name");
}
@SuppressWarnings("unchecked")
public JFishList getPropertyDescriptors(final Class extends Annotation>... ignoreAnnotations){
return JFishList.wrap(this.propertyDescriptors.values()).filter(new It() {
@Override
public boolean doIt(PropertyDescriptor element, int index) {
for(Class extends Annotation> anno : ignoreAnnotations){
if(element.getReadMethod().getAnnotation(anno)!=null){
return false;
}
}
return true;
}
});
}
public Map getAllFieldMap() {
_loadAllFields();
return _allFieldMap;
}
private void _loadAllFields() {
if(_allFieldMap!=null)
return ;
_allFieldLock.lock();
try {
if(_allFieldMap!=null)//dbcheck
return ;
Map tempMap = Maps.newHashMap(getFieldMaps());
List> classes = findSuperClasses(clazz);
// Field[] fs = null;
for (Class> cls : classes) {
/*fs = cls.getDeclaredFields();
for (Field f : fs) {
tempMap.put(f.getName(), f);
}*/
tempMap.putAll(Intro.wrap(cls).getAllFieldMap());
}
this._allFieldMap = ImmutableMap.copyOf(tempMap);
} finally{
_allFieldLock.unlock();
}
}
private void _loadFields(){
if(_fieldMaps!=null)
return ;
this._fieldLock.lock();
try{
if(_fieldMaps!=null)
return ;
if(clazz==Object.class || clazz.isPrimitive()){
_fieldMaps = Collections.emptyMap();
return ;
}
Field[] fields = clazz.getDeclaredFields();
Map maps = new LinkedHashMap(fields.length);
for(Field field : fields){
maps.put(field.getName(), field);
}
this._fieldMaps = ImmutableMap.copyOf(maps);
}finally{
this._fieldLock.unlock();
}
}
public Map getFieldMaps() {
_loadFields();
return _fieldMaps;
}
public Map getPropertyDescriptors() {
return propertyDescriptors;
}
public Collection getProperties(){
return propertyDescriptors.values();
}
public PropertyDescriptor[] getPropertyArray(){
return propertyDescriptors.values().toArray(new PropertyDescriptor[propertyDescriptors.size()]);
}
public PropertyDescriptor getProperty(String propName){
return propertyDescriptors.get(propName);
}
public PropertyDescriptor checkProperty(String propName){
PropertyDescriptor pd = getProperty(propName);
if(pd==null)
throw new BaseException("no property found: " + propName);
return pd;
}
public boolean hasProperty(String propName){
return propertyDescriptors.containsKey(propName);
}
public JFishProperty getJFishProperty(String propName, boolean isField){
JFishProperty prop = null;
if(isField){
/* 改用cache,修复大量获取字段时性能极差的问题
* Field field = getField(propName);
return new JFishFieldInfoImpl(clazz, field);*/
try {
prop = fieldInfoCaches.get(propName);
} catch (ExecutionException e) {
throw new BaseException("no field error", e);
}
}else{
/*PropertyDescriptor pd = getProperty(propName);
return new JFishPropertyInfoImpl(clazz, pd);*/
try {
prop = propertyInfoCaches.get(propName);
} catch (ExecutionException e) {
throw new BaseException("no property error", e);
}
}
return prop;
}
/*public JFishProperty getJFishProperty(String propName){
this._loadProperties();
PropertyDescriptor prop = propCaches.get(propName);
return new JFishPropertyInfoImpl(this, prop);
}*/
public Collection getFields(){
return getFieldMaps().values();
}
public List getFieldList(boolean parent){
if(parent){
return getAllFields();
}else{
return new ArrayList(getFields());
}
}
public Field getField(String fieldName){
return getFieldMaps().get(fieldName);
}
public boolean containsField(String fieldName, boolean includeParent){
if(includeParent){
return getAllFieldMap().containsKey(fieldName);
}else{
return _fieldMaps.containsKey(fieldName);
}
}
public Field getField(String fieldName, boolean parent){
if(parent){
return getAllFieldMap().get(fieldName);
}else{
return getFieldMaps().get(fieldName);
}
}
public Field getStaticField(String fieldName){
Field f = getField(fieldName);
if(Modifier.isStatic(f.getModifiers()))
return f;
return null;
}
public Field checkField(String fieldName, boolean parent){
Field f = getField(fieldName, parent);
if(f==null)
throw new BaseException("no field found: " + fieldName);
return f;
}
public Object getStaticFieldValue(String fieldName, boolean parent) {
Field f = checkField(fieldName, parent);
return getFieldValue(f, clazz, true);
}
public static Object getFieldValue(Field f, Object obj, boolean throwIfError) {
Assert.notNull(f);
try {
if (!f.isAccessible())
f.setAccessible(true);
return f.get(obj);
} catch (Exception ex) {
if (throwIfError)
throw new RuntimeException("get value of field[" + f + "] error: " + ex.getMessage(), ex);
else
return null;
}
}
public static void setFieldValue(Field f, Object obj, Object value) {
Assert.notNull(f);
try {
if (!f.isAccessible())
f.setAccessible(true);
f.set(obj, value==null?null:Types.convertValue(value, f.getType()));
} catch (Exception ex) {
throw new RuntimeException("invoke method error: " + ex.getMessage(), ex);
}
}
public static T newInstance(Class clazz) {
T instance = null;
try {
instance = clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("instantce class error : " + clazz, e);
}
return instance;
}
public Object getFieldValue(Object obj, String fieldName) {
return getFieldValue(obj, fieldName, true);
}
public Object getFieldValue(Object obj, String fieldName, boolean parent) {
Assert.isInstanceOf(clazz, obj);
Field f = checkField(fieldName, parent);
return getFieldValue(f, obj, true);
}
public void setFieldValue(Object obj, String fieldName, Object value) {
setFieldValue(obj, fieldName, value, true);
}
public void setFieldValue(Object obj, String fieldName, Object value, boolean parent) {
Assert.isInstanceOf(clazz, obj);
Field field = checkField(fieldName, parent);
setFieldValue(field, obj, value);
}
public void setStaticFieldValue(Object value, String fieldName) {
setStaticFieldValue(value, fieldName, true);
}
public void setStaticFieldValue(Object value, String fieldName, boolean parent) {
Field field = checkField(fieldName, parent);
setFieldValue(field, clazz, value);
}
public T newInstance(){
T bean = (T)newInstance(clazz);
return bean;
}
public T newInstance(Map propValues, TypeJudge typeJudge){
T bean = newInstance();
Collection props = getProperties();
Object val = null;
for(PropertyDescriptor prop : props){
val = propValues.get(prop.getName());
if(typeJudge!=null){
val = LangUtils.judgeType(val, prop.getPropertyType(), typeJudge);
}
ReflectUtils.setProperty(bean, prop, val);
}
return bean;
}
/********
* 遍历map
* @param propValues
* @return
*/
public T newBy(Map propValues){
T bean = newInstance();
for(Entry entry : propValues.entrySet()){
ReflectUtils.setExpr(bean, entry.getKey(), entry.getValue());
}
return bean;
}
/***************
* 遍历字段和属性
* @param propValues
* @return
*/
public T newFrom(Map, ?> propValues){
T bean = newInstance();
Collection fieldNames = ReflectUtils.findInstanceFieldNames(clazz, Set.class);
Collection propNames = ReflectUtils.desribPropertiesName(clazz, Set.class);
propNames.addAll(fieldNames);
Object val = null;
for(String name : propNames){
val = propValues.get(name);
if(val!=null)
ReflectUtils.setExpr(bean, name, val);
}
return bean;
}
public Object setPropertyValue(Object element, String propName, Object value) {
Method writeMthod = getWriteMethod(propName);
if(writeMthod==null)
throw new NoSuchElementException("no write method found, class:"+element.getClass()+", property:"+propName);
return ReflectUtils.invokeMethod(writeMthod, element, value);
}
public Object setPropertyValue(Object element, PropertyDescriptor pd, Object value) {
Method writeMthod = pd.getWriteMethod();
if(writeMthod==null)
throw new NoSuchElementException("no write method found, class:"+element.getClass()+", property:"+pd.getName());
return ReflectUtils.invokeMethod(writeMthod, element, value);
}
public Object getPropertyValue(Object element, String propName) {
Method readMethod = getReadMethod(propName);
if(readMethod==null)
throw new NoSuchElementException("no read method found, class:"+element.getClass()+", property:"+propName);
return ReflectUtils.invokeMethod(readMethod, element);
}
public Object getPropertyValue(Object element, PropertyDescriptor pd) {
Method readMethod = pd.getReadMethod();
if(readMethod==null)
throw new NoSuchElementException("no read method found, class:"+element.getClass()+", property:"+pd.getName());
return ReflectUtils.invokeMethod(readMethod, element);
}
public Method getReadMethod(String propName) {
PropertyDescriptor pd = checkProperty(propName);
Method readMethod;
// if (Serializable.class.equals(pd.getPropertyType())) {
if (pd.getReadMethod()==null || pd.getReadMethod().isBridge()) {
String rmethodName = getReadMethodName(pd.getName(), pd.getPropertyType());
readMethod = ReflectUtils.findPublicMethod(clazz, rmethodName);
} else {
readMethod = pd.getReadMethod();
}
return readMethod;
}
public Method getWriteMethod(String propName) {
PropertyDescriptor pd = checkProperty(propName);
Method writeMethod;
if (pd.getWriteMethod()==null || pd.getWriteMethod().isBridge()) {
String wmethodName = getWriteMethodName(pd.getName());
writeMethod = ReflectUtils.findPublicMethod(clazz, wmethodName);
} else {
writeMethod = pd.getWriteMethod();
}
return writeMethod;
}
public static String getReadMethodName(String propName, Class> returnType) {
String getMethod = StringUtils.capitalize(propName);
if (returnType!=null && Boolean.class.equals(returnType) || boolean.class.equals(returnType)) {
getMethod = BOOLEAN_READMETHOD_KEY + getMethod;
} else {
getMethod = READMETHOD_KEY + getMethod;
}
return getMethod;
}
public static String getWriteMethodName(String name) {
String getMethod = StringUtils.capitalize(name);
return WRITEMETHOD_KEY + getMethod;
}
public Collection desribPropertyNames() {
return this.propertyDescriptors.keySet();
}
public boolean isCollectionType(){
return Collection.class.isAssignableFrom(clazz);
}
public boolean isMapType(){
return Map.class.isAssignableFrom(clazz);
}
public void copy(Object source, Object target, PropertyCopyer copyer){
Collection sourceProperties = ReflectUtils.getIntro(source.getClass()).desribPropertyNames();
for(PropertyDescriptor targetProperty : this.propertyDescriptors.values()){//propertyDescriptors is target
if(sourceProperties.contains(targetProperty.getName()))
copyer.copy(source, target, targetProperty);
}
}
public List> findSuperClasses() {
return findSuperClasses(Object.class);
}
public List> findSuperClasses(Class> stopClass) {
List> classes = new ArrayList>();
Class> parent = clazz.getSuperclass();
while (parent != null && !parent.equals(stopClass)) {
classes.add(parent);
parent = parent.getSuperclass();
}
return classes;
}
public Collection getNotStaticAndTransientFields(boolean parent) {
Collection fields = getFieldList(false);
Collection rsfields = LangUtils.newArrayList();
for (Field f : fields) {
if(Modifier.isTransient(f.getModifiers()) || Modifier.isStatic(f.getModifiers()))
continue;
rsfields.add(f);
}
return rsfields;
}
public E getAnnotationWithParent(Class annotationClass) {
return AnnotationUtils.findAnnotationWithParent(clazz, annotationClass);
}
public E getAnnotationWithSupers(Class annotationClass) {
return AnnotationUtils.findAnnotationWithSupers(clazz, annotationClass);
}
public E getAnnotationWithInterfaces(Class annotationClass) {
return AnnotationUtils.findAnnotationWithInterfaces(clazz, annotationClass);
}
public String toString(){
return "class wraper["+clazz+"]";
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy