Marshalling and cloning XMLObjects w/Java OpenSAML
Brent Putman
putmanb at georgetown.edu
Tue Oct 1 17:16:01 EDT 2013
On 10/1/13 9:42 AM, Mark Dobrinic wrote:
> - To publish the metadata, I do a entityDescriptor.getDOM(),
Note that we generally don't recommend or support using getDOM() that
way. The standard way to go from an XMLObject to its DOM (Element)
representation is to marshall it, using the appropriate Marshaller
instance. See below.
>
>
>
> My questions/problems are:
> 1) As far as I can tell, this is the right way to do things: it works
> for creating the result: the EntityDescriptor 'oED_publish' gets the
> right NameIDFormats added. Can anybody confirm that using
> XMLHelper.cloneXMLObject() is the way to go here?
Yes, the XMLObjectHelper cloneXMLObject(..) methods are the correct way
and is how I'd do it. Note however that cloning an XMLObject this way
is sort of by "brute force", since it 1) marshalls the original
XMLObject 2) either clones or imports its Element, depending on the
rootInNewDocument arg and 3) unmarshalls a completely new XMObject tree
around the newly imported/cloned Element.
>
> 2) Problem: if (after I run cloneXMLObject()) I do an
> entityDescriptor.getDOM(), there is an empty document returned. I
> narrowed this down to here:
> XMLObjectHelper.cloneXMLObject() ->
> Marshaller.marshall() ->
> AbstractXMLObjectMarshaller.prepareForAdoption(XMLObject) ->
> XMLHelper.rootNamespaces(domCachingObject.getDOM());
If I'm understanding you correctly, I didn't think that should happen,
and I ran a little test. I don't see that behavior, the original
XMLObject still has a cached DOM. What *does* happen, and this is
something that I'd personally like to change in v3, is that the call to
Marshaller#marshall(XMLObject) always unconditionally results in a new
Document being created and the Element being adopted into it. This is
somewhat inefficient and probably unexpected IMHO. But there might be a
technical reason why the original author of the code did it that way.
If not, then that behavior will likely change in v3.
Anyway, if what you mean is that from your original parsing of XML you
had a reference to the original Document, and then you do the clone of
the XMLObject representing say the root Element, then it is true that
that Document after the clone will be "empty" in that it no longer has
its document root element. However, the XMLObject will still have its
cached DOM Element (via getDOM), in fact IIRC the same Element instance,
it will just be owned by a new Document.
> After the rootNamespaces is called on the XMLObject-instance that is
> being cloned, the DOM-element of the original XMLObject is being reset t
> an empty document
Again I'm not sure exactly what you mean, you're sort of mixing
XMLObject terminology and DOM terminology. Do you mean that at that
point the getDOM() returns null? Or do you mean that the original DOM
document is empty? The former I do not see in my test, and wouldn't
expect that from the code. The latter would be expected and you
probably shouldn't be holding on to and using the Document reference
that way.
>
> Side-question:
> I am not completely sure what the DOM element represents of an
> XMLObject: is this a cached version?
Yes, it's basically a cached instance of the Element that represents
that XMLObject.
> If so, is there a way to re-create
> the DOM that belongs to this XMLObject?
Absolutely, that is what marshalling is e.g.:
Marshaller marshaller =
Configuration.getMarshallerFactory().getMarshaller(xmlObject);
Element origElement = marshaller.marshall(xmlObject);
In fact that is the supported way of "converting" from an XMLObject to
an Element. Using getDOM() is not recommended; the only reason that
method is public is I think the original author couldn't find a way to
make protected or package access.
> Main question:
> How can I *really* clone an XMLObject, so I can achieve that I can
> create a new EntityDescriptor(XMLObject) by picking elements from
> another EntityDescriptor(XMLObject), clone these, and add them to the
> new EntityDescriptor(XMLObject), without affecting the source
> EntityDescriptor(XMLObject)?
What you are doing is the correct way to clone. That shouldn't affect
the source XMLObject at least as far as getDOM() returning null.
What *will* absolutely cause getDOM() to return null is if you mutate
the XMLObject in any way (e.g. changing any values on it via its
setters, or mutating any of its XMObject children lists, etc). In that
case, the cached DOM Element on the XMLObject being mutated (and on all
ancestor XMLObjects) is dropped, for hopefully obvious reasons: the
cached Element is stale and no longer reflects the content of the
XMLObject. When you need the DOM representation again, you simply
re-marshall it.
HTH,
Brent
More information about the dev
mailing list