1. 程式人生 > >如何使用ognl將properties中的屬性值對映到物件樹中

如何使用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[] penArray;	
}

配置可以改成:

box.pen[0].name=nike
box.pen[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 {

    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.isAssignableFrom(List.class)) {
                    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();
	}
}
以上已經把OGNL構建物件樹的一些典型情況列舉出來了。除了使用ONGL處,也可以使用spring-boot中的@ConfigurationProperties來完成相同的工作,在實際專案中最終選擇使用哪種方式,就要看個人偏好了。