@@ -137,6 +137,8 @@ public class NodeProxy implements NodeSet, NodeValue, NodeHandle, DocumentSet, C
137137
138138 private final Expression expression ;
139139
140+ private @ Nullable WeakReference <Node > cachedNode = null ;
141+
140142 /**
141143 * Creates a new <code>NodeProxy</code> instance.
142144 *
@@ -233,6 +235,10 @@ public NodeProxy(final Expression expression, final DocumentImpl doc, final Node
233235 this .nodeId = nodeId ;
234236 }
235237
238+ private void invalidateCachedNode () {
239+ this .cachedNode = null ;
240+ }
241+
236242 public void update (final ElementImpl element ) {
237243 invalidateCachedNode ();
238244 this .doc = element .getOwnerDocument ();
@@ -322,6 +328,7 @@ public NodeId getNodeId() {
322328 @ Override
323329 public QName getQName () {
324330 if (qname == null ) {
331+ // NOTE(AR) get the node from the database, which will also update the `qname`
325332 getNode ();
326333 }
327334 return qname ;
@@ -447,14 +454,7 @@ public DocumentImpl getOwnerDocument() {
447454 * @return a <code>boolean</code> value
448455 */
449456 public boolean isDocument () {
450- return nodeType == Node .DOCUMENT_NODE ;
451- }
452-
453-
454- private @ Nullable WeakReference <Node > cachedNode = null ;
455-
456- private void invalidateCachedNode () {
457- this .cachedNode = null ;
457+ return getNodeType () == Node .DOCUMENT_NODE ;
458458 }
459459
460460 /**
@@ -464,7 +464,8 @@ private void invalidateCachedNode() {
464464 */
465465 @ Override
466466 public Node getNode () {
467- if (isDocument ()) {
467+ // NOTE(AR) we don't call isDocument() or getNodeType() here as it would call back to getNode() and cause a StackOverflowError
468+ if (nodeType == Node .DOCUMENT_NODE ) {
468469 return doc ;
469470 }
470471
@@ -481,7 +482,7 @@ public Node getNode() {
481482 this .nodeType = realNode .getNodeType ();
482483 this .qname = realNode .getQName ();
483484 }
484- cachedNode = new WeakReference <>(realNode );
485+ this . cachedNode = new WeakReference <>(realNode );
485486 node = realNode ;
486487 }
487488
@@ -490,6 +491,10 @@ public Node getNode() {
490491
491492 @ Override
492493 public short getNodeType () {
494+ if (nodeType == UNKNOWN_NODE_TYPE ) {
495+ // NOTE(AR) get the node from the database, which will also update the `nodeType`
496+ getNode ();
497+ }
493498 return nodeType ;
494499 }
495500
@@ -851,12 +856,9 @@ public void toSAX(final DBBroker broker, final ContentHandler handler, final Pro
851856
852857 @ Override
853858 public void copyTo (final DBBroker broker , final DocumentBuilderReceiver receiver ) throws SAXException {
854- NodeImpl node = null ;
855- if (nodeType < 0 ) {
856- node = (NodeImpl ) getNode ();
857- }
858- if (nodeType == Node .ATTRIBUTE_NODE ) {
859- final AttrImpl attr = (node == null ? (AttrImpl ) getNode () : (AttrImpl ) node );
859+ final Node node = getNode ();
860+ if (node .getNodeType () == Node .ATTRIBUTE_NODE ) {
861+ final AttrImpl attr = (AttrImpl ) node ;
860862 receiver .attribute (attr .getQName (), attr .getValue ());
861863 } else {
862864 receiver .addReferenceNode (this );
@@ -1344,6 +1346,7 @@ public NodeSet selectFollowing(final NodeSet following, final int position, fina
13441346
13451347 @ Override
13461348 public NodeSet directSelectAttribute (final DBBroker broker , final NodeTest test , final int contextId ) {
1349+ final short nodeType = getNodeType ();
13471350 if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
13481351 return NodeSet .EMPTY_SET ;
13491352 }
@@ -1387,6 +1390,7 @@ public NodeSet directSelectAttribute(final DBBroker broker, final NodeTest test,
13871390 }
13881391
13891392 public NodeSet directSelectChild (final QName qname , final int contextId ) {
1393+ final short nodeType = getNodeType ();
13901394 if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
13911395 return NodeSet .EMPTY_SET ;
13921396 }
@@ -1609,6 +1613,7 @@ public boolean equalDocs(final DocumentSet other) {
16091613
16101614 @ Override
16111615 public boolean directMatchAttribute (final DBBroker broker , final NodeTest test , final int contextId ) {
1616+ final short nodeType = getNodeType ();
16121617 if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
16131618 return false ;
16141619 }
@@ -1638,6 +1643,7 @@ public boolean directMatchAttribute(final DBBroker broker, final NodeTest test,
16381643 }
16391644
16401645 public boolean directMatchChild (final QName qname , final int contextId ) {
1646+ final short nodeType = getNodeType ();
16411647 if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
16421648 return false ;
16431649 }
0 commit comments