BigDecimal value is always zero when passed using Spring by deleting via Hessian

When I call a remote method that returns a BigDecimal value using the Spring Hessian function, it always returns zero. Calling a method directly or using a simple Hessian (not Spring) servlet works fine.

What can be done to fix this?

Server Side (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> 

Remoting-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> 

The class of service whose method I call:

 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; } } 

Client side

Spring configuration - 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> 

Testing the console application:

 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()); } } 

EDIT: Used Spring 3.2 and Hessian 4.0.7 Libraries

+6
source share
4 answers

You can use HessianServlet.setSerializerFactory () to set your own SerializerFactory and return com.caucho.hessian.io.BigDecimalDeserializer as a deserializer for BigDecimal.

We fixed it like this and it works. I do not know why this is not implemented in this way.

See 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

+4
source

This seems to be a known bug. See http://bugs.caucho.com/view.php?id=3920 for more details.

+2
source

We solved this problem as follows:

Like @keuleJ, we create our own SerializerFactory (see below), but we do not return com.caucho.hessian.io.BigDecimalDeserializer because it does not check for 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; } 

}

Then we defined our own deserializer. It differs from the implementation of com.couchos # s in one, checking to see if it is null. Need to extend 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; } } 

}

The serializer only passes the BigDecimal view to String:

Public class BigDecimalSerializer extends 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()); } } } 

}

This implementation works for us not only for BigDecimal, but also for joda DateTime.

To use this, you must add the Serializer Factory to

  SerializerFactory serializerFactory = newSerializerFactory(); serializerFactory.addFactory(new BigDecimalSerializerFactory()); 

You must do this both on the server side and on the client side!

HINT! In our case, we had a difficult problem with BigDecimal and DateTime. So stacktraces and debugging views were weird. Therefore, if you use "non-standard" objects, check them to serialize them!

+1
source

We had the same problem, and it turned out that in the hessian jar, distributed in the center of maven, some key configuration files were missing. If you download the bank directly from http://hessian.caucho.com/ , then the bank will have:

  • META-INF / burlap / serializers
  • META-INF / Hesse / deserializers

We solved the problem by copying these two missing files into our src/main/resources project.

Bonus: this solution also fixed the problem that we encountered serializing hessian java.util.Locale

0
source

Source: https://habr.com/ru/post/919253/


All Articles