通过Hessian使用Spring远程传输时,BigDecimal值始终为零

时间:2012-06-28 14:48:52

标签: java spring hessian spring-remoting

当我通过Spring的Hessian函数调用返回BigDecimal值的远程方法时,它总是返回零。 直接调用方法或使用普通的Hessian servlet(非Spring)正常工作。

可以采取哪些措施来解决这个问题?

服务器端(Tomcat 7)

的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

4 个答案:

答案 0 :(得分:4)

您可以使用HessianServlet.setSerializerFactory()来设置您自己的SerializerFactory并将com.caucho.hessian.io.BigDecimalDeserializer作为BigDecimal的反序列化器返回。

我们像这样修补它并且它有效。不知道为什么没有这样实现。

请参阅http://www.jarvana.com/jarvana/view/com/caucho/hessian/4.0.7/hessian-4.0.7-src.jar!/com/caucho/hessian/server/HessianServlet.java?format=ok

答案 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将包括:

  • META-INF /粗麻/串行化器
  • META-INF /粗麻器/解串

我们通过将这两个丢失的文件复制到我们的项目src/main/resources中来解决了这个问题。

奖励:此解决方案还纠正了我们对java.util.Locale

的粗体序列化所遇到的问题