Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将JavaBean展平到地图_Java_Javabeans_Apache Commons - Fatal编程技术网

将JavaBean展平到地图

将JavaBean展平到地图,java,javabeans,apache-commons,Java,Javabeans,Apache Commons,我一直在把javabean转换成Map。互联网上有很多资源,但不幸的是,它们都处理将简单bean转换为地图的问题。我的范围更广一点 有一个简单的例子: public class MyBean { private String firstName; private String lastName; private MyHomeAddress homeAddress; private int age; // getters & setters } 我的观点是生成M

我一直在把
javabean
转换成
Map
。互联网上有很多资源,但不幸的是,它们都处理将简单bean转换为地图的问题。我的范围更广一点

有一个简单的例子:

public class MyBean {

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

  // getters & setters

}
我的观点是生成
Map
,在本例中,它适用于以下条件:

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")
我尝试过使用ApacheCommonsBeanutils。这两种方法都是
BeanUtils#descripe(Object)
BeanMap(Object)
生成一个“deep level”为1的映射(我的意思是只有
“homemaddress”
键,将
myhomemaddress
对象作为一个值)。我的方法应该越来越深入地输入对象,直到它遇到基元类型(或字符串),然后停止挖掘并插入键,即“order.customer.contactInfo.home”

所以,我的问题是:如何才能轻松完成(或者是否已有项目允许我这么做)

更新

我已将Radiodef答案扩展到包括集合、地图阵列和枚举:

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;
}
私有静态布尔值(对象值){
最终类clazz=value.getClass();
如果(值==null)||
valueClasses.contains(clazz)||
Collection.class.isAssignableFrom(clazz)||
Map.class.isAssignableFrom(clazz)||
value.getClass().isArray()||
value.getClass().isEnum()){
返回true;
}
返回false;
}

下面是一个简单的反射/递归示例

您应该意识到,按照您要求的方式进行转换存在一些问题:

  • 映射键必须是唯一的
  • Java允许类将其私有字段命名为与继承类所拥有的私有字段相同的名称
这个例子没有解决这些问题,因为我不确定你想如何解释它们(如果你想的话)。如果您的bean继承自除
对象
之外的其他对象,则需要稍微改变您的想法。本例仅考虑子类的字段

换句话说,如果你有

public class SubBean extends Bean {
此示例仅返回子bean中的字段

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;
}
并不是说任何人都应该这样做,但是如果您想使用
字符串
作为键,这是一个问题,因为有两个键名为
“value”

import java.lang.reflect.*;
导入java.util.*;
公共最后一堂课豆瓣机{
专用BeanFlattener(){}
公共静态映射deepToMap(对象bean){
Map Map=newlinkedhashmap();
试一试{
putValue(bean、map、null);
}捕获(IllegalacessException x){
抛出新的IllegalArgumentException(x);
}
返回图;
}
私有静态值(对象bean,
地图,
字符串前缀)
抛出非法访问异常{
类cls=bean.getClass();
for(字段:cls.getDeclaredFields()){
if(field.isSynthetic()| | Modifier.isStatic(field.getModifiers()))
继续;
字段。setAccessible(true);
对象值=field.get(bean);
字符串键;
if(前缀==null){
key=field.getName();
}否则{
key=前缀+“+”字段.getName();
}
if(isValue(value)){
map.put(键、值);
}否则{
putValues(值、映射、键);
}
}
}
私有静态最终集
||VALUE_CLASSES.contains(VALUE.getClass());
}
}
您可以随时使用。像这样:

import com.fasterxml.jackson.databind.ObjectMapper;
//...
ObjectMapper objectMapper = new ObjectMapper();
//...
@SuppressWarnings("unchecked")
Map<String, Object> map = objectMapper.convertValue(pojo, Map.class);
import com.fasterxml.jackson.databind.ObjectMapper;
//...
ObjectMapper ObjectMapper=新的ObjectMapper();
//...
@抑制警告(“未选中”)
Map Map=objectMapper.convertValue(pojo,Map.class);
其中pojo是一些javabean。您可以在bean上使用一些漂亮的注释来控制序列化


您可以重复使用ObjectMapper。

您可能不是指“基元”,因为
String
不是基元(它扩展了
Object
)。因此,您需要一种方法来告诉算法哪些类需要遍历,哪些类需要作为值,因此在没有某种配置(可能使用注释)的情况下,可能无法做到这一点。这可以通过反射和递归来完成,您几乎可以肯定必须自己编写。请注意,此时问题将结束,因为询问库建议是离题的。Tonio,Radiodef-感谢您的建议,我已经编辑了我的帖子。您好,通常我会遇到需要将bean映射到传输对象的情况。当创建页面对象以显示或以某种方式将结构从一种更改为另一种时,通常会出现这种情况。在这些情况下,我使用Dozer或ModelMapper之类的工具,允许使用各种方法进行映射,如xml、api或基于注释的方法。@TechTrip感谢您提到Dozer和ModelMapper。不幸的是,它们都不允许JavaBean最终出现在地图中。不管怎样,我刚刚读到了关于它们的文章,它们似乎是非常有趣的工具。谢谢,这个实现很有魅力。我已经扩展了
isValue(Object)
方法,还包括了我的项目中需要的另一个类(参见我的帖子)。感谢您在@Radiodef上提供了一段很棒的代码。我已经为这段代码编写了一些单元测试,我计划在Api中使用它,我想知道在这段代码中是否有人会遇到一些错误?@AngelThread只是在这里再次浏览我的代码,我看到的唯一明显的问题是,如果它传递了一个包含循环引用的对象,例如
类a{B;},它将导致
StackOverflowerError
OutOfMemoryError
B类{A;}
。这样的目标
import com.fasterxml.jackson.databind.ObjectMapper;
//...
ObjectMapper objectMapper = new ObjectMapper();
//...
@SuppressWarnings("unchecked")
Map<String, Object> map = objectMapper.convertValue(pojo, Map.class);