/** * Copyright 2014 Duan Bingnan * * 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 org.pinus4j.utils; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.sql.Timestamp; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import org.pinus4j.constant.Const; import org.pinus4j.entity.annotations.DateTime; import org.pinus4j.entity.annotations.PrimaryKey; import org.pinus4j.entity.annotations.UpdateTime; /** * 反射工具类. 提供了一些简单的反射功能. 方便其他操作调用. * * @author duanbn */ public class BeansUtil { /** * 字段别名缓存,当没有指定别名时,使用字段名作为别名. key: 别名/字段名 */ public static final Map<String, Field> _aliasFieldCache = new ConcurrentHashMap<String, Field>(); /** * 类属性缓存. 缓存反射结果 */ public static final Map<Class<?>, Field[]> _fieldCache = new ConcurrentHashMap<Class<?>, Field[]>(); /** * 接口的缓存 */ private static final Map<String, Class<?>[]> interfaceCache = new HashMap<String, Class<?>[]>(); public static final Map<String, Class<?>> classCache = new HashMap<String, Class<?>>(); /** * 通过反射获取对象的属性值. * * @param obj 被反射对象 * @param propertyName 属性名 * @return 属性值 * @throws Exception 操作失败 */ public static Object getProperty(Object obj, String propertyName) { Field f = getField(obj.getClass(), propertyName); f.setAccessible(true); try { return f.get(obj); } catch (Exception e) { throw new RuntimeException(e); } } /** * 通过反射给对象属性赋值. * * @param obj 被反射的对象 * @param propertyName 赋值的属性名 * @param value 值 * @throws Exception 操作失败 */ public static void setProperty(Object obj, String propertyName, Object value) { if (obj == null) { throw new IllegalArgumentException("param should not be null"); } Class<?> clazz = obj.getClass(); Field f = getField(clazz, propertyName); if (f != null) { try { f.setAccessible(true); if (value == null) { f.set(obj, null); return; } // 这里不能支持装箱类型,否则反射会报错 if (f.getType() == Boolean.TYPE) { f.setBoolean(obj, ((Boolean) value).booleanValue()); } else if (f.getType() == Integer.TYPE) { f.setInt(obj, ((Number) value).intValue()); } else if (f.getType() == Byte.TYPE) { f.setByte(obj, ((Number) value).byteValue()); } else if (f.getType() == Long.TYPE) { f.setLong(obj, ((Number) value).longValue()); } else if (f.getType() == Short.TYPE) { f.setShort(obj, ((Number) value).shortValue()); } else if (f.getType() == Float.TYPE) { f.setFloat(obj, ((Number) value).floatValue()); } else if (f.getType() == Double.TYPE) { f.setDouble(obj, ((Number) value).doubleValue()); } else if (f.getType() == Character.TYPE) { f.setChar(obj, ((Character) value).charValue()); } else { f.set(obj, value); } } catch (Exception e) { throw new RuntimeException(e); } } else { Method[] setMethods = clazz.getMethods(); for (Method setMethod : setMethods) { if (setMethod.getName().equals("set" + StringUtil.upperFirstLetter(propertyName))) { if (setMethod.getParameterTypes().length == 1) { try { setMethod.invoke(obj, value); } catch (Exception e) { throw new RuntimeException(e); } return; } } } } } @Deprecated public static void setProperty(Object obj, String propertyName, String value) { if (obj == null) { throw new IllegalArgumentException("param should not be null"); } Class<?> clazz = obj.getClass(); Field f = getField(clazz, propertyName); if (f != null) { try { f.setAccessible(true); if (value == null) { f.set(obj, null); return; } // 这里不能支持装箱类型,否则反射会报错 if (f.getType() == Boolean.TYPE || f.getType() == Boolean.class) { f.setBoolean(obj, (Boolean.valueOf(value)).booleanValue()); } else if (f.getType() == Integer.TYPE || f.getType() == Integer.class) { f.setInt(obj, Integer.parseInt(value)); } else if (f.getType() == Byte.TYPE || f.getType() == Byte.class) { f.setByte(obj, Byte.parseByte(value)); } else if (f.getType() == Long.TYPE || f.getType() == Long.class) { f.setLong(obj, Long.parseLong(value)); } else if (f.getType() == Short.TYPE || f.getType() == Short.class) { f.setShort(obj, Short.valueOf(value)); } else if (f.getType() == Float.TYPE || f.getType() == Float.class) { f.setFloat(obj, Float.valueOf(value)); } else if (f.getType() == Double.TYPE || f.getType() == Double.class) { f.setDouble(obj, Double.valueOf(value)); } else if (f.getType() == Character.TYPE || f.getType() == Character.class) { f.setChar(obj, value.charAt(0)); } else { f.set(obj, value); } } catch (Exception e) { throw new RuntimeException(e); } } else { Method[] setMethods = clazz.getMethods(); for (Method setMethod : setMethods) { if (setMethod.getName().equals("set" + StringUtil.upperFirstLetter(propertyName))) { if (setMethod.getParameterTypes().length == 1) { Class<?> paramType = setMethod.getParameterTypes()[0]; try { if (paramType == Boolean.TYPE || paramType == Boolean.class) { setMethod.invoke(obj, (Boolean.valueOf(value)).booleanValue()); } else if (paramType == Integer.TYPE || paramType == Integer.class) { setMethod.invoke(obj, Integer.parseInt(value)); } else if (paramType == Byte.TYPE || paramType == Byte.class) { setMethod.invoke(obj, Byte.parseByte(value)); } else if (paramType == Long.TYPE || paramType == Long.class) { setMethod.invoke(obj, Long.parseLong(value)); } else if (paramType == Short.TYPE || paramType == Short.class) { setMethod.invoke(obj, Short.valueOf(value)); } else if (paramType == Float.TYPE || paramType == Float.class) { setMethod.invoke(obj, Float.valueOf(value)); } else if (paramType == Double.TYPE || paramType == Double.class) { setMethod.invoke(obj, Double.valueOf(value)); } else if (paramType == Character.TYPE || paramType == Character.class) { setMethod.invoke(obj, value.charAt(0)); } else { setMethod.invoke(obj, value); } } catch (Exception e) { throw new RuntimeException(e); } return; } } } } } /** * 获取对象的属性描述. * * @param obj 被反射的对象 * @param isFilteDefault 是否过滤掉默认值 * @return {属性名, 属性值} */ public static Map<String, Object> describe(Object obj, boolean isFilteNull) throws Exception { if (obj == null) { throw new IllegalArgumentException("参数错误, obj=null"); } Class<?> objClass = obj.getClass(); Map<String, Object> map = new TreeMap<String, Object>(); Object value = null; for (Field f : getFields(objClass, true)) { f.setAccessible(true); if (f.getAnnotation(UpdateTime.class) != null) { f.set(obj, new Timestamp(System.currentTimeMillis())); } value = f.get(obj); Class<?> fTypeClazz = f.getType(); org.pinus4j.entity.annotations.Field annoField = f .getAnnotation(org.pinus4j.entity.annotations.Field.class); if (fTypeClazz == String.class && annoField != null && annoField.length() > Const.COLUMN_TEXT_LENGTH && value == null) { value = ""; } // 过滤默认值 if (isFilteNull) { if (value == null) { continue; } // if (fTypeClazz == Boolean.TYPE || fTypeClazz == Boolean.class) { // if (!(Boolean) value) { // continue; // } // } else if (fTypeClazz == Byte.TYPE || fTypeClazz == Byte.class) { // if ((Byte) value == 0) { // continue; // } // } else if (fTypeClazz == Character.TYPE || fTypeClazz == Character.class) { // if ((Character) value == 0) { // continue; // } // } else if (fTypeClazz == Short.TYPE || fTypeClazz == Short.class) { // if ((Short) value == 0) { // continue; // } // } else if (fTypeClazz == Integer.TYPE || fTypeClazz == Integer.class) { // if ((Integer) value == 0) { // continue; // } // } else if (fTypeClazz == Long.TYPE || fTypeClazz == Long.class) { // if ((Long) value == 0l) { // continue; // } // } else if (fTypeClazz == Float.TYPE || fTypeClazz == Float.class) { // if ((Float) value == 0.0f) { // continue; // } // } else if (fTypeClazz == Double.TYPE || fTypeClazz == Double.class) { // if ((Double) value == 0.0) { // continue; // } // } } map.put(getFieldName(f), value); } return map; } public static void copyProperties(Object source, Object target) throws Exception { if (source == null) { throw new IllegalArgumentException("source should not be null"); } if (target == null) { throw new IllegalArgumentException("target should not be null"); } Field targetField = null; for (Field sourceField : getFields(source.getClass(), true)) { sourceField.setAccessible(true); targetField = target.getClass().getDeclaredField(sourceField.getName()); targetField.setAccessible(true); if (targetField != null) { targetField.set(target, sourceField.get(source)); } } } public static void putAliasField(Class<?> clazz, String fieldName, Field f) { _aliasFieldCache.put(clazz.getName() + fieldName, f); } /** * 支持通过别名获取Field * * @param clazz * @param field * @return */ public static Field getField(Class<?> clazz, String fieldName) { // 优先根据别名来获取 Field field = _aliasFieldCache.get(clazz.getName() + fieldName); // 根据别名获取不到时 if (field == null) { try { field = clazz.getDeclaredField(fieldName); } catch (Exception e) { // 忽略错误 } } // 查找父类 if (field == null) { Class<?> superClass = clazz.getSuperclass(); if (superClass != null) { field = getField(superClass, fieldName); } } return field; } /** * 获取字段名,包括别名 * * @param field * @return */ public static String getFieldName(Field field) { // 兼容字段别名 String fieldName = field.getName(); org.pinus4j.entity.annotations.Field annoField = field .getAnnotation(org.pinus4j.entity.annotations.Field.class); if (annoField != null && StringUtil.isNotBlank(annoField.name())) { fieldName = annoField.name(); } PrimaryKey annoPrimaryKey = field.getAnnotation(PrimaryKey.class); if (annoPrimaryKey != null && StringUtil.isNotBlank(annoPrimaryKey.name())) { fieldName = annoPrimaryKey.name(); } DateTime annoDateTime = field.getAnnotation(DateTime.class); if (annoDateTime != null && StringUtil.isNotBlank(annoDateTime.name())) { fieldName = annoDateTime.name(); } UpdateTime annoUpdateTime = field.getAnnotation(UpdateTime.class); if (annoUpdateTime != null && StringUtil.isNotBlank(annoUpdateTime.name())) { fieldName = annoUpdateTime.name(); } return fieldName; } /** * 获取类的所有属性名. * * @return 字段名 */ public static Field[] getFields(Class<?> clazz, boolean isCheckEmpty) { Field[] fields = _fieldCache.get(clazz); if (fields != null) { return fields; } List<Field> mappingFields = new ArrayList<Field>(); for (Field f : clazz.getDeclaredFields()) { if (f.getAnnotation(PrimaryKey.class) != null) { mappingFields.add(f); } else if (f.getAnnotation(org.pinus4j.entity.annotations.Field.class) != null) { mappingFields.add(f); } else if (f.getAnnotation(DateTime.class) != null) { mappingFields.add(f); } else if (f.getAnnotation(UpdateTime.class) != null) { mappingFields.add(f); } } if (mappingFields.isEmpty() && isCheckEmpty) { throw new IllegalStateException("没有包含可以操作的列属性" + clazz); } fields = mappingFields.toArray(new Field[mappingFields.size()]); _fieldCache.put(clazz, fields); return fields; } /** * 克隆一个对象,只保留给定的属性值. * * @param obj 被克隆的对象. * @param fieldNames 需要被保留的属性名. * @return 克隆对象. */ public static Object cloneWithGivenField(Object obj, String... fieldNames) throws Exception { if (fieldNames == null || fieldNames.length == 0) { return obj; } Object clone = obj.getClass().newInstance(); Object value = null; for (String fieldName : fieldNames) { value = getProperty(obj, fieldName); setProperty(clone, fieldName, value); } return clone; } /** * 根据字符串获取Class * * @param name class全名 * @return Class */ public static Class<?> getClass(String name) { try { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class<?> c = classCache.get(name); if (c == null) { c = loader.loadClass(name); classCache.put(name, c); } return c; } catch (ClassNotFoundException e) { throw new IllegalStateException(e); } } /** * 获取一个对象实现的接口. * * @param clazz 对象的class * @return 接口的class */ public static Class<?>[] getInterfaces(Class<?> clazz) { Class<?>[] interfaces = interfaceCache.get(clazz.getName()); if (interfaces == null) { List<Class<?>> classList = new ArrayList<Class<?>>(); Class<?> curClass = clazz; while (curClass != Object.class) { for (Class<?> interf : curClass.getInterfaces()) { if (!classList.contains(interf)) { classList.add(interf); } } curClass = curClass.getSuperclass(); } interfaces = classList.toArray(new Class<?>[classList.size()]); interfaceCache.put(clazz.getName(), interfaces); } return interfaces; } }