Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/396.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
Java内省:要映射的对象_Java_Introspection - Fatal编程技术网

Java内省:要映射的对象

Java内省:要映射的对象,java,introspection,Java,Introspection,我有一个Java对象obj,它具有属性obj.attr1,obj.attr2等。如果不是公共的,则可以通过额外的间接层访问这些属性:obj.getAttr1(),obj.getAttr2() 挑战:我想要一个函数,它接受一个对象,并返回一个映射,其中键是字符串“attr1”,“attr2”等,值是对应的对象obj.attr1,obj.attr2。 我想该函数将通过以下方式调用 toMap(obj) 或toMap(obj,“attr1”、“attr3”)(其中attr1和attr3是obj属性的

我有一个Java对象
obj
,它具有属性
obj.attr1
obj.attr2
等。如果不是公共的,则可以通过额外的间接层访问这些属性:
obj.getAttr1()
obj.getAttr2()

挑战:我想要一个函数,它接受一个对象,并返回一个
映射
,其中键是字符串
“attr1”
“attr2”
等,值是对应的对象
obj.attr1
obj.attr2
。 我想该函数将通过以下方式调用

  • toMap(obj)
  • toMap(obj,“attr1”、“attr3”)
    (其中
    attr1
    attr3
    obj
    属性的子集)
  • 或者,如果需要,可以
    toMap(obj,“getAttr1”、“getAttr3”)
我对Java的内省知之甚少:在Java中如何做到这一点

现在,对于我关心的每种对象类型,我都有一个专门的
toMap()


注意:对于那些了解Python的人,我想要类似于
obj的东西。或者
dict((attr,obj.\uuuu getattribute\uuuuuu(attr))用于attr\u列表中的attr)
用于子集变量。

这是一种非常简单的方法

使用lib将对象转换为JSON

然后读取JSON并将其转换为映射

地图将包含你想要的一切

这是4号班轮

ObjectMapper om = new ObjectMapper();
StringWriter sw = new StringWriter();
om.writeValue(object, sw);
Map<String, Object> map = om.readValue(sw.toString(), Map.class);
ObjectMapper om=new ObjectMapper();
StringWriter sw=新的StringWriter();
om.writeValue(对象,sw);
Map Map=om.readValue(sw.toString(),Map.class);

当然,另一个好处是这是递归的,如果需要,它将创建地图的地图。这里有一个粗略的近似值,希望足够让您指出正确的方向:

public Map<String, Object> getMap(Object o) {
    Map<String, Object> result = new HashMap<String, Object>();
    Field[] declaredFields = o.getClass().getDeclaredFields();
    for (Field field : declaredFields) {
        result.put(field.getName(), field.get(o));
    }
    return result;
}
publicmap-getMap(对象o){
映射结果=新的HashMap();
字段[]declaredFields=o.getClass().getDeclaredFields();
for(字段:declaredFields){
put(field.getName(),field.get(o));
}
返回结果;
}

您可以使用JavaBeans内省来实现这一点。阅读
java.beans.Introspector
类:

public static Map<String, Object> introspect(Object obj) throws Exception {
    Map<String, Object> result = new HashMap<String, Object>();
    BeanInfo info = Introspector.getBeanInfo(obj.getClass());
    for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
        Method reader = pd.getReadMethod();
        if (reader != null)
            result.put(pd.getName(), reader.invoke(obj));
    }
    return result;
}
publicstaticmap内省(objectobj)引发异常{
映射结果=新的HashMap();
BeanInfo info=Introspector.getBeanInfo(obj.getClass());
对于(PropertyDescriptor pd:info.getPropertyDescriptors()){
方法reader=pd.getReadMethod();
if(读卡器!=null)
put(pd.getName(),reader.invoke(obj));
}
返回结果;
}

大警告:我的代码只处理getter方法;它找不到裸露的田野。有关字段,请参见HighlyAffinated的答案::-)(您可能希望结合使用这两种方法。)

使用Apache Commons BeanUtils:

Map for JavaBeans的一个实现,它使用内省在bean中获取和放置属性:

Map<Object, Object> introspected = new org.apache.commons.beanutils.BeanMap(object); 
Map introspected=neworg.apache.commons.beanutils.BeanMap(对象);
注意:尽管API返回
Map
(从1.9.0开始),返回的Map中键的实际类是
java.lang.String

另一种用户方式是
转换值
例如:

 ObjectMapper m = new ObjectMapper();
 Map<String,Object> mappedObject = m..convertValue(myObject, new TypeReference<Map<String, String>>() {});
ObjectMapper m=newObjectMapper();
Map mappedObject=m..convertValue(myObject,新类型引用(){});

这些都不适用于嵌套属性,对象映射器做得很好,只是您必须在所有要在映射中看到的字段上设置所有值,即使这样,您也无法在ObjectMapper中轻松避免/忽略对象拥有的@Json注释基本上跳过一些属性。所以不幸的是,你必须做如下的事情,这只是一个草稿,只是给出一个想法

/*
     * returns fields that have getter/setters including nested fields as
     * field0, objA.field1, objA.objB.field2, ... 
     * to take care of recursive duplicates, 
     * simply use a set<Class> to track which classes
     * have already been traversed
     */
    public static void getBeanUtilsNestedFields(String prefix, 
            Class clazz,  List<String> nestedFieldNames) throws Exception {
        PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(clazz);
        for(PropertyDescriptor descr : descriptors){
            // if you want values, use: descr.getValue(attributeName)
            if(descr.getPropertyType().getName().equals("java.lang.Class")){
                continue;
            }
            // a primitive, a CharSequence(String), Number, Date, URI, URL, Locale, Class, or corresponding array
            // or add more like UUID or other types
            if(!BeanUtils.isSimpleProperty(descr.getPropertyType())){
                Field collectionfield = clazz.getDeclaredField(descr.getName());
                if(collectionfield.getGenericType() instanceof ParameterizedType){
                    ParameterizedType integerListType = (ParameterizedType) collectionfield.getGenericType();
                    Class<?> actualClazz = (Class<?>) integerListType.getActualTypeArguments()[0];
                    getBeanUtilsNestedFields(descr.getName(), actualClazz, nestedFieldNames);
                }
                else{   // or a complex custom type to get nested fields
                    getBeanUtilsNestedFields(descr.getName(), descr.getPropertyType(), nestedFieldNames);
                }
            }
            else{
                nestedFieldNames.add(prefix.concat(".").concat(descr.getDisplayName()));
            }
        }
    }
/*
*返回具有getter/setter的字段,包括嵌套字段作为
*字段0,objA.field1,objA.objB.field2。。。
*要处理递归重复项,
*只需使用一个集合来跟踪哪些类
*已经被穿越了
*/
公共静态void getBeanutilsTestedFields(字符串前缀,
类clazz,列表nestedFieldName)引发异常{
PropertyDescriptor[]描述符=BeanUtils.getPropertyDescriptors(clazz);
for(PropertyDescriptor描述:描述符){
//如果需要值,请使用:descr.getValue(attributeName)
if(descr.getPropertyType().getName().equals(“java.lang.Class”)){
继续;
}
//原语、字符序列(字符串)、数字、日期、URI、URL、区域设置、类或相应的数组
//或者添加更多类似UUID或其他类型
如果(!BeanUtils.isSimpleProperty(descr.getPropertyType())){
Field collectionfield=clazz.getDeclaredField(descr.getName());
if(collectionfield.getGenericType()实例为ParameterizedType){
ParameteredType integerListType=(ParameteredType)collectionfield.getGenericType();
类actualClazz=(类)integerListType.getActualTypeArguments()[0];
getBeanUtilsNestedFields(descr.getName(),actualClazz,nestedFieldNames);
}
else{//或复杂的自定义类型以获取嵌套字段
getBeanUtilsNestedFields(descr.getName()、descr.getPropertyType()、nestedFieldNames);
}
}
否则{
添加(前缀为.concat(“.”).concat(descr.getDisplayName());
}
}
}
maven依赖项

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
    </dependency>
相反,我得到了这些:

查询条件:{"startTime":{"dayOfMonth":15,"dayOfWeek":"MONDAY","dayOfYear":196,"hour":20,"minute":38,"month":"JULY","monthValue":7,"nano":263000000,"year":2019,"second":12,"chronology":{"id":"ISO","calendarType":"iso8601"}},"endTime":{"dayOfMonth":16,"dayOfWeek":"TUESDAY","dayOfYear":197,"hour":20,"minute":38,"month":"JULY","monthValue":7,"nano":263000000,"year":2019,"second":12,"chronology":{"id":"ISO","calendarType":"iso8601"}}}
{startTime={dayOfMonth=15, dayOfWeek=MONDAY, dayOfYear=196, hour=20, minute=38, month=JULY, monthValue=7, nano=263000000, year=2019, second=12, chronology={id=ISO, calendarType=iso8601}}, endTime={dayOfMonth=16, dayOfWeek=TUESDAY, dayOfYear=197, hour=20, minute=38, month=JULY, monthValue=7, nano=263000000, year=2019, second=12, chronology={id=ISO, calendarType=iso8601}}, nodeId=null, fsId=null, memId=null, ifCardId=null}
经过几次研究,发现了一个有效的窍门

ObjectMapper mapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
//https://github.com/networknt/light-4j/issues/82
mapper.registerModule(module);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//incase of empty/null String
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
Map<String,Object> filter = mapper.convertValue(this,Map.class);
System.out.printf("查询条件:%s\n", JSON.toJSONString(filter));
return filter;
我在MyBatis中使用上述代码进行动态查询
例如

/***
* 查询文件系统使用率
*@param条件
*@返回
*/
LinkedList queryFileSystemUsage(映射条件)
查询条件:{"startTime":{"2019-07-15T20:43:15"},"endTime":{"2019-07-16T20:43:15"}
{startTime={2019-07-15T20:43:15}, endTime={"2019-07-16T20:43:15"}, nodeId=null, fsId=null, memId=null, ifCardId=null}
查询条件:{"startTime":{"dayOfMonth":15,"dayOfWeek":"MONDAY","dayOfYear":196,"hour":20,"minute":38,"month":"JULY","monthValue":7,"nano":263000000,"year":2019,"second":12,"chronology":{"id":"ISO","calendarType":"iso8601"}},"endTime":{"dayOfMonth":16,"dayOfWeek":"TUESDAY","dayOfYear":197,"hour":20,"minute":38,"month":"JULY","monthValue":7,"nano":263000000,"year":2019,"second":12,"chronology":{"id":"ISO","calendarType":"iso8601"}}}
{startTime={dayOfMonth=15, dayOfWeek=MONDAY, dayOfYear=196, hour=20, minute=38, month=JULY, monthValue=7, nano=263000000, year=2019, second=12, chronology={id=ISO, calendarType=iso8601}}, endTime={dayOfMonth=16, dayOfWeek=TUESDAY, dayOfYear=197, hour=20, minute=38, month=JULY, monthValue=7, nano=263000000, year=2019, second=12, chronology={id=ISO, calendarType=iso8601}}, nodeId=null, fsId=null, memId=null, ifCardId=null}
ObjectMapper mapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
//https://github.com/networknt/light-4j/issues/82
mapper.registerModule(module);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//incase of empty/null String
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
Map<String,Object> filter = mapper.convertValue(this,Map.class);
System.out.printf("查询条件:%s\n", JSON.toJSONString(filter));
return filter;
查询条件:{"startTime":"2019-07-15T21:29:13.711","endTime":"2019-07-16T21:29:13.711"}
{startTime=2019-07-15T21:29:13.711, endTime=2019-07-16T21:29:13.711, nodeId=null, fsId=null, memId=null, ifCardId=null}
 /***
     * 查询文件系统使用率
     * @param condition
     * @return
     */
    LinkedList<SnmpFileSystemUsage> queryFileSystemUsage(Map<String,Object> condition);

    List<SnmpFileSystemUsage> fooBar()
    { 
       return snmpBaseMapper.queryFileSystemUsage(QueryConditionBuilder
                .newBuilder()
                .withNodeId(nodeId)
                .build()
                .toFilter());
    }