You are viewing a plain text version of this content. The canonical link for it is here.
Posted to j-users@xerces.apache.org by Domenic Figliomeni <do...@gmail.com> on 2009/06/01 06:41:27 UTC

Class casting an interface is bad

Hi,

I recently encountered a problem where I pass one of my elements to the
insertBefore(a, b) method on Node and get a class cast exception.  My design
uses composition to expose the Node Methods of an underlying Node, which in
this case it gets from Xerces.  InsertBefore(Node a, Node b) should honor
its contract to accept anything implementing Node and do the job.  However,
when I looked at the code for
https://svn.apache.org/repos/asf/xerces/java/trunk/src/org/apache/xerces/dom/ParentNode.javaI
see this in the internal implementation of the method:

// Convert to internal type, to avoid repeated casting
        ChildNode newInternal = (ChildNode)newChild;


This cast makes the assumption that the implementation is
org.apache.xerces.dom.ChildNode.  In my case it is not, but the underlying
element is.  Therefore, I can get away with it by using
MyNode.getUndelyingNode, but I think that this is a bug as any
implementation should work.  I would suggest that these classes could use
composition rather than casting to get an internal tye to use although I
don't know enough about the internal workings of xerces to make a
reccomendation.  All I know is that casting an interface to an internal type
is probably going to cause problems for others too.

You could have ChildNode newInternel = new ChildNode(newChild); instead of
the above

public class ChildNode {
   private Node node;
   protected Node getNode() {
      return this.node;
   }
   protected void setNode(Node node) {
      this.node = node;
   }
...
   public Whatever someNodeMethod() {
      return this.getNode().someNodeMethod();
   }
...

}

I hope this is useful!

Regards,
Domenic Figliomeni

Re: Class casting an interface is bad

Posted by ke...@us.ibm.com.
> Thanks for the explanation although I am a bit confused as to why we
> would bother to have an interface when we require a specific 
> implementation.

Sorry, but this really is the way the W3C intends it to work.

The interface standardizes most usages of the DOM. But for efficiency of 
implementation, you really don't want to try to standardize usage inside 
the implementation, and for that reason nodes from different 
implementations will generally not be interchangable. 

The DOM's importNode operation was created specifically to address this 
case. If you aren't sure the node is from a compatable DOM, import it 
first; that creates a compatible equivalent.

http://www.w3.org/DOM/faq.html#ownerdoc

---------------------------------------------------------------------
To unsubscribe, e-mail: j-users-unsubscribe@xerces.apache.org
For additional commands, e-mail: j-users-help@xerces.apache.org


Re: Class casting an interface is bad

Posted by Domenic Figliomeni <do...@gmail.com>.
Hi Michael,

Thanks for the explanation although I am a bit confused as to why we would
bother to have an interface when we require a specific implementation.  I
guess the bottom line is that I can't rely on any implementation, xerces or
otherwise to honor the contract the way I would expect.  I can solve this
problem by doing some type checking and casting in my composed methods.  For
some background, I am writing a component based view framework which uses
Document interfaces as opposed to String Buffers like in JSP and others.  It
is already functional and I will be releasing it to Apache 2.0 soon.
Perhaps you could give me some feedback when it goes into the public domain

Regards,
Domenic

2009/6/1 Michael Glavassevich <mr...@ca.ibm.com>

> Hi,
>
> Sorry, but you can't add nodes from arbitrary implementations to the DOM.
> They must have been created by the same Document node (i.e. the same
> implementation) [1] as all the other nodes in the DOM, otherwise a
> DOMException(WRONG_DOCUMENT_ERR) is thrown. The only reason that it would
> be getting passed that check is if your implementation says its owner
> Document [2] is the one from Xerces which is wrong because Xerces didn't
> create the node, doesn't own it and would have no idea how to work with it.
>
> Thanks.
>
> [1]
> http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-952280727
> [2]
> http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#node-ownerDoc
>
> Michael Glavassevich
> XML Parser Development
> IBM Toronto Lab
> E-mail: mrglavas@ca.ibm.com
> E-mail: mrglavas@apache.org
>
> Domenic Figliomeni <do...@gmail.com> wrote on 06/01/2009 12:41:27
> AM:
>
>
> > Hi,
> >
> > I recently encountered a problem where I pass one of my elements to
> > the insertBefore(a, b) method on Node and get a class cast
> > exception.  My design uses composition to expose the Node Methods of
> > an underlying Node, which in this case it gets from Xerces.
> > InsertBefore(Node a, Node b) should honor its contract to accept
> > anything implementing Node and do the job.  However, when I looked
> > at the code for https://svn.apache.
> > org/repos/asf/xerces/java/trunk/src/org/apache/xerces/dom/ParentNode.java
> > I see this in the internal implementation of the method:
>
> > // Convert to internal type, to avoid repeated casting
> >         ChildNode newInternal = (ChildNode)newChild;
> >
> > This cast makes the assumption that the implementation is org.
> > apache.xerces.dom.ChildNode.  In my case it is not, but the
> > underlying element is.  Therefore, I can get away with it by using
> > MyNode.getUndelyingNode, but I think that this is a bug as any
> > implementation should work.  I would suggest that these classes
> > could use composition rather than casting to get an internal tye to
> > use although I don't know enough about the internal workings of
> > xerces to make a reccomendation.  All I know is that casting an
> > interface to an internal type is probably going to cause problems
> > for others too.
> >
> > You could have ChildNode newInternel = new ChildNode(newChild);
> > instead of the above
> >
> > public class ChildNode {
> >    private Node node;
> >    protected Node getNode() {
> >       return this.node;
> >    }
> >    protected void setNode(Node node) {
> >       this.node = node;
> >    }
> > ...
> >    public Whatever someNodeMethod() {
> >       return this.getNode().someNodeMethod();
> >    }
> > ...
> >
> > }
> >
> > I hope this is useful!
> >
> > Regards,
> > Domenic Figliomeni
>

Re: Class casting an interface is bad

Posted by Michael Glavassevich <mr...@ca.ibm.com>.
Hi,

Sorry, but you can't add nodes from arbitrary implementations to the DOM.
They must have been created by the same Document node (i.e. the same
implementation) [1] as all the other nodes in the DOM, otherwise a
DOMException(WRONG_DOCUMENT_ERR) is thrown. The only reason that it would
be getting passed that check is if your implementation says its owner
Document [2] is the one from Xerces which is wrong because Xerces didn't
create the node, doesn't own it and would have no idea how to work with it.

Thanks.

[1]
http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-952280727
[2]
http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#node-ownerDoc

Michael Glavassevich
XML Parser Development
IBM Toronto Lab
E-mail: mrglavas@ca.ibm.com
E-mail: mrglavas@apache.org

Domenic Figliomeni <do...@gmail.com> wrote on 06/01/2009 12:41:27
AM:

> Hi,
>
> I recently encountered a problem where I pass one of my elements to
> the insertBefore(a, b) method on Node and get a class cast
> exception.  My design uses composition to expose the Node Methods of
> an underlying Node, which in this case it gets from Xerces.
> InsertBefore(Node a, Node b) should honor its contract to accept
> anything implementing Node and do the job.  However, when I looked
> at the code for https://svn.apache.
> org/repos/asf/xerces/java/trunk/src/org/apache/xerces/dom/ParentNode.java
> I see this in the internal implementation of the method:

> // Convert to internal type, to avoid repeated casting
>         ChildNode newInternal = (ChildNode)newChild;
>
> This cast makes the assumption that the implementation is org.
> apache.xerces.dom.ChildNode.  In my case it is not, but the
> underlying element is.  Therefore, I can get away with it by using
> MyNode.getUndelyingNode, but I think that this is a bug as any
> implementation should work.  I would suggest that these classes
> could use composition rather than casting to get an internal tye to
> use although I don't know enough about the internal workings of
> xerces to make a reccomendation.  All I know is that casting an
> interface to an internal type is probably going to cause problems
> for others too.
>
> You could have ChildNode newInternel = new ChildNode(newChild);
> instead of the above
>
> public class ChildNode {
>    private Node node;
>    protected Node getNode() {
>       return this.node;
>    }
>    protected void setNode(Node node) {
>       this.node = node;
>    }
> ...
>    public Whatever someNodeMethod() {
>       return this.getNode().someNodeMethod();
>    }
> ...
>
> }
>
> I hope this is useful!
>
> Regards,
> Domenic Figliomeni