[jdom-interest] Bug in Document(List) -> setMixedContent()

philip.nelson at omniresources.com philip.nelson at omniresources.com
Mon Jun 25 20:09:43 PDT 2001


Here is a patch to Document that fixes a problem similar to one reported
earlier today with Element.  
This really can't work unless the document already existed.  oldRoot is null
on a new document which causes NPE's so this patch allows you to create a
new document from a starter List.

********** marks the changed areas

    public Document setMixedContent(List mixedContent) {

        if (mixedContent == null) {
            return this;
        }

        // Save original content and create a new list
        Element oldRoot = getRootElement();
        List oldContent = content;
        content = new ArrayList(INITIAL_ARRAY_SIZE);

        RuntimeException ex = null;
        boolean didRoot = false;
        int itemsAdded = 0;

        try {
            for (Iterator i = mixedContent.iterator(); i.hasNext(); ) {
                Object obj = i.next();
                if (obj instanceof Element) {
                    if (didRoot == false) {
                        setRootElement((Element)obj);
                        // Manually remove old root's doc ref, because
                        // setRootElement() can't see the old content list
to
                        // do it for us
                        if (oldRoot != null) //****************
                        	oldRoot.setDocument(null);
                        didRoot = true;
                    }
                    else {
                        throw new IllegalAddException(
                          "A Document may contain only one root element");
                    }
                }
                else if (obj instanceof Comment) {
                    addContent((Comment)obj);
                }
                else if (obj instanceof ProcessingInstruction) {
                    addContent((ProcessingInstruction)obj);
                }
                else {
                    throw new IllegalAddException(
                      "A Document may directly contain only objects of type
" +
                      "Element, Comment, and ProcessingInstruction: " +
                      (obj == null ? "null" : obj.getClass().getName()) + 
                      " is not allowed");
                }
                itemsAdded++;
            }
    
            // Make sure they set a root element
            if (didRoot == false) {
                throw new IllegalAddException(
                    "A Document must contain a root element");
            }
        }
        catch (RuntimeException e) {
            ex = e;
        }
        finally {
            if (ex != null) {
                // Restore the original state and parentage and throw
                if (oldRoot != null) { //*******************
	                content = oldContent;
	                oldRoot.setDocument(this);
	                // Unmodify all modified elements.  DO NOT change
any later
	                // elements tho because they may already have
parents!
	                Iterator itr = mixedContent.iterator();
	                while (itemsAdded-- > 0) {
	                    Object obj = itr.next();
	                    if (obj instanceof Element) {
	                        ((Element)obj).setDocument(null);
	                    }
	                    else if (obj instanceof Comment) {
	                        ((Comment)obj).setDocument(null);
	                    }
	                    else if (obj instanceof ProcessingInstruction) {
	
((ProcessingInstruction)obj).setDocument(null);
	                    }
	                }
	                
                }
                throw ex;
            }
        }
snip

I also patched Document(List, DocType)to throw an NPE if the list is null
which would result in an invalid state. I suppose the NPE is arguable but
this is better than returning a useless document.


    public Document(List content, DocType docType) {
	    if (content == null) 
		    throw new NullPointerException();

        setMixedContent(content);
        setDocType(docType);
    }

My updated test suite still has a couple of other places where Document
doesn't handle nulls but these are documented as TODO's and can wait.



More information about the jdom-interest mailing list