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:
- We are using Java for interfacing with CouchDB
- We have chosen jcouchdb.
- jcouchdb uses svenson for converting from Java into JSON and viceversa.
- 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