@@ -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 ;
@@ -446,14 +453,7 @@ public DocumentImpl getOwnerDocument() {
446453 * @return a <code>boolean</code> value
447454 */
448455 public boolean isDocument () {
449- return nodeType == Node .DOCUMENT_NODE ;
450- }
451-
452-
453- private @ Nullable WeakReference <Node > cachedNode = null ;
454-
455- private void invalidateCachedNode () {
456- this .cachedNode = null ;
456+ return getNodeType () == Node .DOCUMENT_NODE ;
457457 }
458458
459459 /**
@@ -463,7 +463,8 @@ private void invalidateCachedNode() {
463463 */
464464 @ Override
465465 public Node getNode () {
466- if (isDocument ()) {
466+ // NOTE(AR) we don't call isDocument() or getNodeType() here as it would call back to getNode() and cause a StackOverflowError
467+ if (nodeType == Node .DOCUMENT_NODE ) {
467468 return doc ;
468469 }
469470
@@ -480,7 +481,7 @@ public Node getNode() {
480481 this .nodeType = realNode .getNodeType ();
481482 this .qname = realNode .getQName ();
482483 }
483- cachedNode = new WeakReference <>(realNode );
484+ this . cachedNode = new WeakReference <>(realNode );
484485 node = realNode ;
485486 }
486487
@@ -489,6 +490,10 @@ public Node getNode() {
489490
490491 @ Override
491492 public short getNodeType () {
493+ if (nodeType == UNKNOWN_NODE_TYPE ) {
494+ // NOTE(AR) get the node from the database, which will also update the `nodeType`
495+ getNode ();
496+ }
492497 return nodeType ;
493498 }
494499
@@ -738,6 +743,7 @@ public String debugContext() {
738743 // methods of interface Item
739744 @ Override
740745 public int getType () {
746+ final short nodeType = getNodeType ();
741747 if (nodeType == UNKNOWN_NODE_TYPE ) {
742748 return Type .NODE ;
743749 }
@@ -835,12 +841,9 @@ public void toSAX(final DBBroker broker, final ContentHandler handler, final Pro
835841
836842 @ Override
837843 public void copyTo (final DBBroker broker , final DocumentBuilderReceiver receiver ) throws SAXException {
838- NodeImpl node = null ;
839- if (nodeType < 0 ) {
840- node = (NodeImpl ) getNode ();
841- }
842- if (nodeType == Node .ATTRIBUTE_NODE ) {
843- final AttrImpl attr = (node == null ? (AttrImpl ) getNode () : (AttrImpl ) node );
844+ final Node node = getNode ();
845+ if (node .getNodeType () == Node .ATTRIBUTE_NODE ) {
846+ final AttrImpl attr = (AttrImpl ) node ;
844847 receiver .attribute (attr .getQName (), attr .getValue ());
845848 } else {
846849 receiver .addReferenceNode (this );
@@ -1328,6 +1331,7 @@ public NodeSet selectFollowing(final NodeSet following, final int position, fina
13281331
13291332 @ Override
13301333 public NodeSet directSelectAttribute (final DBBroker broker , final NodeTest test , final int contextId ) {
1334+ final short nodeType = getNodeType ();
13311335 if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
13321336 return NodeSet .EMPTY_SET ;
13331337 }
@@ -1371,6 +1375,7 @@ public NodeSet directSelectAttribute(final DBBroker broker, final NodeTest test,
13711375 }
13721376
13731377 public NodeSet directSelectChild (final QName qname , final int contextId ) {
1378+ final short nodeType = getNodeType ();
13741379 if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
13751380 return NodeSet .EMPTY_SET ;
13761381 }
@@ -1593,6 +1598,7 @@ public boolean equalDocs(final DocumentSet other) {
15931598
15941599 @ Override
15951600 public boolean directMatchAttribute (final DBBroker broker , final NodeTest test , final int contextId ) {
1601+ final short nodeType = getNodeType ();
15961602 if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
15971603 return false ;
15981604 }
@@ -1622,6 +1628,7 @@ public boolean directMatchAttribute(final DBBroker broker, final NodeTest test,
16221628 }
16231629
16241630 public boolean directMatchChild (final QName qname , final int contextId ) {
1631+ final short nodeType = getNodeType ();
16251632 if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
16261633 return false ;
16271634 }
0 commit comments