我开始使用BeanUtils将Properties文件转换为JavaBean。 使用BeanUtils.populate,我能够很好地完成这项工作。但是我可以正确地实现从JavaBean到Map的复古转换(只存储简单的值)。
根据BeanUtils文档的Employee Class查看此示例。
import org.apache.commons.beanutils.BeanUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Employee {
private Map<String, Address> addressMap = new HashMap<String, Address>();
private List<Employee> subordinateList = new ArrayList<Employee>();
private String firstName;
private String lastName;
public Address getAddress(String type) {
if (!addressMap.containsKey(type)) {
addressMap.put(type, new Address());
}
return addressMap.get(type);
}
public void setAddress(String type, Address address) {
addressMap.put(type, address);
}
public Employee getSubordinate(int index) {
if (subordinateList.size() <= index) {
subordinateList.add(new Employee());
}
return subordinateList.get(index);
}
public void setSubordinate(int index, Employee subordinate) {
subordinateList.add(index, subordinate);
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public class Address {
private String city;
private String street;
private int number;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
public static void main(String[] args) throws Exception {
Map<String, Object> map = new TreeMap<String, Object>();
map.put("firstName", "MyfirstName");
map.put("lastName", "MylastName");
map.put("address(pro).city", "MyProCity");
map.put("address(pro).street", "MyProStreet");
map.put("address(pro).number", 22);
map.put("subordinate[1].firstName", "Sub1FirstName");
map.put("subordinate[1].lastName", "Sub1LastName");
map.put("address(perso).city", "MyPersoCity");
map.put("address(perso).street", "MyPersoStreet");
map.put("address(perso).number", 2);
map.put("subordinate[0].firstName", "Sub0FirstName");
map.put("subordinate[0].lastName", "Sub0LastName");
Employee employee = new Employee();
BeanUtils.populate(employee, map);
System.out.println(employee.getFirstName());
System.out.println(employee.getLastName());
System.out.println(employee.getAddress("pro").city);
System.out.println(employee.getAddress("pro").street);
System.out.println(employee.getAddress("pro").number);
System.out.println(employee.getAddress("perso").city);
System.out.println(employee.getAddress("perso").street);
System.out.println(employee.getAddress("perso").number);
System.out.println(employee.getSubordinate(0).firstName);
System.out.println(employee.getSubordinate(0).lastName);
System.out.println(employee.getSubordinate(1).firstName);
System.out.println(employee.getSubordinate(1).lastName);
Map<String, Object> map2 = BeanUtils.describe(employee);
System.out.println("----------------");
System.out.println(map2);
}
}
结果:
MyfirstName
MylastName
MyProCity
MyProStreet
22
MyPersoCity
MyPersoStreet
2
Sub0FirstName
Sub0LastName
Sub1FirstName
Sub1LastName
----------------
{lastName=MylastName, class=class Employee, firstName=MyfirstName}
我缺少什么,以便map2使用BeanUtils.describe方法实际存储像“address(pro).city”或“subordinate [1] .firstName”这样的键?
答案 0 :(得分:1)
最后我找到了解决这个问题的方法。首先,我需要根据我当前的bean实例检索每个嵌套的propertyName,并且这是递归的。所以我写了一个简单的方法来做到这一点:
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class MyPropertyUtils {
public List<String> listNestedPropertyName(Object objectSource) throws Exception {
List<String> nodeNameList = new ArrayList<String>();
if (Serializable.class.isAssignableFrom(objectSource.getClass())) {
nodeNameList.add(objectSource.toString());
return nodeNameList;
}
PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(objectSource.getClass());
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
Method method = propertyDescriptor.getReadMethod();
if (propertyDescriptor.getReadMethod() == null) {
continue;
}
if (method.getGenericParameterTypes().length > 0) {
continue;
}
String name = propertyDescriptor.getName();
Object value = method.invoke(objectSource);
if (value == null) {
continue;
}
if (Map.class.isAssignableFrom(value.getClass())) { // Mapped name
Map map = ((Map) value);
name = StringUtils.substringBeforeLast(name, "Map");
for (Object key : map.keySet()) {
String mappedName = name + "(" + key.toString() + ")";
List<String> nestedNames = listNestedPropertyName(map.get(key));
for (String nestedName : nestedNames) {
nodeNameList.add(mappedName + "." + nestedName);
}
}
} else if (List.class.isAssignableFrom(value.getClass())) { // Indexed name
List list = ((List) value);
name = StringUtils.substringBeforeLast(name, "List");
for (int i = 0; i < list.size(); i++) {
String indexedName = name + "[" + i + "]";
List<String> nestedNames = listNestedPropertyName(list.get(i));
for (String nestedName : nestedNames) {
nodeNameList.add(indexedName + "." + nestedName);
}
}
} else if (Serializable.class.isAssignableFrom(value.getClass())) { // Simple Value
nodeNameList.add(name);
} else { // Nested Value
List<String> nestedNames = listNestedPropertyName(value);
for (String nestedName : nestedNames) {
nodeNameList.add(name + "." + nestedName);
}
}
}
return nodeNameList;
}
}
然后我迭代其他名称以检索属性值,然后在Map中设置它们。
Map<String, Object> map = new HashMap<String, Object>();
MyPropertyUtils myPropertyUtils = new MyPropertyUtils();
List<String> names = myPropertyUtils.listNestedPropertyName(employee);
for (String name : names) {
map.put(name, PropertyUtils.getNestedProperty(employee, name));
}
这对我的用例很有用。我只是在源对象中添加了一个访问器,用于访问具有常规名称的Map或List(propertyName +“Map”或“List”)。
也许这会让某人感兴趣。无论如何,如果有更明显的事情要做,请告诉我。