Java:如何使用OGNL将properties中的属性值映射到对象树中

比如有如下相互关联的类:

public class User {

    private String gender;

    private String name;

    private int age;

    private Box box;
    
    ......
}


public class Box {

    private Eraser eraser;
    
    private Pen pen;
    
    ......
}

public class Eraser {

    private int coler;

    private int weight;
    
    ......
}

public class Pen {

    private String name;

    private int length;

    ......
}

属性文件中的配置:

gender=male
name=XX
age=21
box.eraser.coler=256
box.eraser.weight=13
box.pen.name=nike
box.pen.length=10

按照一般的处理方式,是先解析配置文件,接着一个一个的创建对象,再给它们赋值,然后建立各个对象之间的关联关系。这样做代码量会很大,而且不方便维护。

有没有方便的方式直接构建对象树后就自动赋值了?有的,可以使用ognl

maven中引入ongl的jar:

<dependency>
	<groupId>ognl</groupId>
	<artifactId>ognl</artifactId>
	<version>3.1.15</version>
</dependency>

先实现ObjectNullHandler,用于告诉OGNL,当属性为null时如何创建这个属性对应的对象

public class DefaultObjectNullHandler extends ObjectNullHandler {

    public Object nullPropertyValue(Map context, Object target, Object property) {
        if (property instanceof String) {
            try {
                String propertyName = (String) property;
                Class<?> propertyType = PropertyUtils.getPropertyType(target, propertyName);

                Object  propertyInstance = propertyType.newInstance();

                PropertyUtils.setProperty(target, propertyName, propertyInstance);

                return propertyInstance;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}

写一个例子测试一下:

public static void doTest() {
	try {
		DefaultObjectNullHandler defaultObjectNullHandler = new DefaultObjectNullHandler();
		// 注册一个ObjectNullHandler
		OgnlRuntime.setNullHandler(Object.class, defaultObjectNullHandler);

		User user = new User();
		
		Ognl.setValue("gender", user, "male");
		Ognl.setValue("name", user, "XX");
		Ognl.setValue("age", user, 21);
		Ognl.setValue("box.eraser.coler", user, 256);
		Ognl.setValue("box.eraser.weight", user, 13);
		Ognl.setValue("box.pen.name", user, "nike");
		Ognl.setValue("box.pen.length", user, 10);
		
	} catch (OgnlException e) {
		e.printStackTrace();
	}
}

只需要通过以上几行代码,就可以自动把对象树构建出来,并且赋上属性值。代码简单明了,用起来也非常方便。
 

如果对象树中出现了数组怎么办:

public class Box {

    private Eraser eraser;
	
    private Pen[] pens;	
}

配置可以改成:

box.pens[0].name=nike
box.pens[0].length=10

ObjectNullHandler的实现中加入创建数组的逻辑:

public class DefaultObjectNullHandler extends ObjectNullHandler {

    public Object nullPropertyValue(Map context, Object target, Object property) {
        if (property instanceof String) {
            try {
                String propertyName = (String) property;
                Class<?> propertyType = PropertyUtils.getPropertyType(target, propertyName);

                Object propertyInstance = null;
				
		if (propertyType.isArray()) {
		// 这里要注意,创建数组时要指定数组大小。配置中的数组索引编号不能大于等于这个值,否则会报NullPointerException
                    propertyInstance = Array.newInstance(propertyType.getComponentType(), 10);
                    Object componentInstance = propertyType.getComponentType().newInstance();
                    Array.set(propertyInstance, 0, componentInstance);
                } else {
                    propertyInstance = propertyType.newInstance();
                }

                PropertyUtils.setProperty(target, propertyName, propertyInstance);

                return propertyInstance;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}

测试例子如下:

public static void doTest() {
	try {
		DefaultObjectNullHandler defaultObjectNullHandler = new DefaultObjectNullHandler();
		// 注册一个ObjectNullHandler
		OgnlRuntime.setNullHandler(Object.class, defaultObjectNullHandler);

		User user = new User();

		Ognl.setValue("box.pen[0].name", user, "nike");
		Ognl.setValue("box.pen[0].length", user, 10);
		
	} catch (OgnlException e) {
		e.printStackTrace();
	}
}

如果出现了list怎么办?这里有两种情况,List中是基础数据类型,List中是自定义类

public class Box {

    private List<String> aliasList;
	
    private List<Pen> penList;	
}

配置文件:

box.aliasList[0]="xx"
box.aliasList[1]="12"
box.aliasList[2]="10000"
box.penList[0].name="xx"
box.penList[1].name="12"
box.penList[2].name="10000"

ObjectNullHandler的实现中加入创建数组的逻辑:

public class DefaultObjectNullHandler extends ObjectNullHandler {
    private Class defaultListClass = ArrayList.class;

    public Object nullPropertyValue(Map context, Object target, Object property) {
        if (property instanceof String) {
            try {
                String propertyName = (String) property;
                Class<?> propertyType = PropertyUtils.getPropertyType(target, propertyName);

                Object propertyInstance = null;

                if (List.class.isAssignableFrom(propertyType)) {
                    propertyInstance = defaultListClass.newInstance();

                    List list = (List)propertyInstance;
					
		    if ("aliasList".equal(propertyName)){
			list.add(null);
			list.add(null);
			list.add(null);
		    } else if ("penList".equal(propertyName)) {
			list.add(new Pen());
			list.add(new Pen());
			list.add(new Pen());
		    }

                } else if (propertyType.isArray()) {
		// 这里要注意,创建数组时要指定数组大小。配置中的数组索引编号不能大于等于这个值,否则会报NullPointerException
                    propertyInstance = Array.newInstance(propertyType.getComponentType(), 10);
                    Object componentInstance = propertyType.getComponentType().newInstance();
                    Array.set(propertyInstance, 0, componentInstance);
                } else {
                    propertyInstance = propertyType.newInstance();
                }

                PropertyUtils.setProperty(target, propertyName, propertyInstance);

                return propertyInstance;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}

测试代码如下:

public static void doTest() {
	try {
		DefaultObjectNullHandler defaultObjectNullHandler = new DefaultObjectNullHandler();

		OgnlRuntime.setNullHandler(Object.class, defaultObjectNullHandler);

		User user = new User();

		Ognl.setValue("box.aliasList[0]", user, "xx");
		Ognl.setValue("box.aliasList[1]", user, "12");
		Ognl.setValue("box.aliasList[2]", user, "10000");
		
		Ognl.setValue("box.penList[0].name", user, "xx");
		Ognl.setValue("box.penList[1].name", user, "12");
		Ognl.setValue("box.penList[2].name", user, "10000");

	} catch (OgnlException e) {
		e.printStackTrace();
	}
}

如果不想在创建List后添加多个null对象,可以使用org.apache.commons.collections.list.GrowthList,Ognl在调用GrowthList.set(...)方法时可直接扩容,而不会像调用其它List.set(...)方法那样会报错。

以上已经把OGNL构建对象树的一些典型情况列举出来了。除了使用ONGL外,也可以使用spring-boot中的@ConfigurationProperties来完成相同的工作,在实际项目中最终选择使用哪种方式,就要看个人偏好了。

除了以上方法,还有一种间接的方法可以将属性映射到对象,就是jackson-dataformat-properties将先properties转化为json,再将json转化为对象。而将json转化为对象可以找到的工具就很多了,这里就不再多讲了。

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-properties</artifactId>
</dependency>

 
 
 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值