加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

将Java Bean展平为地图

发布时间:2020-12-15 03:01:16 所属栏目:Java 来源:网络整理
导读:我坚持将 Java Bean转换为Map.互联网上有很多资源,但不幸的是,它们都将简单的bean转换为地图.我的那些更广泛. 有简化的例子: public class MyBean { private String firstName; private String lastName; private MyHomeAddress homeAddress; private int a
我坚持将 Java Bean转换为Map.互联网上有很多资源,但不幸的是,它们都将简单的bean转换为地图.我的那些更广泛.

有简化的例子:

public class MyBean {

  private String firstName;
  private String lastName;
  private MyHomeAddress homeAddress;
  private int age;

  // getters & setters

}

我的观点是生成Map< String,Object>在这种情况下,对于以下条件是正确的:

map.containsKey("firstName")
map.containsKey("lastName")
map.containsKey("homeAddress.street")  // street is String
map.containsKey("homeAddress.number")  // number is int
map.containsKey("homeAddress.city")    // city is String
map.containsKey("homeAddress.zipcode") // zipcode is String
map.containsKey("age")

我尝试过使用Apache Commons BeanUtils.两种方法BeanUtils #thedes(Object)和BeanMap(Object)都生成一个“深层次”为1的Map(我的意思是只有“homeAddress”键,将MyHomeAddress对象保存为值).我的方法应该越来越深入地进入对象,直到它遇到基本类型(或字符串),然后它应该停止挖掘和插入键,即“order.customer.contactInfo.home”.

所以,我的问题是:如何轻松完成(或者是否已经存在允许我这样做的项目)?

更新

我已经扩展了Radiodef的答案,还包括Collections,Maps Arrays和Enums:

private static boolean isValue(Object value) {
  final Class<?> clazz = value.getClass();
  if (value == null ||
      valueClasses.contains(clazz) ||
      Collection.class.isAssignableFrom(clazz) ||
      Map.class.isAssignableFrom(clazz) ||
      value.getClass().isArray() ||
      value.getClass().isEnum()) {
    return true;
  }
  return false;
}

解决方法

这是一个简单的反射/递归示例.

您应该知道,按照您提出的方式进行转换存在一些问题:

>地图键必须是唯一的.
> Java允许类将其私有字段命名为与继承类拥有的私有字段相同的名称.

这个例子没有解决这些问题,因为我不确定你想如何解释它们(如果你这样做).如果你的bean继承自Object以外的东西,你需要稍微改变一下你的想法.此示例仅考虑子类的字段.

换句话说,如果你有

public class SubBean extends Bean {

此示例仅返回SubBean中的字段.

Java让我们这样做:

package com.acme.util;
public class Bean {
    private int value;
}

package com.acme.misc;
public class Bean extends com.acme.util.Bean {
    private int value;
}

并不是说任何人都应该这样做,但是如果你想使用String作为键是一个问题,因为会有两个名为“value”的键.

import java.lang.reflect.*;
import java.util.*;

public final class BeanFlattener {
    private BeanFlattener() {}

    public static Map<String,Object> deepToMap(Object bean) {
        Map<String,Object> map = new LinkedHashMap<>();
        try {
            putValues(bean,map,null);
        } catch (IllegalAccessException x) {
            throw new IllegalArgumentException(x);
        }
        return map;
    }

    private static void putValues(Object bean,Map<String,Object> map,String prefix)
            throws IllegalAccessException {
        Class<?> cls = bean.getClass();

        for (Field field : cls.getDeclaredFields()) {
            if (field.isSynthetic() || Modifier.isStatic(field.getModifiers()))
                continue;
            field.setAccessible(true);

            Object value = field.get(bean);
            String key;
            if (prefix == null) {
                key = field.getName();
            } else {
                key = prefix + "." + field.getName();
            }

            if (isValue(value)) {
                map.put(key,value);
            } else {
                putValues(value,key);
            }
        }
    }

    private static final Set<Class<?>> VALUE_CLASSES =
        Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
            Object.class,String.class,Boolean.class,Character.class,Byte.class,Short.class,Integer.class,Long.class,Float.class,Double.class
            // etc.
        )));

    private static boolean isValue(Object value) {
        return value == null
            || value instanceof Enum<?>
            || VALUE_CLASSES.contains(value.getClass());
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读