如何使用ognl將properties中的屬性值對映到物件樹中
阿新 • • 發佈:2019-02-20
比如有如下相互關聯的類:
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來完成相同的工作,在實際專案中最終選擇使用哪種方式,就要看個人偏好了。