XDMP-RANGEINDEX Error for decimal properties value saved via the Java API

Viewed 23

For each XML we store in MarkLogic we store calculated values in the document's associated properties. One of these values is a potentially large decimal value. Which is causing an exception because the Marklogic Java API is formatting the number in the XML it sends to the MarkLogic server in a way that the MarkLogic server doesn’t like.

We have a Range Element Index set up on a “TotalObligatedAmount” element that we store in the properties:

The Java code below reproduces the issues we are seeing:

import java.nio.charset.StandardCharsets;
 
import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
 
import com.marklogic.client.DatabaseClient;
import com.marklogic.client.document.XMLDocumentManager;
import com.marklogic.client.io.DOMHandle;
import com.marklogic.client.io.DocumentMetadataHandle;
 
@Component
public class LoadTester {
 
  private final XMLDocumentManager mgr;
  
  public LoadTester(DatabaseClient client) {
    this.mgr = client.newXMLDocumentManager();
  }
 
  public void loadTest() throws Exception {
    String uri = "testDocument.xml";
    DOMHandle handle = new DOMHandle();
    String xml = "<test><value>Hello World</value></test>";
    Document doc = handle.getFactory().newDocumentBuilder()
                   .parse(IOUtils.toInputStream(xml, StandardCharsets.UTF_8));
    DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
    metadataHandle.withProperty("TotalObligatedAmount",Double.valueOf(18912626.00));
    handle.set(doc);
    mgr.write(mgr.newDescriptor(uri), metadataHandle, handle);
  }
}

This results in the following Exception:

Exception in thread "main" com.marklogic.client.FailedRequestException: Local message: write failed: Bad Request. Server Message: XDMP-RANGEINDEX: Range index error: decimal xdmp:document-properties("testDocument.xml")/prop:properties/TotalObligatedAmount: XDMP-LEXVAL: Invalid lexical value "1.8912626E7"
    at com.marklogic.client.impl.OkHttpServices.putPostDocumentImpl(OkHttpServices.java:1697)
    at com.marklogic.client.impl.OkHttpServices.putDocument(OkHttpServices.java:1344)
    at com.marklogic.client.impl.DocumentManagerImpl.write(DocumentManagerImpl.java:940)
    at com.marklogic.client.impl.DocumentManagerImpl.write(DocumentManagerImpl.java:888)
    at com.marklogic.client.impl.DocumentManagerImpl.write(DocumentManagerImpl.java:827)

The properties data XML that the Java API is generating and sending to the server is:

<?xml version='1.0' encoding='utf-8'?>
<rapi:metadata xmlns:rapi="http://marklogic.com/rest-api"
    xmlns:prop="http://marklogic.com/xdmp/property"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <prop:properties>
        <TotalObligatedAmount xsi:type="xs:double">1.8912626E7</TotalObligatedAmount>
    </prop:properties>
</rapi:metadata> 

When serializing the properties to XML the decimal value of 18,912,626.00 is being turned into the string 1.8912626E7 and the MarkLogic server is rejecting that string.

I was able to step through the code to find out how the double gets converted to a string. The com.marklogic.client.impl.ValueConverter does the conversion and it uses the javax.xml.bind.DatatypeConverter.printDouble() method to convert the Double to the “1.8912626E7” String (ultimately using the String.valueOf(doubleValue) method.

Does anyone know how I can get around this? Is there a change I need to make on the server or a way to configure the Java API?

I'm using version 5.2.0 of the Java API and version 10.0-8.1 of the MarkLogic server.

1 Answers

It turns out if you add the property as a BigDecimal instead of a Double it gets serialized correctly.

Changing metadataHandle.withProperty("TotalObligatedAmount",Double.valueOf(18912626.00)); to metadataHandle.withProperty("TotalObligatedAmount",new BigDecimal(18912626.00)); was enough to make the code work.

Related