使用commons-beans BeanUtils将JavaBean转换为具有嵌套名称的键/值映射 [英] Convert a JavaBean to key/value Map with nested name using commons-beans BeanUtils

查看:313
本文介绍了使用commons-beans BeanUtils将JavaBean转换为具有嵌套名称的键/值映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始使用BeanUtils将Properties文件转换为JavaBean. 使用BeanUtils.populate,我可以很好地做到这一点.但是我可以正确实现从JavaBean到Map的逆向转换(仅存储简单值).

I start using BeanUtils to convert a Properties files to a JavaBean. Using BeanUtils.populate, I'm able to do this nicely. But I can achieve the retro conversion from the JavaBean to the Map correctly (only simple values are store).

请参阅BeanUtils文档中基于Employee类的示例.

See this sample based on the Employee Class form the BeanUtils documentation.

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"之类的键?

What am I missing so that the map2 stores actually keys like "address(pro).city" or "subordinate[1].firstName" using the BeanUtils.describe method ?

推荐答案

最后,我找到了解决此问题的方法.首先,我需要基于当前的bean实例来检索每个嵌套的propertyName,并且这是递归的.所以我写了一个简单的方法来做到这一点:

Finally I find a way to solve this. First of all, I need to retrieve every nested propertyName based on my current bean instance, and this recursively. So I've wrote a simple method to do this :

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;
    }
}

然后我迭代其他名称以检索属性值,然后在地图中进行设置.

And then I iterate other those names to retrieve property value and then set them in the 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));
}

这对于我的用例来说效果很好.我只是在源对象中添加了一个访问器,以使用常规名称(propertyName +"Map"或"List")访问Map或List.

This work well for my use case. I simply had add an accessor in my source object for accessing the Map or the List with a conventional name (propertyName + "Map" or "List").

也许这会使某人感兴趣.无论如何,如果还有其他更明显的事情要做,请告诉我.

Maybe this could interest someone. Anyway, if there is something more obvious to do it, let me know.

这篇关于使用commons-beans BeanUtils将JavaBean转换为具有嵌套名称的键/值映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆