代码之家  ›  专栏  ›  技术社区  ›  Sean Patrick Floyd

Java Builder生成器问题

  •  8
  • Sean Patrick Floyd  · 技术社区  · 14 年前

    在我的一个项目中,我有两个充满dto的包,pojo只有getter和setter。虽然它们是简单的JavaBean很重要(例如,因为ApacheCxf使用它们来创建Web服务XSD等),但是这样的程序也很糟糕,而且容易出错。

    Foo foo = new Foo();
    foo.setBar("baz");
    foo.setPhleem(123);
    return foo;
    

    我更喜欢流畅的接口和构建器对象,所以我使用maven/gmaven自动为dto创建构建器。所以对于上面的代码,a FooBuilder 是自动生成的,我可以这样使用:

    Foo foo = new FooBuilder()
               .bar("baz")
               .phleem(123)
               .build();
    

    我还为生成的构建器自动生成单元测试。单元测试将生成上述两个代码(构建器版本和非构建器版本),并断言这两个版本在 equals() hashcode() . 我可以实现这一点的方法是为每种属性类型创建一个具有默认值的全局可访问映射。像这样的:

    public final class Defaults{
        private Defaults(){}
        private static final Map<Class<?>, Object> DEFAULT_VALUES =
            new HashMap<Class<?>, Object>();
        static{
            DEFAULT_VALUES.put(String.class, "baz");
            // argh, autoboxing is necessary :-)
            DEFAULT_VALUES.put(int.class, 123);
            // etc. etc.
        }
        public static getPropertyValue(Class<?> type){
            return DEFAULT_VALUES.get(type);
        }
    }
    

    另一个重要的方面是pojo有时有集合成员。例如。:

    foo.setBings(List<Bing> bings)
    

    但在我的生成器中,我希望从这个例子中生成两个方法:set方法和add方法:

    fooBuilder.bings(List<Bing> bings); // set method
    fooBuilder.addBing(Bing bing); // add method
    

    我已经解决了这个问题,在 Foo

    @ComponentType(Bing.class)
    private List<Bing> bings;
    

    builder builder(sic)读取注释并使用该值作为要生成的方法的泛型类型。

    我们现在离这个问题越来越近了(对不起,简短不是我的优点之一:-)。

    我已经意识到这种构建方法可以在多个项目中使用,所以我正在考虑将其转换为maven插件。我非常清楚如何生成maven插件,所以这不是问题的一部分(也不是如何生成有效的Java源代码)。我的问题是:如何在不引入任何公共依赖项(在项目和插件之间)的情况下处理上述两个问题:

    <Question>

    1. 我需要一个默认类(或类似的机制)来获取生成的单元测试的默认值(这是概念的关键部分,如果没有完全测试,我不会信任自动生成的构建器)。请帮助我想出一个好的通用方法来解决这个问题,因为每个项目都有自己的域对象。

    2. 我需要一种将泛型类型通信到生成器的通用方法。我目前使用的基于注释的版本并不令人满意,因为project和plugin都需要知道同一个注释。

    </Question>

    有什么想法吗?

    顺便说一句:我知道使用构建器的真正关键是使对象不可变。我不能使我的对象不可变,因为标准的javabean是必要的,但是我使用AspectJ来强制在我的代码库中除了在构建器中之外的任何地方都不调用set方法或构造函数,因此出于实际目的,生成的对象是不可变的。

    另外,是的,我知道现有的生成器生成器IDE插件。这不符合我的目的,我想要一个自动化的解决方案,只要底层代码改变,它总是最新的。


    马特B要求一些关于我如何生成我的建设者的信息。我做的是:

    我每次读一节课,用 Introspector.getBeanInfo(clazz).getPropertyDescriptors() 获取属性描述符数组。我所有的建设者都有一个基类 AbstractBuilder<T> 哪里 T 会是 在上述情况下。这是 the code of the Abstract Builder class . 对于 PropertyDescriptor 数组,则生成具有属性名称的方法。这将是 FooBuilder.bar(String) :

    public FooBuilder bar(String bar){
        setProperty("bar", bar);
        return this;
    }
    

    这个 build() 方法 AbstractBuilder 实例化对象并分配其属性映射中的所有属性。

    2 回复  |  直到 14 年前
        1
  •  1
  •   eric    13 年前

    你看过吗 Diezel ? 它是一个建筑发电机。

    1. 它处理泛型类型,因此这里可能有助于回答问题2
    2. 它生成所有接口,并基于一个描述XML文件实现boiler plate。通过内省,您可能能够生成这个XML(甚至可以直接进入较低的API)
    3. 它作为maven插件捆绑在一起。
        2
  •  2
  •   Peter Lawrey    14 年前

    POJO是不遵循Java Bean spoec的对象。也就是说,它没有setter/getter。

    javabean不需要有setter,如果不想调用它们,就不要生成它们。(生成器可以调用包本地或私有构造函数来创建不可变对象)