获取对象属性类型、属性名称、属性值的研究:反射和JEXL解析引擎

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 同步发布:http://www.yuanrengu.com/index.php/20170511.html先简单介绍下反射的概念:java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

 

同步发布: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<Map<String, Object>> getFiledsInfo(Object o) {
		Field[] fields = o.getClass().getDeclaredFields();
//		String[] fieldNames = new String[fields.length];
		List<Map<String, Object>> list = new ArrayList<>();
		Map<String, Object> infoMap = null;
		for (int i = 0; i < fields.length; i++) {
			infoMap = new HashMap<String, Object>();
			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<Map<String, Object>> listMap = ObjectFieldUtil.getFiledsInfo(truckBills);
		
		System.out.println("---------------------------");
		System.out.println(orderSn);
		System.out.println(shipper);
		System.out.println(Arrays.toString(fieldNames));
		for (Map<String, Object> map : listMap) {
			System.out.println("---------------------------");
			Set<Entry<String, Object>> entrySet = map.entrySet();
			for (Entry<String, Object> 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配置如下:

 

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-jexl</artifactId>
			<version>2.0</version>
		</dependency>

 

 核心代码如下:

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<String, Object> 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<TruckGoodsAddr> truckGoodsAddrs = truckBills.getTruckGoodsAddrs();
		TruckOther truckOther = truckBills.getTruckOther();
		
		Map<String, Object> 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("------------------------");
	}

 

img_e00999465d1c2c1b02df587a3ec9c13d.jpg
微信公众号: 猿人谷
如果您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】
如果您希望与我交流互动,欢迎关注微信公众号
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

目录
相关文章
|
19天前
|
机器学习/深度学习 安全 大数据
揭秘!企业级大模型如何安全高效私有化部署?全面解析最佳实践,助你打造智能业务新引擎!
【10月更文挑战第24天】本文详细探讨了企业级大模型私有化部署的最佳实践,涵盖数据隐私与安全、定制化配置、部署流程、性能优化及安全措施。通过私有化部署,企业能够完全控制数据,确保敏感信息的安全,同时根据自身需求进行优化,提升计算性能和处理效率。示例代码展示了如何利用Python和TensorFlow进行文本分类任务的模型训练。
58 6
|
1月前
|
开发框架 供应链 监控
并行开发模型详解:类型、步骤及其应用解析
在现代研发环境中,企业需要在有限时间内推出高质量的产品,以满足客户不断变化的需求。传统的线性开发模式往往拖慢进度,导致资源浪费和延迟交付。并行开发模型通过允许多个开发阶段同时进行,极大提高了产品开发的效率和响应能力。本文将深入解析并行开发模型,涵盖其类型、步骤及如何通过辅助工具优化团队协作和管理工作流。
57 3
|
19天前
|
缓存 监控 网络协议
一文带你了解10大DNS攻击类型,收藏!
【10月更文挑战第23天】
128 1
一文带你了解10大DNS攻击类型,收藏!
|
15天前
|
Kubernetes Cloud Native 调度
云原生批量任务编排引擎Argo Workflows发布3.6,一文解析关键新特性
Argo Workflows是CNCF毕业项目,最受欢迎的云原生工作流引擎,专为Kubernetes上编排批量任务而设计,本文主要对最新发布的Argo Workflows 3.6版本的关键新特性做一个深入的解析。
|
19天前
|
存储 消息中间件 NoSQL
Redis数据结构:List类型全面解析
Redis数据结构——List类型全面解析:存储多个有序的字符串,列表中每个字符串成为元素 Eelement,最多可以存储 2^32-1 个元素。可对列表两端插入(push)和弹出(pop)、获取指定范围的元素列表等,常见命令。 底层数据结构:3.2版本之前,底层采用**压缩链表ZipList**和**双向链表LinkedList**;3.2版本之后,底层数据结构为**快速链表QuickList** 列表是一种比较灵活的数据结构,可以充当栈、队列、阻塞队列,在实际开发中有很多应用场景。
|
17天前
|
Dart 安全 编译器
Flutter结合鸿蒙next 中数据类型转换的高级用法:dynamic 类型与其他类型的转换解析
在 Flutter 开发中,`dynamic` 类型提供了灵活性,但也带来了类型安全性问题。本文深入探讨 `dynamic` 类型及其与其他类型的转换,介绍如何使用 `as` 关键字、`is` 操作符和 `whereType&lt;T&gt;()` 方法进行类型转换,并提供最佳实践,包括避免过度使用 `dynamic`、使用 Null Safety 和异常处理,帮助开发者提高代码的可读性和可维护性。
69 1
|
1月前
|
存储 编译器 C语言
C++类与对象深度解析(一):从抽象到实践的全面入门指南
C++类与对象深度解析(一):从抽象到实践的全面入门指南
48 8
|
1月前
|
弹性计算 负载均衡 网络协议
内部名称解析设置阿里云私有 DNS 区域,针对于阿里云国际版经验教程
内部名称解析设置阿里云私有 DNS 区域,针对于阿里云国际版经验教程
|
18天前
|
存储 NoSQL 关系型数据库
Redis的ZSet底层数据结构,ZSet类型全面解析
Redis的ZSet底层数据结构,ZSet类型全面解析;应用场景、底层结构、常用命令;压缩列表ZipList、跳表SkipList;B+树与跳表对比,MySQL为什么使用B+树;ZSet为什么用跳表,而不是B+树、红黑树、二叉树
|
1月前
|
安全 Java 编译器
Java 泛型深入解析:类型安全与灵活性的平衡
Java 泛型通过参数化类型实现了代码重用和类型安全,提升了代码的可读性和灵活性。本文深入探讨了泛型的基本原理、常见用法及局限性,包括泛型类、方法和接口的使用,以及上界和下界通配符等高级特性。通过理解和运用这些技巧,开发者可以编写更健壮和通用的代码。

推荐镜像

更多