当我通过Spring的Hessian函数调用返回BigDecimal值的远程方法时,它总是返回零。 直接调用方法或使用普通的Hessian servlet(非Spring)正常工作。
可以采取哪些措施来解决这个问题?
的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<servlet>
<servlet-name>remoting</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>remoting</servlet-name>
<url-pattern>/remoting/*</url-pattern>
</servlet-mapping>
</web-app>
远程-servlet.xml中:
<beans>
<context:annotation-config />
<context:component-scan base-package="hr.spi.logic.lcspi" />
<tx:annotation-driven proxy-target-class="true" />
<bean name="/lcspi/lc302/poslovi" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="posloviLogic" />
<property name="serviceInterface" value="hr.spi.logic.lcspi.lc302.PosloviLogicInterface" />
</bean>
</beans>
我调用其方法的服务类:
package hr.spi.logic.lcspi.lc302;
@Transactional
@Repository
public class PosloviLogic implements PosloviLogicInterface {
@Override
public BigDecimal test()
{
BigDecimal bd = new BigDecimal("2.2");
return bd;
}
}
Spring配置 - applicationContextHessian.xml:
<beans>
<bean id="posloviLogic" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="http://localhost:8080/SpringWebTest/remoting/lcspi/lc302/poslovi" />
<property name="serviceInterface" value="hr.spi.logic.lcspi.lc302.PosloviLogicInterface" />
</bean>
</beans>
控制台应用程序测试:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextHessian.xml");
try {
PosloviLogicInterface posloviLogic = (PosloviLogicInterface) context.getBean("posloviLogic");
BigDecimal bd = posloviLogic.test();
System.out.println(bd); // This returns 0.00
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
编辑: 使用的库是Spring 3.2和Hessian 4.0.7
答案 0 :(得分:4)
您可以使用HessianServlet.setSerializerFactory()来设置您自己的SerializerFactory并将com.caucho.hessian.io.BigDecimalDeserializer作为BigDecimal的反序列化器返回。
我们像这样修补它并且它有效。不知道为什么没有这样实现。
答案 1 :(得分:2)
我们解决了这个问题:
与@keuleJ一样,我们构建了自己的SerializerFactory(见下文),但我们不返回com.caucho.hessian.io.BigDecimalDeserializer,因为它没有检查null。
public class BigDecimalSerializerFactory extends AbstractSerializerFactory {
private BigDecimalSerializer bigDecimalSerializer = new BigDecimalSerializer();
private BigDecimalDeserializer bigDecimalDeserializer = new BigDecimalDeserializer();
@Override
public Serializer getSerializer(Class cl) throws HessianProtocolException {
if (BigDecimal.class.isAssignableFrom(cl)) {
return bigDecimalSerializer;
}
return null;
}
@Override
public Deserializer getDeserializer(Class cl) throws HessianProtocolException {
if (BigDecimal.class.isAssignableFrom(cl)) {
return bigDecimalDeserializer;
}
return null;
}
}
然后我们定义了自己的反序列化器。它与com.couchos#s的实现不同,它通过验证value是否为null。有必要扩展 AbstractStringValueDeserialize !
public class BigDecimalDeserializer extends AbstractStringValueDeserializer {
@Override
public Class getType() {
return BigDecimal.class;
}
@Override
protected Object create(String value) {
if (null != value) {
return new BigDecimal(value);
} else {
return null;
}
}
}
Serializer仅将BigDecimal传递给String表示:
公共类BigDecimalSerializer扩展了AbstractSerializer {
@Override
public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
if (obj == null)
out.writeNull();
else {
Class cl = obj.getClass();
if (out.addRef(obj))
return;
int ref = out.writeObjectBegin(cl.getName());
BigDecimal bi = (BigDecimal) obj;
if (ref < -1) {
out.writeString("value");
out.writeString(bi.toString());
out.writeMapEnd();
} else {
if (ref == -1) {
out.writeInt(1);
out.writeString("value");
out.writeObjectBegin(cl.getName());
}
out.writeString(bi.toString());
}
}
}
}
此实现适用于我们,不仅适用于BigDecimal,也适用于joda DateTime。
要使用此功能,您必须将Serializer Factory添加到
SerializerFactory serializerFactory = newSerializerFactory();
serializerFactory.addFactory(new BigDecimalSerializerFactory());
您必须在服务器端和客户端都这样做!
<强> HINT!强> 在我们的例子中,我们遇到了BigDecimal和DateTime的组合问题。因此,堆栈跟踪和调试视图很奇怪。 因此,如果您使用“非标准”对象,请检查它们的序列化!
答案 2 :(得分:2)
这似乎是一个已知的错误。有关详细信息和可能的解决方法,请参阅http://bugs.caucho.com/view.php?id=3920。
答案 3 :(得分:0)
我们遇到了同样的问题,发现在maven中心分发的粗麻布jar缺少一些关键的配置文件。如果直接从http://hessian.caucho.com/下载jar,jar将包括:
我们通过将这两个丢失的文件复制到我们的项目src/main/resources
中来解决了这个问题。
奖励:此解决方案还纠正了我们对java.util.Locale