JSON floats become BigDecimal using JCoachDB…


When converting  types from one representation into another we always know that there are some issues with serialization and deserialization. Of course with JSON is not different!

Type representation representation

Assumptions:

  1. We are using Java for interfacing with CouchDB
  2. We have chosen jcouchdb.
  3. jcouchdb uses svenson for converting from Java into JSON and viceversa.
  4. We have a CouchDB BaseDocument and we want to store an Integer, a Long, a Float and a Double.

Our code is something like:

// Create a document
BaseDocument doc1 = new BaseDocument();
doc1.setId("test_0001");
doc1.setProperty("Integer", new Integer(10));
doc1.setProperty("Long", new Long(10));
doc1.setProperty("Float", new Float(10));
doc1.setProperty("Double", new Double(10));

// Persist it into the database
db.createDocument(doc1);

Lets see what we get when we read that document from the database and print its values.

// Retrieve it
BaseDocument doc2 = db.getDocument(BaseDocument.class, doc1.getId());

// Print values
System.out.println("Values...");
System.out.println("Integer      " +
        doc1.getProperty("Integer") + " / " +
        doc2.getProperty("Integer"));
System.out.println("Long         " +
        doc1.getProperty("Long") + " / " +
        doc2.getProperty("Long"));
System.out.println("Float        " +
        doc1.getProperty("Float") + " / " +
        doc2.getProperty("Float"));
System.out.println("Double       " +
        doc1.getProperty("Double") + " / " +
        doc2.getProperty("Double"));

And the output is…

Values...
Integer      10 / 10
Long         10 / 10
Float        10.0 / 10.0
Double       10.0 / 10.0

Seems fine! But… what happens if we print the types of the arguments…

// Print types
System.out.println("Types...");
System.out.println("Integer      " +
        doc1.getProperty("Integer").getClass().getSimpleName() + " / " +
        doc2.getProperty("Integer").getClass().getSimpleName());
System.out.println("Long         " +
        doc1.getProperty("Long").getClass().getSimpleName() + " / " +
        doc2.getProperty("Long").getClass().getSimpleName());
System.out.println("Float        " +
        doc1.getProperty("Float").getClass().getSimpleName() + " / " +
        doc2.getProperty("Float").getClass().getSimpleName());
System.out.println("Double       " +
        doc1.getProperty("Double").getClass().getSimpleName() + " / " +
        doc2.getProperty("Double").getClass().getSimpleName());

Now we get as output…

Types...
Integer      Integer / Long
Long         Long / Long
Float        Float / BigDecimal
Double       Double / BigDecimal

We see that types have changed integer numbers are always Long while floating point numbers are BigDecimal.

Problems with conversion and precision

The question on this is problems with precision.
The following example creates a BaseDocument with an Integer, Long, Float and Double but now instead of 10 we have a value of 123.456.

// Create a document
BaseDocument doc1 = new BaseDocument();
doc1.setId("test_0002");
doc1.setProperty("Float", new Float(123.456));
doc1.setProperty("Double", new Double(123.456));

// Persist it into the database
db.createDocument(doc1);

// Retrieve it
BaseDocument doc2 = db.getDocument(BaseDocument.class, doc1.getId());

And when we print the value using:

// Print values
System.out.println("Values...");
System.out.println("Float        " +
        doc1.getProperty("Float") + " / " +
        doc2.getProperty("Float"));
System.out.println("Double       " +
        doc1.getProperty("Double") + " / " +
        doc2.getProperty("Double"));

we get:

Values...
Float        123.456 / 123.45600000000000307
Double       123.456 / 123.45600000000000307

It is not such a big difference but if you compare numbers, of course, they will not be the same…
And the problem is with the representation of 123.456 using the different data types.

System.out.println("Float      : " + new Float(123.456));
System.out.println("Double     : " + new Double(123.456));
System.out.println("BigDecimal : " + new BigDecimal(123.456));

shows

Float      : 123.456
Double     : 123.456
BigDecimal : 123.4560000000000030695446184836328029632568359375
Advertisements