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 3807f669eb86b8ed13d3f10ade2ef218b0a848f1
Author: Andy Seaborne <[email protected]>
AuthorDate: Thu Nov 6 14:32:01 2025 +0000

    GH-3562: NodeValue creation cache
---
 .../org/apache/jena/sparql/expr/NVCompare.java     |   4 +-
 .../org/apache/jena/sparql/expr/NVDatatypes.java   | 102 +++++-----
 .../org/apache/jena/sparql/expr/NVFactory.java     |  27 ++-
 .../org/apache/jena/sparql/expr/NodeValue.java     |  65 +++----
 .../org/apache/jena/sparql/expr/TestNVFactory.java | 210 ++++++++++-----------
 5 files changed, 212 insertions(+), 196 deletions(-)

diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVCompare.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVCompare.java
index 5f12156779..16fc63d397 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVCompare.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVCompare.java
@@ -151,12 +151,12 @@ class NVCompare {
             case VSPACE_CDT_LIST : {
                 final LiteralLabel lit1 = nv1.asNode().getLiteral() ;
                 final LiteralLabel lit2 = nv2.asNode().getLiteral() ;
-                return CompositeDatatypeList.type.isEqual(lit1, lit2) ;
+                return CompositeDatatypeList.datatype().isEqual(lit1, lit2) ;
             }
             case VSPACE_CDT_MAP : {
                 final LiteralLabel lit1 = nv1.asNode().getLiteral() ;
                 final LiteralLabel lit2 = nv2.asNode().getLiteral() ;
-                return CompositeDatatypeMap.type.isEqual(lit1, lit2) ;
+                return CompositeDatatypeMap.datatype().isEqual(lit1, lit2) ;
             }
         }
 
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVDatatypes.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVDatatypes.java
index 6cd527a772..7bdc23101d 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVDatatypes.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVDatatypes.java
@@ -33,54 +33,53 @@ class NVDatatypes {
     // Not a derived type of xsd:decimal.
     //public static final RDFDatatype XSDprecisionDecimal = new 
XSDPRecisionDecimal("precisionDecimal", BigDecimal.class);
 
-    public static final RDFDatatype XSDdecimal = XSDDatatype.XSDdecimal;
-    public static final RDFDatatype XSDfloat = XSDDatatype.XSDfloat;
-    public static final RDFDatatype XSDdouble = XSDDatatype.XSDdouble;
-
-    public static final RDFDatatype XSDinteger = XSDDatatype.XSDinteger;
-    public static final RDFDatatype XSDpositiveInteger = 
XSDDatatype.XSDpositiveInteger;
-    public static final RDFDatatype XSDnegativeInteger = 
XSDDatatype.XSDnegativeInteger;
-    public static final RDFDatatype XSDnonPositiveInteger = 
XSDDatatype.XSDnonPositiveInteger;
-    public static final RDFDatatype XSDnonNegativeInteger = 
XSDDatatype.XSDnonNegativeInteger;
-
-    public static final RDFDatatype XSDlong = XSDDatatype.XSDlong;
-    public static final RDFDatatype XSDint = XSDDatatype.XSDint;
-    public static final RDFDatatype XSDshort = XSDDatatype.XSDshort;
-    public static final RDFDatatype XSDbyte = XSDDatatype.XSDbyte;
-
-    public static final RDFDatatype XSDunsignedLong = 
XSDDatatype.XSDunsignedLong;
-    public static final RDFDatatype XSDunsignedInt = 
XSDDatatype.XSDunsignedInt;
-    public static final RDFDatatype XSDunsignedShort = 
XSDDatatype.XSDunsignedShort;
-    public static final RDFDatatype XSDunsignedByte = 
XSDDatatype.XSDunsignedByte;
-
-    public static final RDFDatatype XSDboolean = XSDDatatype.XSDboolean;
-
-    public static final RDFDatatype XSDstring = XSDDatatype.XSDstring;
-    public static final RDFDatatype langString = RDF.dtLangString;
-    public static final RDFDatatype dirLangString = RDF.dtDirLangString;
-
-
-    public static final RDFDatatype XSDnormalizedString = 
XSDDatatype.XSDnormalizedString;
-//    public static final RDFDatatype XSDtoken = XSDDatatype.XSDtoken;
-//    public static final RDFDatatype XSDlanguage = XSDDatatype.XSDlanguage;
-
-//    public static final RDFDatatype XSDhexBinary = XSDDatatype.XSDhexBinary;
-//    public static final RDFDatatype XSDbase64Binary = 
XSDDatatype.XSDbase64Binary;
-
-    public static final RDFDatatype XSDdateTime = XSDDatatype.XSDdateTime;
-    public static final RDFDatatype XSDdateTimeStamp = 
XSDDatatype.XSDdateTimeStamp;
-    public static final RDFDatatype XSDdate = XSDDatatype.XSDdate;
-    public static final RDFDatatype XSDtime = XSDDatatype.XSDtime;
-
-    public static final RDFDatatype XSDduration = XSDDatatype.XSDduration;
-    public static final RDFDatatype XSDdayTimeDuration = 
XSDDatatype.XSDdayTimeDuration;
-    public static final RDFDatatype XSDyearMonthDuration = 
XSDDatatype.XSDyearMonthDuration;
-
-    public static final RDFDatatype XSDgYear = XSDDatatype.XSDgYear;
-    public static final RDFDatatype XSDgMonth = XSDDatatype.XSDgMonth;
-    public static final RDFDatatype XSDgDay = XSDDatatype.XSDgDay;
-    public static final RDFDatatype XSDgYearMonth = XSDDatatype.XSDgYearMonth;
-    public static final RDFDatatype XSDgMonthDay = XSDDatatype.XSDgMonthDay;
+    public static final RDFDatatype XSDdecimal            = 
datatype(XSDDatatype.XSDdecimal);
+    public static final RDFDatatype XSDfloat              = 
datatype(XSDDatatype.XSDfloat);
+    public static final RDFDatatype XSDdouble             = 
datatype(XSDDatatype.XSDdouble);
+
+    public static final RDFDatatype XSDinteger            = 
datatype(XSDDatatype.XSDinteger);
+    public static final RDFDatatype XSDpositiveInteger    = 
datatype(XSDDatatype.XSDpositiveInteger);
+    public static final RDFDatatype XSDnegativeInteger    = 
datatype(XSDDatatype.XSDnegativeInteger);
+    public static final RDFDatatype XSDnonPositiveInteger = 
datatype(XSDDatatype.XSDnonPositiveInteger);
+    public static final RDFDatatype XSDnonNegativeInteger = 
datatype(XSDDatatype.XSDnonNegativeInteger);
+
+    public static final RDFDatatype XSDlong               = 
datatype(XSDDatatype.XSDlong);
+    public static final RDFDatatype XSDint                = 
datatype(XSDDatatype.XSDint);
+    public static final RDFDatatype XSDshort              = 
datatype(XSDDatatype.XSDshort);
+    public static final RDFDatatype XSDbyte               = 
datatype(XSDDatatype.XSDbyte);
+
+    public static final RDFDatatype XSDunsignedLong       = 
datatype(XSDDatatype.XSDunsignedLong);
+    public static final RDFDatatype XSDunsignedInt        = 
datatype(XSDDatatype.XSDunsignedInt);
+    public static final RDFDatatype XSDunsignedShort      = 
datatype(XSDDatatype.XSDunsignedShort);
+    public static final RDFDatatype XSDunsignedByte       = 
datatype(XSDDatatype.XSDunsignedByte);
+
+    public static final RDFDatatype XSDboolean            = 
datatype(XSDDatatype.XSDboolean);
+
+    public static final RDFDatatype XSDstring             = 
datatype(XSDDatatype.XSDstring);
+    public static final RDFDatatype langString            = 
datatype(RDF.dtLangString);
+    public static final RDFDatatype dirLangString         = 
datatype(RDF.dtDirLangString);
+
+    public static final RDFDatatype XSDnormalizedString   = 
datatype(XSDDatatype.XSDnormalizedString);
+//    public static final RDFDatatype XSDtoken              = 
datatype(XSDDatatype.XSDtoken);
+//    public static final RDFDatatype XSDlanguage           = 
datatype(XSDDatatype.XSDlanguage);
+
+//    public static final RDFDatatype XSDhexBinary          = 
datatype(XSDDatatype.XSDhexBinary);
+//    public static final RDFDatatype XSDbase64Binary       = 
datatype(XSDDatatype.XSDbase64Binary);
+
+    public static final RDFDatatype XSDdateTime           = 
datatype(XSDDatatype.XSDdateTime);
+    public static final RDFDatatype XSDdateTimeStamp      = 
datatype(XSDDatatype.XSDdateTimeStamp);
+    public static final RDFDatatype XSDdate               = 
datatype(XSDDatatype.XSDdate);
+    public static final RDFDatatype XSDtime               = 
datatype(XSDDatatype.XSDtime);
+
+    public static final RDFDatatype XSDduration           = 
datatype(XSDDatatype.XSDduration);
+    public static final RDFDatatype XSDdayTimeDuration    = 
datatype(XSDDatatype.XSDdayTimeDuration);
+    public static final RDFDatatype XSDyearMonthDuration  = 
datatype(XSDDatatype.XSDyearMonthDuration);
+
+    public static final RDFDatatype XSDgYear              = 
datatype(XSDDatatype.XSDgYear);
+    public static final RDFDatatype XSDgMonth             = 
datatype(XSDDatatype.XSDgMonth);
+    public static final RDFDatatype XSDgDay               = 
datatype(XSDDatatype.XSDgDay);
+    public static final RDFDatatype XSDgYearMonth         = 
datatype(XSDDatatype.XSDgYearMonth);
+    public static final RDFDatatype XSDgMonthDay          = 
datatype(XSDDatatype.XSDgMonthDay);
 
     public static final Set<RDFDatatype> numerics = Set.of(XSDdecimal, 
XSDfloat, XSDdouble, XSDinteger,
                                                            XSDpositiveInteger, 
XSDnegativeInteger, XSDnonPositiveInteger, XSDnonNegativeInteger,
@@ -92,4 +91,9 @@ class NVDatatypes {
     public static final Set<RDFDatatype> temporal = Set.of(XSDdateTime, 
XSDdateTimeStamp,XSDdate, XSDtime,
                                                            XSDgYear, 
XSDgMonth, XSDgDay,
                                                            XSDgYearMonth, 
XSDgMonthDay);
-}
+
+    private static RDFDatatype datatype(RDFDatatype rdfDatatype) {
+        // Option to register in a set.
+        return rdfDatatype;
+    }
+}
\ No newline at end of file
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVFactory.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVFactory.java
index 5da176ba7d..345b5609d5 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVFactory.java
@@ -28,12 +28,14 @@ import java.util.Map;
 import javax.xml.datatype.Duration;
 import javax.xml.datatype.XMLGregorianCalendar;
 
+import org.apache.jena.atlas.lib.InternalErrorException;
 import org.apache.jena.datatypes.RDFDatatype;
 import org.apache.jena.graph.Node;
 import org.apache.jena.graph.impl.LiteralLabel;
 import org.apache.jena.sparql.ARQInternalErrorException;
 import org.apache.jena.sparql.SystemARQ;
 import org.apache.jena.sparql.expr.nodevalue.*;
+import org.apache.jena.sparql.util.NodeUtils;
 import org.apache.jena.sparql.util.RomanNumeral;
 import org.apache.jena.sparql.util.RomanNumeralDatatype;
 import org.apache.jena.vocabulary.RDF;
@@ -44,8 +46,28 @@ class NVFactory {
 
     private static Map<RDFDatatype, ToNodeValue> mapper = dtSetup();
 
-    public static NodeValue create(Node node) {
+    // Called from NodeValue.
+    static NodeValue create(Node node) {
+        if ( ! node.isLiteral() )
+            // Not a literal - no value to extract
+            return new NodeValueNode(node);
+
+        // Special cases: LangString and DirLangString, well-formed.
         RDFDatatype datatype = node.getLiteralDatatype();
+
+        boolean hasLangTag = NodeUtils.hasLang(node);  // hasLang - covers 
rdf:langString and rdf:dirLangString
+        if ( hasLangTag ) {
+            if ( NodeUtils.hasLangDir(node) ) {
+                if ( ! RDF.dtDirLangString.equals(datatype) )
+                    throw new InternalErrorException("Wrong type for literal 
with a text direction");
+                return new NodeValueLangDir(node);
+            } else {
+                if ( ! RDF.dtLangString.equals(datatype) )
+                    throw new InternalErrorException("Wrong type for literal 
with a langugae tag");
+                return new NodeValueLang(node);
+            }
+        }
+        // Includes literal datatype rdf:langString or rdf:dirLangString 
without the proper special components
         ToNodeValue function = mapper.get(datatype);
         if ( function == null )
             return new NodeValueNode(node);
@@ -86,9 +108,8 @@ class NVFactory {
         entry(mapper, XSDboolean,            NVFactory::booleanMaker);
 
         entry(mapper, XSDstring,             NVFactory::stringMaker);
-        //[DT] XXX needs validation
         entry(mapper, XSDnormalizedString,  NVFactory::stringMaker);
-        //[DT] XXX xsd;token, xsd:language
+        // XXX May be xsd;token, xsd:language
 
         entry(mapper, RDF.dtLangString,      NVFactory::langStringMaker);
         entry(mapper, RDF.dtDirLangString,   NVFactory::dirLangStringMaker);
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
index 0e619b453a..42c860b968 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
@@ -31,8 +31,12 @@ import javax.xml.datatype.DatatypeFactory;
 import javax.xml.datatype.Duration;
 import javax.xml.datatype.XMLGregorianCalendar;
 
+import org.apache.jena.atlas.lib.Cache;
+import org.apache.jena.atlas.lib.CacheFactory;
 import org.apache.jena.atlas.lib.DateTimeUtils;
 import org.apache.jena.atlas.logging.Log;
+import org.apache.jena.cdt.CompositeDatatypeList;
+import org.apache.jena.cdt.CompositeDatatypeMap;
 import org.apache.jena.datatypes.RDFDatatype;
 import org.apache.jena.datatypes.TypeMapper;
 import org.apache.jena.ext.xerces.DatatypeFactoryInst;
@@ -50,10 +54,8 @@ import 
org.apache.jena.sparql.serializer.SerializationContext;
 import org.apache.jena.sparql.sse.SSE;
 import org.apache.jena.sparql.util.FmtUtils;
 import org.apache.jena.sparql.util.NodeFactoryExtra;
-import org.apache.jena.sparql.util.NodeUtils;
 import org.apache.jena.sparql.util.XSDNumUtils;
 import org.apache.jena.sys.JenaSystem;
-import org.apache.jena.vocabulary.RDF;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -87,11 +89,17 @@ public abstract class NodeValue extends ExprNode
      * ref:  http://www.w3.org/TR/xquery/#dt-ebv
      */
 
-    private static Logger log = LoggerFactory.getLogger(NodeValue.class);
+    static Logger log = LoggerFactory.getLogger(NodeValue.class);
 
     public static boolean VerboseWarnings = true;
     public static boolean VerboseExceptions = false;
 
+    // Before constants
+    public static DatatypeFactory xmlDatatypeFactory =  
DatatypeFactoryInst.newDatatypeFactory();
+    private static int NODEVALUE_CACHE_SIZE = 10_000;
+    private static Set<RDFDatatype> noCache = 
Set.of(CompositeDatatypeList.datatype(), CompositeDatatypeMap.datatype());
+    private static Cache<Node, NodeValue> nodeValueCache = 
CacheFactory.createCache(NODEVALUE_CACHE_SIZE);
+
     public static final NodeValue TRUE   = NodeValue.makeNode("true", 
XSDboolean);
     public static final NodeValue FALSE  = NodeValue.makeNode("false", 
XSDboolean);
 
@@ -111,15 +119,6 @@ public abstract class NodeValue extends ExprNode
 
     public static final String xsdNamespace = XSD+"#";
 
-    public static DatatypeFactory xmlDatatypeFactory = null;
-
-    static {
-        // JDK default regardless.
-        //xmlDatatypeFactory = DatatypeFactory.newDefaultInstance();
-        // Extracted Xerces.
-        xmlDatatypeFactory = DatatypeFactoryInst.newDatatypeFactory();
-    }
-
     private Node node = null;     // Null used when a value has not been 
turned into a Node.
 
     protected NodeValue() { super(); }
@@ -510,14 +509,32 @@ public abstract class NodeValue extends ExprNode
     public Duration    getDuration() { raise(new ExprEvalTypeException("Not a 
duration: "+this)); return null; }
 
     // ----------------------------------------------------------------
-    // ---- Setting : used when a node is used to make a NodeValue
 
     private static NodeValue nodeToNodeValue(Node node) {
+        if ( node.isLiteral() ) {
+            // XXX Could have a set of all support datatypes in NVDatatypes
+            RDFDatatype dt = node.getLiteralDatatype();
+            if ( noCache.contains(dt) ) {
+                // Composite datatypes (CDT) are not cached.
+                return NodeValue.nodeToNodeValueMaker(node);
+            }
+        }
         if ( node.isExt() ) {
             // Don't judge custom extensions.
             return new NodeValueNode(node);
         }
+        NodeValue nv = nodeValueCache.get(node, 
NodeValue::nodeToNodeValueMaker);
+        //NodeValue nv = NodeValue.nodeToNodeValueMaker(node);
+        return nv;
+    }
 
+    /**
+     * Always returns a NodeValue of some kind.
+     *
+     * If the literal is ill-formed for the datatype,
+     * then a {@link NodeValueNode} is returned
+     */
+    private static NodeValue nodeToNodeValueMaker(Node node) {
         if ( ! node.isConcrete() ) {
             String msg;
             if ( node.isVariable() )
@@ -528,28 +545,6 @@ public abstract class NodeValue extends ExprNode
             throw new ExprException("Node is not a constant");
         }
 
-        if ( ! node.isLiteral() )
-            // Not a literal - no value to extract
-            return new NodeValueNode(node);
-
-        boolean hasLangTag = NodeUtils.isLangString(node);
-        boolean isPlainLiteral = ( node.getLiteralDatatypeURI() == null && ! 
hasLangTag );
-
-        if ( isPlainLiteral )
-            return new NodeValueString(node.getLiteralLexicalForm(), node);
-
-        if ( hasLangTag ) {
-            // Works for RDF 1.0 and RDF 1.1
-            if ( node.getLiteralDatatype() != null && ! 
RDF.dtLangString.equals(node.getLiteralDatatype()) ) {
-                if ( NodeValue.VerboseWarnings )
-                    Log.warn(NodeValue.class, "Lang tag and datatype (datatype 
ignored)");
-            }
-            // RDF 1.2
-            if ( NodeUtils.hasLangDir(node) )
-                    return new NodeValueLangDir(node);
-            return new NodeValueLang(node);
-        }
-
         // Includes creating NodeValueNode for ill-formed literals.
         NodeValue nv = NVFactory.create(node);
         return nv;
diff --git 
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNVFactory.java 
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNVFactory.java
index 35c330e357..d35a772660 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNVFactory.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNVFactory.java
@@ -100,49 +100,6 @@ public class TestNVFactory {
         assertTrue(nv.isDecimal());
     }
 
-    @Test
-    public void testBoolean() {
-        NodeValue nv1 = test("true", XSDboolean, NodeValueBoolean.class);
-        NodeValue nv2 = test("false", XSDboolean, NodeValueBoolean.class);
-    }
-
-    @Test
-    public void testString() {
-        NodeValue nv = test("test string", XSDstring, NodeValueString.class);
-    }
-
-    // Keep original language string tests as they have special handling
-    @Test
-    public void testLangString() {
-        String lex = "hello";
-        String lang = "en";
-        Node n = NodeFactory.createLiteralLang(lex, lang);
-        NodeValue nv = NVFactory.create(n);
-        assertTrue(NodeValueLang.class.isInstance(nv));
-        assertEquals(lex, nv.getString());
-        assertEquals(lang, nv.getLang());
-    }
-
-    @Test
-    public void testDirLangString() {
-        String lex = "hello";
-        String lang = "en-GB";
-        String ltr = "ltr";
-        Node n = NodeFactory.createLiteralDirLang(lex, lang, ltr);
-        NodeValue nv = NVFactory.create(RDF.dtDirLangString, n);
-        assertTrue(NodeValueLangDir.class.isInstance(nv));
-        assertEquals(lex, nv.getString());
-        assertEquals(lang, nv.getLang());
-    }
-
-    @Test
-    public void testInvalidIntegerLiteral() {
-        NodeValue nv = test("not-an-integer", XSDinteger, NodeValueNode.class);
-        assertNotNull(nv);
-        assertFalse(nv.isNumber());
-        assertFalse(nv.isInteger());
-    }
-
     @Test
     public void testDerivedInt() {
         NodeValue nv = test("123", XSDint, NodeValueInteger.class);
@@ -215,8 +172,110 @@ public class TestNVFactory {
         assertTrue(nv.isInteger());
     }
 
-    // Date and time types
+    @Test
+    public void testInvalidIntegerLiteral() {
+        NodeValue nv = test("not-an-integer", XSDinteger, NodeValueNode.class);
+        assertNotNull(nv);
+        assertFalse(nv.isNumber());
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidDecimalFormat() {
+        // Multiple decimal points
+        NodeValue nv = test("12.34.56", XSDdecimal, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidFloatFormat() {
+        // Incomplete exponent
+        NodeValue nv = test("12.34e", XSDfloat, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidIntegerFormat() {
+        // Decimal not allowed for integer
+        NodeValue nv = test("123.45", XSDinteger, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidPositiveIntegerNegativeValue() {
+        // Negative value not allowed for positive integer
+        NodeValue nv = test("-123", XSDpositiveInteger, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidUnsignedIntValue() {
+        // Negative value not allowed for unsigned
+        NodeValue nv = test("-1", XSDunsignedInt, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidByteRange() {
+        // Outside byte range (-128 to 127)
+        NodeValue nv = test("128", XSDbyte, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidUnsignedByteRange() {
+        // Outside unsigned byte range (0 to 255)
+        NodeValue nv = test("256", XSDunsignedByte, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidNonNegativeInteger() {
+        // Negative value not allowed
+        NodeValue nv = test("-1", XSDnonNegativeInteger, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testInvalidNonPositiveInteger() {
+        // Positive value not allowed
+        NodeValue nv = test("1", XSDnonPositiveInteger, NodeValueNode.class);
+        assertFalse(nv.isInteger());
+    }
+
+    @Test
+    public void testBoolean() {
+        NodeValue nv1 = test("true", XSDboolean, NodeValueBoolean.class);
+        NodeValue nv2 = test("false", XSDboolean, NodeValueBoolean.class);
+    }
+
+    @Test
+    public void testString() {
+        NodeValue nv = test("test string", XSDstring, NodeValueString.class);
+    }
+
+    @Test
+    public void testLangString() {
+        String lex = "hello";
+        String lang = "en";
+        Node n = NodeFactory.createLiteralLang(lex, lang);
+        NodeValue nv = NVFactory.create(n);
+        assertTrue(NodeValueLang.class.isInstance(nv));
+        assertEquals(lex, nv.getString());
+        assertEquals(lang, nv.getLang());
+    }
 
+    @Test
+    public void testDirLangString() {
+        String lex = "hello";
+        String lang = "en-GB";
+        String ltr = "ltr";
+        Node n = NodeFactory.createLiteralDirLang(lex, lang, ltr);
+        NodeValue nv = NVFactory.create(RDF.dtDirLangString, n);
+        assertTrue(NodeValueLangDir.class.isInstance(nv));
+        assertEquals(lex, nv.getString());
+        assertEquals(lang, nv.getLang());
+    }
 
     @Test
     public void testDateTimeType() {
@@ -374,27 +433,6 @@ public class TestNVFactory {
         NodeValue nv = test("2025-12-25", XSDdateTime, NodeValueNode.class);
     }
 
-    @Test
-    public void testInvalidDecimalFormat() {
-        // Multiple decimal points
-        NodeValue nv = test("12.34.56", XSDdecimal, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
-
-    @Test
-    public void testInvalidFloatFormat() {
-        // Incomplete exponent
-        NodeValue nv = test("12.34e", XSDfloat, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
-
-    @Test
-    public void testInvalidIntegerFormat() {
-        // Decimal not allowed for integer
-        NodeValue nv = test("123.45", XSDinteger, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
-
     @Test
     public void testInvalidDurationFormat() {
         // Invalid duration designator
@@ -412,46 +450,4 @@ public class TestNVFactory {
         // Invalid day value
         test("---32", XSDgDay, NodeValueNode.class);
     }
-
-    @Test
-    public void testInvalidPositiveIntegerNegativeValue() {
-        // Negative value not allowed for positive integer
-        NodeValue nv = test("-123", XSDpositiveInteger, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
-
-    @Test
-    public void testInvalidUnsignedIntValue() {
-        // Negative value not allowed for unsigned
-        NodeValue nv = test("-1", XSDunsignedInt, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
-
-    @Test
-    public void testInvalidByteRange() {
-        // Outside byte range (-128 to 127)
-        NodeValue nv = test("128", XSDbyte, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
-
-    @Test
-    public void testInvalidUnsignedByteRange() {
-        // Outside unsigned byte range (0 to 255)
-        NodeValue nv = test("256", XSDunsignedByte, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
-
-    @Test
-    public void testInvalidNonNegativeInteger() {
-        // Negative value not allowed
-        NodeValue nv = test("-1", XSDnonNegativeInteger, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
-
-    @Test
-    public void testInvalidNonPositiveInteger() {
-        // Positive value not allowed
-        NodeValue nv = test("1", XSDnonPositiveInteger, NodeValueNode.class);
-        assertFalse(nv.isInteger());
-    }
 }
\ No newline at end of file

Reply via email to