返回的对象转化成map_将对象转换为Map并返回

在大型企业应用中,经常需要将数据对象与Map互相转换。本文探讨了如何将对象转换为Map,包括使用反射和自定义方法的两种方式,并介绍了Java :: Geci这个代码生成工具,它能自动生成将对象转为Map的代码,提高开发效率。
摘要由CSDN通过智能技术生成
返回的对象转化成map

返回的对象转化成map

在大型企业应用程序中,有时我们需要将数据对象与Map相互转换。 通常,这是特殊序列化的中间步骤。 如果可以使用某种标准,则最好使用该标准,但是很多时候,一些首席架构师所构想的架构,严格的环境或某些类似的原因都无法使用JOOQ,Hibernate,Jackson,JAX或其他某种方式像那样。 在这种情况下,就像几年前我想到的那样,我们必须将对象转换为字符串或二进制的某种专有格式,朝该方向迈出的第一步是将对象转换为Map

最终,转换不仅仅是简单的

Map myMap =  (Map)myObject;

因为这些对象几乎从来都不是自己的地图。 转换中真正需要的是具有一个Map ,其中每个条目都对应于“ MyObject”类中的一个字段。 条目中的关键字是字段的名称,值是可能转换为Map本身的字段的实际值。

一种解决方案是使用反射并以反射方式读取对象的字段并从中创建地图。 另一种方法是在需要转换为Map的类中创建toMap()方法,该方法只需使用字段名称将每个字段简单地添加到返回的Map中即可。 这比基于反射的解决方案要快一些,并且代码要简单得多。

几年前,当我在一个实际的应用程序中遇到这个问题时,我为每个数据对象编写原始但众多的toMap()方法感到沮丧,以至于我创建了一个简单的基于反射的工具,该工具可以针对我们想要的任何类进行操作。 它解决了问题吗? 没有。

这是一个专业的环境,不仅功能很重要,而且代码的质量和我的程序员的判断所得出的我的代码的质量都不匹配。 他们认为基于反射的解决方案很复杂,如果它成为代码库的一部分,那么后来加入普通开发人员将无法维护它。 好吧,我不得不承认它们是正确的。 在不同的情况下,我会说开发人员必须在代码所需的水平上学习Java的反射和编程。 但是,在这种情况下,我们并不是在谈论某个特定的人,而是在将来某个人加入并加入团队,可能是在我们已经离开该项目的某个时候。 假定此人是普通开发人员,这似乎很合理,因为我们对该人一无所知。 从这个意义上讲,代码的质量不好,因为它太复杂了。 开发人员团队的法定人数决定,维护许多手动制作的toMap()方法比将来寻找高级和有经验的开发人员要便宜。

老实说,我有点不愿意接受他们的决定,但是即使我仅根据我在团队中的位置就可以推翻它,我还是接受了它。 即使我不同意,但我倾向于接受团队的决定,但前提是我可以接受这些决定。 如果一项决定是危险的,可怕的并且威胁到项目的未来,那么我们必须继续讨论细节,直到达成协议。

几年后,我开始创建Java :: Geci作为副项目,可以从http://github.com/verhas/javageci下载

Java :: Geci是在Java开发生命周期的测试阶段运行的代码生成工具。 Java :: Geci中的代码生成是一个“测试”。 它运行代码生成,并且如果所有生成的代码都保留下来,则测试成功。 如果代码库中的任何内容发生了更改,导致代码生成器生成的代码与以前不同,因此源代码发生了更改,则测试将失败。 如果测试失败,则必须修复错误并运行构建,包括再次进行测试。 在这种情况下,测试将生成新的,现已固定的代码,因此您所要做的只是再次运行构建。

在开发框架时,我创建了一些简单的生成器来生成equals()hashCode() ,设置器和获取器,委托生成器,最后我无法抗拒,但我创建了一个通用的toMap()生成器。 该生成器生成的代码将对象转换为Map ,就像我们之前讨论的一样,还有我之前未提到的fromMap() ,但显然也需要。

Java :: Geci生成器是实现Generator接口的类。 Mapper生成器可以扩展抽象类AbstractJavaGenerator 。 这使生成器可以抛出任何异常,从而简化了生成器开发人员的工作,并且它已经在查找Java类,该Java类是从当前处理的源生成的。 生成器可以通过参数klass来访问实际的Class对象,同时可以通过参数source来访问源代码, source代表源代码并提供创建要插入其中的Java代码的方法。

第三个global参数类似于保存源代码注释@Geci定义的配置参数的映射。

package javax0.geci.mapper;

import ...

public class Mapper extends AbstractJavaGenerator {

...

    @Override
    public void process(Source source, Class<?> klass, CompoundParams global)
                                                             throws Exception {
        final var gid = global.get("id");
        var segment = source.open(gid);
        generateToMap(source, klass, global);
        generateFromMap(source, klass, global);

        final var factory = global.get("factory", "new {{class}}()");
        final var placeHolders = Map.of(
                "mnemonic", mnemonic(),
                "generatedBy", generatedAnnotation.getCanonicalName(),
                "class", klass.getSimpleName(),
                "factory", factory,
                "Map", "java.util.Map",
                "HashMap", "java.util.HashMap"
        );
        final var rawContent = segment.getContent();
        try {
            segment.setContent(Format.format(rawContent, placeHolders));
        } catch (BadSyntax badSyntax) {
            throw new IOException(badSyntax);
        }
    }

生成器本身仅调用这两个方法generateToMap()generateFromMap() ,这两个方法generateToMap() ,正如名称暗示将toMap()fromMap()方法引入类中。

两种方法都使用Segment类提供的源生成支持,还使用Jamal提供的模板。 还需要注意的是,这些字段是通过调用反射工具方法getAllFieldsSorted()收集的,该方法返回该类具有确定顺序的所有字段,而不依赖于实际的JVM供应商或版本。

private void generateToMap(Source source, Class<?> klass, CompoundParams global) throws Exception {
        final var fields = GeciReflectionTools.getAllFieldsSorted(klass);
        final var gid = global.get("id");
        var segment = source.open(gid);
        segment.write_r(getResourceString("tomap.jam"));
        for (final var field : fields) {
            final var local = GeciReflectionTools.getParameters(field, mnemonic());
            final var params = new CompoundParams(local, global);
            final var filter = params.get("filter", DEFAULTS);
            if (Selector.compile(filter).match(field)) {
                final var name = field.getName();
                if (hasToMap(field.getType())) {
                    segment.write("map.put(\"%s\", %s == null ? null : %s.toMap0(cache));", field2MapKey(name), name, name);
                } else {
                    segment.write("map.put(\"%s\",%s);", field2MapKey(name), name);
                }
            }
        }
        segment.write("return map;")
                ._l("}\n\n");
    }

该代码仅选择由filter表达式表示的字段。

翻译自: https://www.javacodegeeks.com/2019/06/converting-objects-map-back.html

返回的对象转化成map

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值