You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2025/12/09 10:06:05 UTC
(jena) 05/05: GH-3618: Node.sameTermAs(Node) and Node.sameValueAs(Node)
This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
commit abd21173a8808d3621a743f0651c653e0ef739bd
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Fri Dec 5 12:38:25 2025 +0000
GH-3618: Node.sameTermAs(Node) and Node.sameValueAs(Node)
---
.../src/main/java/org/apache/jena/graph/Node.java | 23 +++---
.../java/org/apache/jena/graph/Node_Literal.java | 2 +-
.../jena/reasoner/rulesys/Node_RuleVariable.java | 2 +-
.../reasoner/rulesys/impl/RETEClauseFilter.java | 88 ++++++++++++----------
.../java/org/apache/jena/graph/test/TestNode.java | 14 +++-
5 files changed, 74 insertions(+), 55 deletions(-)
diff --git a/jena-core/src/main/java/org/apache/jena/graph/Node.java b/jena-core/src/main/java/org/apache/jena/graph/Node.java
index 35d1d20679..80d5ceb4bd 100644
--- a/jena-core/src/main/java/org/apache/jena/graph/Node.java
+++ b/jena-core/src/main/java/org/apache/jena/graph/Node.java
@@ -21,6 +21,7 @@ package org.apache.jena.graph;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
+import java.util.Objects;
import java.util.function.Function;
import org.apache.jena.datatypes.RDFDatatype ;
@@ -250,22 +251,26 @@ public abstract class Node implements Serializable {
* <p>
* The {@link Node} argument must not be null.
*/
- public boolean sameTermAs(Object node) {
+ public boolean sameTermAs(Node node) {
+ Objects.requireNonNull(node);
return equals(node);
}
/**
- * Test that two nodes are semantically equivalent.
- * In some cases this may be the same as equals, in others
- * equals is stricter. For example, two xsd:int literals with
- * the same value but different lexical form are semantically
- * equivalent but distinguished by the java equals function.
- * <p>Default implementation is to use {@link #equals}
- * subclasses should override this.</p>
+ * Test that two nodes represent the same value.
* <p>
+ * In some cases this may be the same as {@link #sameTermAs}. For example, two
+ * xsd:int literals with the same value but different lexical form are
+ * semantically equivalent but distinguished by the java equals function.
+ * </p>
+ * <p>
+ * The default implementation is to use {@link #equals}; subclasses should
+ * override this.
+ * </p>
* The {@link Node} argument must not be null.
*/
- public boolean sameValueAs(Object node) {
+ public boolean sameValueAs(Node node) {
+ Objects.requireNonNull(node);
return equals(node);
}
diff --git a/jena-core/src/main/java/org/apache/jena/graph/Node_Literal.java b/jena-core/src/main/java/org/apache/jena/graph/Node_Literal.java
index 92050a7aed..70e2353132 100644
--- a/jena-core/src/main/java/org/apache/jena/graph/Node_Literal.java
+++ b/jena-core/src/main/java/org/apache/jena/graph/Node_Literal.java
@@ -126,7 +126,7 @@ public class Node_Literal extends Node
}
@Override
- public boolean sameValueAs(Object other) {
+ public boolean sameValueAs(Node other) {
if ( other instanceof Node_Literal otherLiteral )
return label.sameValueAs( otherLiteral.getLiteral() );
return false;
diff --git a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Node_RuleVariable.java b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Node_RuleVariable.java
index 5f54e3c2dd..7fa62177cf 100755
--- a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Node_RuleVariable.java
+++ b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/Node_RuleVariable.java
@@ -174,7 +174,7 @@ public class Node_RuleVariable extends Node_Variable {
* Test that two nodes are semantically equivalent.
*/
@Override
- public boolean sameValueAs(Object other) {
+ public boolean sameValueAs(Node other) {
return other instanceof Node_RuleVariable;
}
diff --git a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/RETEClauseFilter.java b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/RETEClauseFilter.java
index f864eab2aa..f16ce4488c 100644
--- a/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/RETEClauseFilter.java
+++ b/jena-core/src/main/java/org/apache/jena/reasoner/rulesys/impl/RETEClauseFilter.java
@@ -31,47 +31,47 @@ import org.apache.jena.reasoner.rulesys.* ;
* and bindings are implemented using a simple byte-coded interpreter.
*/
public class RETEClauseFilter implements RETESourceNode {
-
+
/** Contains the set of byte-coded instructions and argument pointers */
protected byte[] instructions;
-
+
/** Contains the object arguments referenced from the instructions array */
protected Object[] args;
-
+
/** The network node to receive any created tokens */
protected RETESinkNode continuation;
-
+
/** Instruction code: Check triple entry (arg1) against literal value (arg2). */
public static final byte TESTValue = 0x01;
-
+
/** Instruction code: Check literal value is a functor of name arg1 */
public static final byte TESTFunctorName = 0x02;
-
+
/** Instruction code: Cross match two triple entries (arg1, arg2) */
public static final byte TESTIntraMatch = 0x03;
-
+
/** Instruction code: Create a result environment of length arg1. */
public static final byte CREATEToken = 0x04;
-
+
/** Instruction code: Bind a node (arg1) to a place in the rules token (arg2). */
public static final byte BIND = 0x05;
-
+
/** Instruction code: Final entry - dispatch to the network. */
public static final byte END = 0x06;
-
+
/** Argument addressing code: triple subject */
public static final byte ADDRSubject = 0x10;
-
+
/** Argument addressing code: triple predicate */
public static final byte ADDRPredicate = 0x20;
-
+
/** Argument addressing code: triple object as a whole */
public static final byte ADDRObject = 0x30;
-
- /** Argument addressing code: triple object functor node, offset in
+
+ /** Argument addressing code: triple object functor node, offset in
* low nibble, only usable after a successful TestFunctorName. */
public static final byte ADDRFunctorNode = 0x40;
-
+
/**
* Constructor.
* @param instructions the set of byte-coded instructions and argument pointers.
@@ -81,7 +81,7 @@ public class RETEClauseFilter implements RETESourceNode {
this.instructions = instructions;
this.args = args;
}
-
+
/**
* Create a filter node from a rule clause.
* Clause complexity is limited to less than 50 args in a Functor.
@@ -89,17 +89,17 @@ public class RETEClauseFilter implements RETESourceNode {
* @param envLength the size of binding environment that should be created on successful matches
* @param varList a list to which all clause variables will be appended
*/
- public static RETEClauseFilter compile(TriplePattern clause, int envLength, List<Node> varList) {
+ public static RETEClauseFilter compile(TriplePattern clause, int envLength, List<Node> varList) {
byte[] instructions = new byte[300];
byte[] bindInstructions = new byte[100];
ArrayList<Object> args = new ArrayList<>();
- int pc = 0;
+ int pc = 0;
int bpc = 0;
-
+
// Pass 0 - prepare env creation statement
bindInstructions[bpc++] = CREATEToken;
bindInstructions[bpc++] = (byte)envLength;
-
+
// Pass 1 - check literal values
Node n = clause.getSubject();
if ( !n.isVariable() ) {
@@ -162,16 +162,16 @@ public class RETEClauseFilter implements RETESourceNode {
varList.add(n);
}
bindInstructions[bpc++] = END;
-
+
// Pass 4 - Pack instructions
byte[] packed = new byte[pc + bpc];
System.arraycopy(instructions, 0, packed, 0, pc);
System.arraycopy(bindInstructions, 0, packed, pc, bpc);
Object[] packedArgs = args.toArray();
-
+
return new RETEClauseFilter(packed, packedArgs);
}
-
+
/**
* Set the continuation node for this node.
*/
@@ -186,23 +186,32 @@ public class RETEClauseFilter implements RETESourceNode {
* @param isAdd true if the triple is being added to the working set.
*/
public void fire(Triple triple, boolean isAdd) {
-
+
Functor lastFunctor = null; // bound by TESTFunctorName
BindingVector env = null; // bound by CREATEToken
Node n = null; // Temp workspace
-
+
for (int pc = 0; pc < instructions.length; ) {
switch(instructions[pc++]) {
-
- case TESTValue:
- // Check triple entry (arg1) against literal value (arg2)
- if (! getTripleValue(triple, instructions[pc++], lastFunctor)
- .sameValueAs(args[instructions[pc++]])) return;
- break;
-
+
+ case TESTValue:
+ // Check triple entry (arg1) against literal value (arg2)
+ Node arg1 = getTripleValue(triple, instructions[pc++], lastFunctor);
+ Object obj2 = args[instructions[pc++]];
+ if ( ! ( obj2 instanceof Node arg2) )
+ return;
+ if ( ! arg1.sameValueAs(arg2) )
+ return;
+ break;
+ // Was:
+ // when sameValueAs took an Object as argument (a non-node was then false).
+ // if (! getTripleValue(triple, instructions[pc++], lastFunctor)
+ // .sameValueAs(args[instructions[pc++]])) return;
+ // break;
+
case TESTFunctorName:
// Check literal value is a functor of name arg1.
- // Side effect: leaves a loop variable pointing to functor
+ // Side effect: leaves a loop variable pointing to functor
// for possible later functor argument accesses
n = triple.getObject();
if ( !n.isLiteral() ) return;
@@ -210,26 +219,25 @@ public class RETEClauseFilter implements RETESourceNode {
lastFunctor = (Functor)n.getLiteralValue();
if ( !lastFunctor.getName().equals(args[instructions[pc++]]) ) return;
break;
-
+
case CREATEToken:
// Create a result environment of length arg1
env = new BindingVector(new Node[instructions[pc++]]);
break;
-
+
case BIND:
// Bind a node (arg1) to a place in the rules token (arg2)
n = getTripleValue(triple, instructions[pc++], lastFunctor);
if ( !env.bind(instructions[pc++], n) ) return;
break;
-
+
case END:
// Success, fire the continuation
continuation.fire(env, isAdd);
}
}
-
}
-
+
/**
* Helpful function. Return the node from the argument triple
* corresponding to the byte code address.
@@ -247,7 +255,7 @@ public class RETEClauseFilter implements RETESourceNode {
}
return null;
}
-
+
/**
* Clone this node in the network.
* @param netCopy a map from RETENode to cloned instance
@@ -263,5 +271,5 @@ public class RETEClauseFilter implements RETESourceNode {
}
return clone;
}
-
+
}
diff --git a/jena-core/src/test/java/org/apache/jena/graph/test/TestNode.java b/jena-core/src/test/java/org/apache/jena/graph/test/TestNode.java
index ed7271d26e..4f682d5737 100644
--- a/jena-core/src/test/java/org/apache/jena/graph/test/TestNode.java
+++ b/jena-core/src/test/java/org/apache/jena/graph/test/TestNode.java
@@ -628,11 +628,17 @@ public class TestNode extends GraphTestBase {
assertFalse("", NodeCreateUtils.create("_X").sameTermAs(NodeCreateUtils.create("_Y")));
assertTrue(NodeCreateUtils.create("10").sameTermAs(NodeCreateUtils.create("10")));
assertFalse("", NodeCreateUtils.create("10").sameTermAs(NodeCreateUtils.create("11")));
+ // Jena6. nulls no longer allowed.
- assertFalse("", NodeCreateUtils.create("S").sameTermAs(null));
- assertFalse("", NodeCreateUtils.create("_X").sameTermAs(null));
- assertFalse("", NodeCreateUtils.create("10").sameTermAs(null));
- assertFalse("", Node.ANY.sameTermAs(null));
+ try {
+ NodeCreateUtils.create("S").sameTermAs(null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException ex) {}
+
+// assertFalse("", NodeCreateUtils.create("S").sameTermAs(null));
+// assertFalse("", NodeCreateUtils.create("_X").sameTermAs(null));
+// assertFalse("", NodeCreateUtils.create("10").sameTermAs(null));
+// assertFalse("", Node.ANY.sameTermAs(null));
}
public void testDataSameValue() {