如何让Spring接受流利(非空洞)的seters?

我有一个API,我正在把它变成一个内部的DSL。因此,我的PoJos中的大多数方法都返回对此的引用,以便我可以以声明方式将方法链接在一起(语法糖)。

myComponent
    .setID("MyId")
    .setProperty("One")
    .setProperty2("Two")
    .setAssociation(anotherComponent)
    .execute();

我的API不依赖于Spring,但我希望通过PoJo友好化来使其“Spring友好”,参数构造器,getters和setters为零。问题是,当我有一个非空洞返回类型时,Spring似乎没有检测到我的setter方法。

在将我的命令链接在一起时,这种返回类型非常方便,因此我不想破坏我的编程API,只是为了与Spring注入兼容。

春季是否有允许我使用非空洞设置器的设置?

克里斯


答案 1

感谢所有人(特别是Espen,他付出了很多努力向我展示了春季的各种选择)。

最后,我自己找到了一个不需要Spring配置的解决方案。

我点击了Stephen C的链接,然后在那组线程中找到了对SimpleBeanInfo类的引用。该类允许用户编写自己的Bean方法解析代码,方法是将另一个类放在与具有非标准 setters/getters 的类相同的包中,以覆盖将“BeanInfo”附加到类名上的逻辑并实现“BeanInfo”接口。

然后我在谷歌上搜索了一下,找到了这个指出了方向的博客。博客上的解决方案非常基本,所以我为了我的目的而填充了它。

每班(流利的二传手)

public class MyComponentBeanInfo<T> extends SimpleBeanInfo {

private final static Class<?> _clazz = MyComponent.class;
PropertyDescriptor[] _properties = null;

public synchronized PropertyDescriptor[] getPropertyDescriptors() {
    if (_properties == null) {
        _properties = Helpers.getPropertyDescriptionsIncludingFluentSetters(_clazz);
    }
    return _properties;
}

public BeanDescriptor getBeanDescriptor() {
    return new BeanDescriptor(_clazz);
}
}

属性描述符生成方法

public static PropertyDescriptor[] getPropertyDescriptionsIncludingFluentSetters( Class<?> clazz) {
    Map<String,Method> getterMethodMap = new HashMap<String,Method>();
    Map<String,Method> setterMethodMap = new HashMap<String,Method>();
    Set<String> allProperties = new HashSet<String>();
    PropertyDescriptor[] properties = null;
    try {
        Method[] methods = clazz.getMethods();
        for (Method m : methods) {
            String name = m.getName();
            boolean isSetter = m.getParameterTypes().length == 1 && name.length() > 3 && name.substring(0,3).equals("set") && name.charAt(3) >= 'A' && name.charAt(3) <= 'Z';
            boolean isGetter = (!isSetter) && m.getParameterTypes().length == 0 && name.length() > 3 && name.substring(0,3).equals("get") && name.charAt(3) >= 'A' && name.charAt(3) <= 'Z';

            if (isSetter || isGetter) {
                name = name.substring(3);
                name = name.length() > 1
                        ? name.substring(0,1).toLowerCase() + name.substring(1)
                        : name.toLowerCase();

                if (isSetter) {
                    setterMethodMap.put(name, m);
                } else {
                    getterMethodMap.put(name, m);
                }
                allProperties.add(name);
            }
        }

        properties = new PropertyDescriptor[allProperties.size()];
        Iterator<String> iterator = allProperties.iterator();
        for (int i=0; i < allProperties.size(); i++) {
            String propertyName = iterator.next();
            Method readMethod = getterMethodMap.get(propertyName);
            Method writeMethod = setterMethodMap.get(propertyName);
            properties[i] = new PropertyDescriptor(propertyName, readMethod, writeMethod);
        }
    } catch (IntrospectionException e) {
        throw new RuntimeException(e.toString(), e);
    }
    return properties;
}

这种方法的优点:

  • 没有自定义弹簧配置(Spring不知道非标准设置器,并将其视为正常)。不依赖于任何Spring.jar文件,但可以从Spring访问。
  • 似乎只是工作。

这种方法的缺点:

  • 我必须为我的所有API类创建一个BeanInfo类,其中包含非标准设置器。幸运的是,只有大约10个这样的类,通过将方法解析逻辑移动到一个单独的类中,我只有一个地方可以维护。

结束语

在我看来,Spring应该天生地处理流利的二传手,他们不会伤害任何人,它应该忽略返回值。

通过要求 setter 严格无效,它迫使我编写比我需要的更多的样板代码。我很欣赏Bean规范,但是使用反射甚至不使用标准Bean解析器即可实现bean分辨率,因此Spring应该提供自己的Bean解析器选项来处理这种情况。

无论如何,将标准机制保留为默认机制,但提供单行配置选项。我期待着未来的版本,其中可能会有所选择的放松。


答案 2

春季是否有允许我使用非空洞设置器的设置?

简单的答案是否定的 - 没有这样的设置。

Spring被设计为与JavaBeans规范兼容,这需要setter返回。void

有关讨论,请参阅此春季论坛主题。论坛中提到的这种限制有一些可能的方法,但没有简单的解决方案,我认为没有人真正报告他们已经尝试过并且它有效。