オブジェクトの属性タイプ、属性名、属性値を取得する研究:反射とJEXL解析エンジン

7792 ワード


同期パブリケーション:http://www.yuanrengu.com/index.php/20170511.html
まず反射の概念を簡単に紹介します:java反射メカニズムは運行状態の中で、いずれのクラスに対しても、このクラスのすべての属性と方法を知ることができます;任意のオブジェクトに対して、任意のメソッドと属性を呼び出すことができます.このような動的取得情報および動的呼び出しオブジェクトメソッドの機能をjava言語の反射メカニズムと呼ぶ.
反射はjavaの強力なツールであり、実行時に組み立てることができる柔軟なコードを簡単に作成できます.実際のビジネスでは、プロパティに基づいて動的に値を取得する場合があります.
ツールクラスは次のとおりです.
 
package com.yaoguang.common.utils.field;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *          
 * 
 * @author heyonggang
 * @date 2017 5 10   5:56:59
 */
public class ObjectFieldUtil {

	private static Logger log = LoggerFactory.getLogger(ObjectFieldUtil.class);

	/**
	 *           
	 * 
	 * @param fieldName     
	 * @param o   
	 * @return
	 */
	public static Object getFieldValueByName(String fieldName, Object o) {
		try {
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getter = "get" + firstLetter + fieldName.substring(1);
			Method method = o.getClass().getMethod(getter, new Class[] {});
			Object value = method.invoke(o, new Object[] {});
			return value;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return null;
		}
	}

	/**
	 *        
	 * 
	 * @param o   
	 * @return
	 */
	public static String[] getFiledName(Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
		String[] fieldNames = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			System.out.println(fields[i].getType());
			fieldNames[i] = fields[i].getName();
		}
		return fieldNames;
	}

	/**
	 *       (type),   (name),   (value) map   list
	 * 
	 * @param o   
	 * @return
	 */
	public static List> getFiledsInfo(Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
//		String[] fieldNames = new String[fields.length];
		List> list = new ArrayList<>();
		Map infoMap = null;
		for (int i = 0; i < fields.length; i++) {
			infoMap = new HashMap();
			infoMap.put("type", fields[i].getType().toString());
			infoMap.put("name", fields[i].getName());
			infoMap.put("value", getFieldValueByName(fields[i].getName(), o));
			list.add(infoMap);
		}
		return list;
	}

	/**
	 *           ,        
	 * 
	 * @param o    
	 * @return
	 */
	public static Object[] getFiledValues(Object o) {
		String[] fieldNames = getFiledName(o);
		Object[] value = new Object[fieldNames.length];
		for (int i = 0; i < fieldNames.length; i++) {
			value[i] = getFieldValueByName(fieldNames[i], o);
		}
		return value;
	}

	/**
	 *             
	 * 
	 * @param fieldName    
	 * @param value    
	 * @param o   
	 * @return
	 */
	public static void setFieldValueByName(String fieldName, Object o,Object value) {
		try {
			BeanInfo obj =Introspector.getBeanInfo(o.getClass(), Object.class);
			PropertyDescriptor[] pds = obj.getPropertyDescriptors();
			for (PropertyDescriptor pd : pds) {
				if(pd.getName().equals(fieldName)){
					pd.getWriteMethod().invoke(o, value);
					break;
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}
}

 
 テスト例は次のとおりです.
/**
	 *            
	 */
	@Test
	public void testGetField(){
		TruckBills truckBills = iTruckBillsService.geTruckBills("02cb5069b44f45dca578e5ada08bf513", "88");
		
		String orderSn = (String) ObjectFieldUtil.getFieldValueByName("orderSn", truckBills);
		String shipper = (String) ObjectFieldUtil.getFieldValueByName("shipper", truckBills);
		
		String[] fieldNames = ObjectFieldUtil.getFiledName(truckBills);
		
		List> listMap = ObjectFieldUtil.getFiledsInfo(truckBills);
		
		System.out.println("---------------------------");
		System.out.println(orderSn);
		System.out.println(shipper);
		System.out.println(Arrays.toString(fieldNames));
		for (Map map : listMap) {
			System.out.println("---------------------------");
			Set> entrySet = map.entrySet();
			for (Entry entry : entrySet) {
				System.out.println(entry.getKey() + "-----" + entry.getValue());
			}
			System.out.println("---------------------------");
		}
	}

 
文字列をjavaコードに変換して実行する方法もあります.Java Expression Language(JEXL)は、アプリケーションまたはフレームワークで使用できる式言語エンジンです.
JEXLは、VelocityとJSPタグライブラリ1.1(JSTL)の影響を受けて発生するものであり、JEXLは、JSTLにおける式言語の実現を時々行わないことに注意が必要である.
まずjarパッケージを追加する必要があります.mavenは次のように構成されています.
 
		
			org.apache.commons
			commons-jexl
			2.0
		

 
 コアコードは次のとおりです.
public class DyMethodUtil {
	
	/**
	 *        java     
	 * 
	 * @param jexlExp         
	 * @param map     
	 * @return       
	 *  :
	 * String jexlExp="testService.save(person)"; 
	 * map.put("testService",testService);  
	 * map.put("person",person);  
	 */
	public static Object invokeMethod(String jexlExp, Map map) {
		JexlEngine jexl = new JexlEngine();
		Expression e = jexl.createExpression(jexlExp);
		JexlContext jc = new MapContext();
		for (String key : map.keySet()) {
			jc.set(key, map.get(key));
		}
		if (null == e.evaluate(jc)) {
			return "";
		}
		return e.evaluate(jc);
	}
}

 テスト例は次のとおりです.
/**
	 *     
	 */
	@Test
	@Rollback(false)
	public void testTemple(){
		//1.     
		//2.       
		//3.    
		
		TruckBills truckBills = iTruckBillsService.geTruckBills("02cb5069b44f45dca578e5ada08bf513", "88");
		
		List truckGoodsAddrs = truckBills.getTruckGoodsAddrs();
		TruckOther truckOther = truckBills.getTruckOther();
		
		Map map = new HashMap<>();
		map.put("truckBills", truckBills);
		
		System.out.println("------------------------");
		System.out.println(JsonBinder.buildNormalBinder().toJson(map));
		System.out.println("------------------------");
		
		String expression = "truckBills.getTruckGoodsAddrs().get(0).getBillsId()";
		
		Object aa = DyMethodUtil.invokeMethod(expression, map);
		System.out.println("------------------------");
		System.out.println(JsonBinder.buildNormalBinder().toJson(aa));
		System.out.println("------------------------");
	}