Chr*_*ris 14 java reflection spring fluent-interface introspection
我有一个API,我正在变成一个内部DSL.因此,我的PoJos中的大多数方法返回对此的引用,以便我可以声明性地将方法链接在一起(语法糖).
myComponent
.setID("MyId")
.setProperty("One")
.setProperty2("Two")
.setAssociation(anotherComponent)
.execute();
Run Code Online (Sandbox Code Playgroud)
我的API不依赖于Spring,但我希望通过PoJo友好,零参数构造函数,getter和setter使其成为"Spring-Friendly".问题是,当我有一个非void返回类型时,Spring似乎没有检测到我的setter方法.
在将命令链接在一起时,返回类型非常方便,所以我不想破坏我的编程API,只是为了兼容Spring注入.
Spring中有一个设置允许我使用非void setter吗?
克里斯
Spring中有一个设置允许我使用非void setter吗?
简单的答案是否 - 没有这样的设置.
Spring旨在与JavaBeans规范兼容,并且需要setter返回void.
有关讨论,请参阅此Spring论坛主题.有可能解决这个限制在论坛中提到,但没有简单的解决方案,我认为没有人真正报告他们已经尝试过这个并且它有效.
感谢所有人(特别是Espen,他花了很多精力向我展示Spring中的各种选项).
最后,我找到了一个不需要Spring配置的解决方案.
我按照Stephen C的链接,然后在该组Threads中找到了对SimpleBeanInfo类的引用.此类允许用户通过将另一个类放在与具有非标准setter/getters的类相同的包中来编写自己的bean方法解析代码,以覆盖附加到类名并将'BeanInfo'附加到类名并实现'BeanInfo的逻辑'界面.
然后我在Google上搜索了一下,发现这个博客指明了方向.博客上的解决方案非常基础,所以我为了我的目的填写了它.
每班(有流利的设定者)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
PropertyDescriptor生成方法
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;
}
Run Code Online (Sandbox Code Playgroud)
这种方法的优点:
这种方法的缺点:
闭幕思考
在我看来,Spring应该本地处理流利的setter,它们不会伤害任何人,它应该忽略返回值.
通过要求定位器严格无效,它迫使我编写了比我本来需要的更多的锅炉板代码.我很欣赏Bean规范,但是即使没有使用标准的bean解析器,bean的解析也很简单,所以Spring应该提供自己的bean解析器选项来处理这种情况.
无论如何,请将标准机制保留为默认值,但提供单行配置选项.我期待未来的版本可以选择放宽.
Spring也可以配置Java配置.
一个例子:
@Configuration
public class Config {
@Bean
public MyComponent myComponent() {
return MyComponent
.setID(id)
.setProperty("One", "1")
.setProperty("Two", "2")
.setAssociation(anotherConfig.anotherComponent())
.execute();
}
@Autowired
private AnotherConfig anotherConfig;
@Value("${id}")
private String id;
}
Run Code Online (Sandbox Code Playgroud)
你有一个很好的不可变对象.您实际上已经实现了Builder模式!
更新以回应Chris的评论:
我想这不完全是你想要的,但使用属性文件解决了一些问题.请参阅上面示例中的id字段.
否则,您可以使用Spring的FactoryBean模式:
public class MyComponentFactory implements FactoryBean<MyComponent> {
private MyComponent myComponent;
public MyComponentFactory(String id, Property propertyOne, ..) {
myComponent = MyComponent
.setID(id)
.setProperty("One", "1")
.set(..)
.execute();
}
public MyComponent getObject() throws Exception {
return myComponent;
}
public Class<MyComponent> getObjectType() {
return MyComponent.class;
}
public boolean isSingleton() {
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
使用FactoryBean,可以保护配置与从getObject()方法返回的对象.
在XML配置中,您可以配置FactoryBean实现.在这种情况下与<constructor-arg />元素.
| 归档时间: |
|
| 查看次数: |
5720 次 |
| 最近记录: |