1

I have a array of objects from which I am constructing an xml document using java like below -

Object[] arr = fetchData();
Document newDoc =DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element rootElement = newDoc.createElement("company");
for(int i=0;i<arr.length();i++)
{
    Element staff = new Element("staff");
    staff.setAttribute(new Attribute("id", i));
    staff.addContent(new Element("firstname").setText(arr[i].getFirstName()));
    staff.addContent(new Element("lastname").setText(arr[i].getLastName()));
    staff.addContent(new Element("nickname").setText(arr[i].getNickName()));
    staff.addContent(new Element("salary").setText(arr[i].getSalary()));
    ............
    ............
    ............
    ............
    ............
    rootElement.appendChild(staff);
}
newDoc.appendChild(rootElement);

The xml generated will be of following form -

<company>
  <staff id="1">
    <firstname>Foo</firstname>
    <lastname>Bar</lastname>
    <nickname>FB</nickname>
    <salary>999999</salary>
............
............
............
............
  </staff>
  ......
  ......
</company>

Above solution is working fine for small size of arrays but when array size increases it takes long time to process because of sequential processing of above code. Is there any way to process construction of staff element parallel either by using java 8 Stream parallel processing or threads in java?

Updated solution using CompletableFuture :

Object[] arr = fetchData();
Document newDoc =DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element rootElement = newDoc.createElement("company");
List<CompletableFuture<Element>> futureElements = new ArrayList<>();
for (int x = 0; x < arr.length(); x++) {
    Object e = arr[x];
    CompletableFuture<Element> f = CompletableFuture.supplyAsync(() -> getElement(newDoc, e));
    futureElements.add(f);
}

for (CompletableFuture<Element> e : futureElements)
        rootElement.appendChild(e.get());

newDoc.appendChild(rootElement); 
4
  • 2
    If you creating elements via new Element, you are not using the standard DOM API. We can’t guess the thread safety of an unspecified non-standard library. Commented Apr 5, 2017 at 12:14
  • Thank you for the quick response, I have updated my code. Commented Apr 5, 2017 at 12:32
  • The simplest with threads would be to have an object encapsulating the name, nickname, salary (and so on), put each of these elements in a concurrent collection, and have several threads polling the concurrent collection until it's empty, creating the necessary elements, then applying all that to create the tree (you might need to add synchronization or post treatment if elements should be ordered by id). Now perhaps if you show which libraries you use for creating the XML tree, it might help provide a concrete implementation Commented Apr 5, 2017 at 12:57
  • 1
    Since DocumentBuilderFactory.newInstance() might return an arbitrary DocumentBuilder implementation, there is no guaranty that it will be thread safe and even worse, the fact, that nodes are created through the Document interface and keep being associated with a document, invites the implementors to maintain hidden data structures combining these artifacts, which are unlikely to be thread safe. If performance is a concern, you should ask yourself whether you really need a DocumentBuilder or if a lightweight code assembling an XML String would work as well. The latter can be parallel… Commented Apr 5, 2017 at 16:38

1 Answer 1

3

What you could use is CompletableFutures

This way you could generate all the "staff" elements in a new thread then wait for them all to complete and add them

List<CompletableFuture<Element>> futureElements = new ArrayList<>()
for(int x = 0; x < arr.length; x++){
     //getElement(arr[x]) is the get staff element logic
     CompletableFuture<Element> f = CompletableFuture.supplyAsync(() -> getElement(arr[x]))
     futureElements.add(f);
}

CompletableFuture<Void> allOf = CompletableFuture.allOf(futureElements.toArray(new CompletableFuture[0]))

Now you can either modify the allOf CompletableFuture or you can use things like thenAccept() to create a new thread that will start as soon as all others complete, or do a .get() to join back to the main thread.

if you do a .get() then you can do something like

futureElements.forEach(f -> rootElement.append(f.get()));
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the above solution, I modified my code to use above logic but I don't see any performance improvement rather it is degraded for large set of data, updated the question with my solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.