我有一个AbstractSingleBeanDeFinitionParser的自定义实现,允许我在我的spring配置中定义3D向量,其中包含的项目比其他方式要少.
<rbf:vector3d id="test_vector" delimeter=";" value="45;46;47"/>
这很好用,我已经使用它几个月没有任何问题.昨天我试图在.properties文件中定义这样的值:
在test.properties我有:
vector3d.value=1,2,3
<context:property-placeholder location="test.properties"/>
<rbf:vector3d id="test_vector_with_properties" delimeter="," value="${vector3d.value}"/>
当我尝试运行我的单元测试时,它崩溃了,我得到了这个异常:
Caused by: java.lang.NumberFormatException: For input string: "${vector3d.value}"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1222)
at java.lang.Double.parseDouble(Double.java:510)
at scala.collection.immutable.StringLike$class.todouble(StringLike.scala:234)
at scala.collection.immutable.StringOps.todouble(StringOps.scala:31)
at rb.foundation.spring.xml.Vector3DBeanDeFinitionParser$$anonfun$1.apply(Vector3DBeanDeFinitionParser.scala:25)
当我将.properties文件用于普通bean时,它工作得很好,这使我相信在我的解析器实现中我忽略了一些微妙之处.它是用scala编写的,但你应该能够遵循它:
class Vector3DBeanDeFinitionParser extends AbstractSingleBeanDeFinitionParser
{
override def getBeanClass(element : Element) = classOf[Vector3D]
override def doParse(element: Element, builder: BeanDeFinitionBuilder)
{
val delim = element.getAttribute("delimeter")
val value = element.getAttribute("value")
val values = value.split(delim).map(_.todouble)
builder.addConstructorArgValue(values(0))
builder.addConstructorArgValue(values(1))
builder.addConstructorArgValue(values(2))
}
}
如果有必要,我很乐意添加密钥替换,我只需要知道在哪里/如何做.
想法?
解决方法:
所以这不起作用的原因是你的BeanDeFinitionParser在解析属性占位符之前运行很多.我理解的简单概述:
> BeanDeFinitionParsers将XML解析为内存中的BeanDeFinition对象
>然后将BeanDeFinitions加载到beanfactory中
> beanfactoryPostProcessors(包括属性占位符配置程序)在bean定义上执行
> bean是从bean定义创建的
(当然其他事情也会发生,但这些都是相关的步骤.)
因此,为了将已解析的属性值放入Vector3D对象中,我认为在beanfactoryPostProcessors运行之前,您将不得不延迟指定Vector3D构造函数的参数.我遇到的一种方法是让你的BeanDeFinitionParser为Spring factorybean而不是Vector3D本身构造一个bean定义.然后,您在Vector3DBeanDeFinitionParser中当前具有的矢量值的拆分需要在factorybean实现中.
对不起,我对Scala不太熟悉所以这将是Java.
factorybean类看起来像这样:
import org.springframework.beans.factory.factorybean;
public class Vector3Dfactorybean implements factorybean<Vector3D> {
private String delimiter;
private String value;
private transient Vector3D instance;
public String getDelimiter() { return delimiter; }
public void setDelimiter(String delimiter) { this.delimiter = delimiter; }
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
@Override
public Vector3D getobject() {
if (instance == null) {
String[] values = value.split(delimiter);
instance = new Vector3D(
Double.parseDouble(values[0]),
Double.parseDouble(values[1]),
Double.parseDouble(values[2])
);
}
return instance;
}
@Override
public Class<?> getobjectType() {
return Vector3D.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
然后你的Vector3DBeanDeFinitionParser只会将分隔符和值不变地传递给Vector3Dfactorybean bean定义:
class Vector3DBeanDeFinitionParser extends AbstractSingleBeanDeFinitionParser
{
override def getBeanClass(element : Element) = classOf[Vector3Dfactorybean]
override def doParse(element: Element, builder: BeanDeFinitionBuilder)
{
val delim = element.getAttribute("delimeter")
val value = element.getAttribute("value")
builder.addPropertyValue("delimiter", delim)
builder.addPropertyValue("value", value)
}
}
然后,当占位符属性configurer运行时,它应该解析Vector3Dfactorybean bean定义中的属性值.当最终从bean定义创建bean时,Vector3Dfactorybean将解析向量值并创建Vector3D对象.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。