6

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

可以做些什么来解决这个问题?

服务器端(Tomcat 7)

网页.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

4 回答 4

4

您可以使用 HessianServlet.setSerializerFactory() 设置您自己的 SerializerFactory 并返回 com.caucho.hessian.io.BigDecimalDeserializer 作为 BigDecimal 的 Deserializer。

我们像这样对其进行了修补,并且可以正常工作。不知道为什么不以这种方式实施。

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=好的

于 2012-08-10T14:39:37.720 回答
2

这似乎是一个已知的错误。有关详细信息和可能的解决方法,请参阅http://bugs.caucho.com/view.php?id=3920

于 2013-01-11T09:08:45.473 回答
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;
}

}

然后我们定义了自己的 Deserializer。它与 com.couchos#s 的实现不同,它通过验证值是否不为空来实现。有必要扩展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());

您必须在服务器端和客户端都这样做!

暗示! 在我们的例子中,我们遇到了 BigDecimal 和 DateTime 的综合问题。因此堆栈跟踪和调试视图很奇怪。因此,如果您使用“非标准”对象,请检查它们的序列化!

于 2012-08-17T06:03:31.353 回答
-1

我们遇到了同样的问题,发现分布在 maven Central 上的 hessian jar 缺少一些关键配置文件。如果您直接从http://hessian.caucho.com/下载该 jar,该 jar 将包括:

  • META-INF/hessian/序列化器
  • META-INF/hessian/反序列化器

我们通过将这两个丢失的文件复制到我们项目的src/main/resources.

奖励:此解决方案还纠正了我们在 hessian 序列化时遇到的问题java.util.Locale

于 2017-01-25T20:30:43.037 回答