Apache Axiom 1.2.11 Release Note

Axiom 1.2.11 is a maintenance release to support the upcoming Axis2 1.6 release. It also introduces a couple of new APIs that make it easier to support alternative Axiom implementations and that eliminate the need to refer to internal Axiom APIs.

Resolved JIRA issues:

  • [AXIOM-12] - OMOutputFormat: doSWA and doOptimize should be mutually exclusive…plus we need doOptimizeThreshold
  • [AXIOM-24] - OMDocument#serializeAndConsume doesn’t consume the document
  • [AXIOM-172] - OMChildrenQNameIterator doesn’t work correctly if hasNext() is not called before next()
  • [AXIOM-274] - Refactor/deprecate MIMEOutputUtils
  • [AXIOM-275] - Implement non JavaMail implementation of MultipartWriter
  • [AXIOM-313] - Add a new getDocumentElement method to StAXOMBuilder that allows to discard the OMDocument
  • [AXIOM-333] - getFirstChildWithName should not read the next element.
  • [AXIOM-346] - Enhance OMStAXWrapper/OMNavigator to work with OMDocument objects
  • [AXIOM-351] - Links in Javadoc JARs are broken
  • [AXIOM-352] - StAXDialectDetector doesn’t recognize com.bea.core.weblogic.stax_1.7.0.0.jar

Changes in this release

Resurrection of the OMXMLBuilderFactory API

Historically, org.apache.axiom.om.impl.llom.factory.OMXMLBuilderFactory was used to create Axiom trees from XML documents. Unfortunately, this class is located in the wrong package and JAR (it is implementation independent but belongs to LLOM). In Axiom 1.2.10, the standard way to create an Axiom tree was therefore to instantiate StAXOMBuilder or one of its subclasses directly. However, this is not optimal for two reasons:

  • It relies on the assumption that every implementation of the Axiom API necessarily uses StAXOMBuilder. This means that an implementation doesn’t have the freedom to provide its own builder implementation (e.g. in order to implement some special optimizations).

  • StAXOMBuilder and its subclasses belong to packages which have impl in their names. This tends to blur the distinction between the public API and internal implementation classes.

Therefore, in Axiom 1.2.11, a new abstract API for creating builder instances was introduced. It is again called OMXMLBuilderFactory, but located in the org.apache.axiom.om package. The methods defined by this new API are similar to the ones in the original (now deprecated) OMXMLBuilderFactory, so that migration should be easy.

Changes in the behavior of certain iterators

In Axiom 1.2.10 and previous versions, iterators returned by methods such as OMIterator#getChildren() internally stayed one step ahead of the node returned by the next() method. This meant that sometimes, using such an iterator had the side effect of building elements that were not intended to be built. In Axiom 1.2.11 this behavior was changed such that next() no longer builds the nodes it returns. In a few cases, this change may cause issues in existing code. One known instance is the following construct (which was used internally by Axiom itself):

while (children.hasNext()) { 
    OMNodeEx omNode = (OMNodeEx) children.next(); 
    omNode.internalSerializeAndConsume(writer); 
}

One would expect that the effect of this code is to consume the child nodes. However, in Axiom 1.2.10 this is not the case because next() actually builds the node. Note that the code actually doesn’t make sense because once a child node has been consumed, it is no longer possible to retrieve the next sibling. Since in Axiom 1.2.11 the call to next() no longer builds the child node, this code will indeed trigger an exception.

Another example is the following piece of code which removes all child elements with a given name:

Iterator iterator = element.getChildrenWithName(qname);
while (iterator.hasNext()) {
    OMElement child = (OMElement)iterator.next();
    child.detach();
}

In Axiom 1.2.10 this works as expected. Indeed, since the iterator stays one node ahead, the current node can be safely removed using the detach() method. In Axiom 1.2.11, this is no longer the case and the following code (which also works with previous versions) should be used instead:

Iterator iterator = element.getChildrenWithName(qname);
while (iterator.hasNext()) {
    iterator.next();
    iterator.remove();
}

Note that this is actually compatible with the behavior of the Java 2 collection framework, where a ConcurrentModificationException may be thrown if a thread modifies a collection directly while it is iterating over the collection with an iterator.

In Axiom 1.2.12, the iterator implementations have been further improved to detect this situation and to throw a ConcurrentModificationException. This enables early detection of problematic usages of iterators.