Java 通过Hessian与Spring远程处理一起传输时,BigDecimal值始终为零

Java 通过Hessian与Spring远程处理一起传输时,BigDecimal值始终为零,java,spring,hessian,spring-remoting,Java,Spring,Hessian,Spring Remoting,当我调用通过Spring的Hessian函数返回BigDecimal值的远程方法时,它总是返回零。 直接调用该方法或使用普通Hessian servlet(非Spring)正常工作 如何解决这个问题 服务器端(Tomcat7) web.xml: <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://ja

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

如何解决这个问题

服务器端(Tomcat7) 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>
客户端 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>
编辑:
使用的库是Spring 3.2和Hessian 4.0.7

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

我们这样修补了它,效果很好。不知道为什么它没有以这种方式实现


参见

我们这样解决了这个问题:

像@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的实现不同,它验证值是否不为null。有必要扩展AbstractStringValueDeserialize

}

序列化程序仅将BigDecimal转换为字符串表示形式:

公共类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和DateTime的组合问题,因此stacktraces和调试视图很奇怪。
因此,如果您使用“非标准”对象,请检查它们的序列化!

这似乎是一个已知的错误。有关详细信息和可能的解决方法,请参阅。

我们也遇到了同样的问题,发现maven central上分发的hessian jar缺少一些关键配置文件。如果您直接从jar下载jar,将包括:

  • META-INF/hessian/序列化程序
  • META-INF/hessian/反序列化程序
我们通过将这两个丢失的文件复制到项目的
src/main/resources
中解决了这个问题

好处:这个解决方案还纠正了我们在
java.util.Locale

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());
    }
}
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;
}
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;
    }
}
@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());
        }
    }
}
    SerializerFactory serializerFactory = newSerializerFactory();
    serializerFactory.addFactory(new BigDecimalSerializerFactory());