@@ -137,6 +137,8 @@ public class NodeProxy implements NodeSet, NodeValue, NodeHandle, DocumentSet, C
137
137
138
138
private final Expression expression ;
139
139
140
+ private @ Nullable WeakReference <Node > cachedNode = null ;
141
+
140
142
/**
141
143
* Creates a new <code>NodeProxy</code> instance.
142
144
*
@@ -233,6 +235,10 @@ public NodeProxy(final Expression expression, final DocumentImpl doc, final Node
233
235
this .nodeId = nodeId ;
234
236
}
235
237
238
+ private void invalidateCachedNode () {
239
+ this .cachedNode = null ;
240
+ }
241
+
236
242
public void update (final ElementImpl element ) {
237
243
invalidateCachedNode ();
238
244
this .doc = element .getOwnerDocument ();
@@ -322,6 +328,7 @@ public NodeId getNodeId() {
322
328
@ Override
323
329
public QName getQName () {
324
330
if (qname == null ) {
331
+ // NOTE(AR) get the node from the database, which will also update the `qname`
325
332
getNode ();
326
333
}
327
334
return qname ;
@@ -446,14 +453,7 @@ public DocumentImpl getOwnerDocument() {
446
453
* @return a <code>boolean</code> value
447
454
*/
448
455
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 ;
457
457
}
458
458
459
459
/**
@@ -463,7 +463,8 @@ private void invalidateCachedNode() {
463
463
*/
464
464
@ Override
465
465
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 ) {
467
468
return doc ;
468
469
}
469
470
@@ -480,7 +481,7 @@ public Node getNode() {
480
481
this .nodeType = realNode .getNodeType ();
481
482
this .qname = realNode .getQName ();
482
483
}
483
- cachedNode = new WeakReference <>(realNode );
484
+ this . cachedNode = new WeakReference <>(realNode );
484
485
node = realNode ;
485
486
}
486
487
@@ -489,6 +490,10 @@ public Node getNode() {
489
490
490
491
@ Override
491
492
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
+ }
492
497
return nodeType ;
493
498
}
494
499
@@ -738,6 +743,7 @@ public String debugContext() {
738
743
// methods of interface Item
739
744
@ Override
740
745
public int getType () {
746
+ final short nodeType = getNodeType ();
741
747
if (nodeType == UNKNOWN_NODE_TYPE ) {
742
748
return Type .NODE ;
743
749
}
@@ -835,12 +841,9 @@ public void toSAX(final DBBroker broker, final ContentHandler handler, final Pro
835
841
836
842
@ Override
837
843
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 ;
844
847
receiver .attribute (attr .getQName (), attr .getValue ());
845
848
} else {
846
849
receiver .addReferenceNode (this );
@@ -1328,6 +1331,7 @@ public NodeSet selectFollowing(final NodeSet following, final int position, fina
1328
1331
1329
1332
@ Override
1330
1333
public NodeSet directSelectAttribute (final DBBroker broker , final NodeTest test , final int contextId ) {
1334
+ final short nodeType = getNodeType ();
1331
1335
if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
1332
1336
return NodeSet .EMPTY_SET ;
1333
1337
}
@@ -1371,6 +1375,7 @@ public NodeSet directSelectAttribute(final DBBroker broker, final NodeTest test,
1371
1375
}
1372
1376
1373
1377
public NodeSet directSelectChild (final QName qname , final int contextId ) {
1378
+ final short nodeType = getNodeType ();
1374
1379
if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
1375
1380
return NodeSet .EMPTY_SET ;
1376
1381
}
@@ -1593,6 +1598,7 @@ public boolean equalDocs(final DocumentSet other) {
1593
1598
1594
1599
@ Override
1595
1600
public boolean directMatchAttribute (final DBBroker broker , final NodeTest test , final int contextId ) {
1601
+ final short nodeType = getNodeType ();
1596
1602
if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
1597
1603
return false ;
1598
1604
}
@@ -1622,6 +1628,7 @@ public boolean directMatchAttribute(final DBBroker broker, final NodeTest test,
1622
1628
}
1623
1629
1624
1630
public boolean directMatchChild (final QName qname , final int contextId ) {
1631
+ final short nodeType = getNodeType ();
1625
1632
if (nodeType != UNKNOWN_NODE_TYPE && nodeType != Node .ELEMENT_NODE ) {
1626
1633
return false ;
1627
1634
}
0 commit comments