You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by cl...@apache.org on 2023/11/27 16:03:17 UTC

(jena) branch main updated: JENA-2357 Added Collection and collection SPARQL textual representation as a valid argument to the QueryBuilder clauses.

This is an automated email from the ASF dual-hosted git repository.

claude pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git


The following commit(s) were added to refs/heads/main by this push:
     new 5d5beb64d6 JENA-2357 Added Collection and collection SPARQL textual representation as a valid argument to the QueryBuilder clauses.
     new a3165eb4f7 Merge pull request #2085 from Claudenw/add_list_to_builder_where
5d5beb64d6 is described below

commit 5d5beb64d619eb0108293261b6fdebfd34f269cf
Author: Claude Warren <cl...@xenei.com>
AuthorDate: Mon Nov 27 17:00:36 2023 +0100

    JENA-2357 Added Collection and collection SPARQL textual representation as a valid argument to the QueryBuilder clauses.
---
 .../arq/querybuilder/AbstractQueryBuilder.java     |  32 ++
 .../apache/jena/arq/querybuilder/AskBuilder.java   |  38 +-
 .../jena/arq/querybuilder/ConstructBuilder.java    |  45 ++-
 .../apache/jena/arq/querybuilder/Converters.java   | 386 ++++++++++++++++++++-
 .../jena/arq/querybuilder/DescribeBuilder.java     |  43 ++-
 .../jena/arq/querybuilder/SelectBuilder.java       |  46 ++-
 .../jena/arq/querybuilder/UpdateBuilder.java       | 102 +++++-
 .../apache/jena/arq/querybuilder/WhereBuilder.java |  41 ++-
 .../jena/arq/querybuilder/clauses/WhereClause.java |  30 +-
 .../arq/querybuilder/handlers/WhereHandler.java    |  51 ++-
 .../querybuilder/rewriters/AbstractRewriter.java   |   6 +-
 .../updatebuilder/WhereQuadHolder.java             |  28 ++
 .../apache/jena/arq/TestAbstractQueryBuilder.java  |  37 ++
 .../arq/querybuilder/AbstractQueryBuilderTest.java |  44 ++-
 .../jena/arq/querybuilder/AskBuilderTest.java      |   1 +
 .../arq/querybuilder/ConstructBuilderTest.java     |   1 +
 .../jena/arq/querybuilder/ConvertersTest.java      | 125 ++++++-
 .../jena/arq/querybuilder/SelectBuilderTest.java   |  16 +-
 .../querybuilder/clauses/SolutionModifierTest.java |  11 +-
 .../arq/querybuilder/clauses/WhereClauseTest.java  | 179 +++++++++-
 .../handlers/SolutionModifierHandlerTest.java      |  11 +-
 .../querybuilder/handlers/WhereHandlerTest.java    | 103 ++++--
 22 files changed, 1233 insertions(+), 143 deletions(-)

diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
index d1c5bcb9a0..53f48d1cc5 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
@@ -146,7 +146,9 @@ public abstract class AbstractQueryBuilder<T extends AbstractQueryBuilder<T>>
      * @param p the predicate object
      * @param o the object object.
      * @return a TriplePath
+     * @deprecated Use {@link makeTriplePaths(Object, Object, Object)}
      */
+    @Deprecated(since="5.0.0")
     public TriplePath makeTriplePath(Object s, Object p, Object o) {
         final Object po = makeNodeOrPath(p);
         if (po instanceof Path) {
@@ -154,6 +156,36 @@ public abstract class AbstractQueryBuilder<T extends AbstractQueryBuilder<T>>
         }
         return new TriplePath(Triple.create(makeNode(s), (Node) po, makeNode(o)));
     }
+    
+    /**
+     * Make a collecton triple path from the objects.
+     *
+     * For subject, predicate and objects nodes
+     * <ul>
+     * <li>Will return Node.ANY if object is null.</li>
+     * <li>Will return the enclosed Node from a FrontsNode</li>
+     * <li>Will return the object if it is a Node.</li>
+     * <li>For {@code subject} and {@code object} <em>only</em>, if the object is a collection, will convert each item
+     * in the collection into a node and create an RDF list. All RDF list nodes are included in the collection.</li> 
+     * <li>If the object is a String
+     * <ul>
+     * <li>For <code>predicate</code> <em>only</em>, will attempt to parse as a path</li>
+     * <li>for subject, predicate and object will call NodeFactoryExtra.parseNode()
+     * using the currently defined prefixes if the object is a String</li>
+     * </ul>
+     * </li>
+     * <li>Will create a literal representation if the parseNode() fails or for any
+     * other object type.</li>
+     * </ul>
+     *
+     * @param s The subject object
+     * @param p the predicate object
+     * @param o the object object.
+     * @return a TriplePath
+     */
+    public List<TriplePath> makeTriplePaths(Object s, Object p, Object o) {
+        return Converters.makeTriplePaths(s, p, o, query.getPrefixMapping());
+    }
 
     /**
      * A convenience method to make an expression from a string. Evaluates the
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java
index 21033a94a0..4fce3786e3 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java
@@ -113,6 +113,12 @@ public class AskBuilder extends AbstractQueryBuilder<AskBuilder>
         return this;
     }
 
+    @Override
+    public AskBuilder addWhere(Collection<TriplePath> collection) {
+        getWhereHandler().addWhere(collection);
+        return this;
+    }
+
     @Override
     public AskBuilder addWhere(Triple t) {
         getWhereHandler().addWhere(new TriplePath(t));
@@ -127,7 +133,7 @@ public class AskBuilder extends AbstractQueryBuilder<AskBuilder>
 
     @Override
     public AskBuilder addWhere(Object s, Object p, Object o) {
-        getWhereHandler().addWhere(makeTriplePath(s, p, o));
+        getWhereHandler().addWhere(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -185,8 +191,7 @@ public class AskBuilder extends AbstractQueryBuilder<AskBuilder>
 
     @Override
     public AskBuilder addOptional(Triple t) {
-        getWhereHandler().addOptional(new TriplePath(t));
-        return this;
+        return addOptional(new TriplePath(t));
     }
 
     @Override
@@ -196,14 +201,19 @@ public class AskBuilder extends AbstractQueryBuilder<AskBuilder>
     }
 
     @Override
-    public AskBuilder addOptional(FrontsTriple t) {
-        getWhereHandler().addOptional(new TriplePath(t.asTriple()));
+    public AskBuilder addOptional(Collection<TriplePath> collection) {
+        getWhereHandler().addOptional(collection);
         return this;
     }
 
+    @Override
+    public AskBuilder addOptional(FrontsTriple t) {
+        return addOptional(new TriplePath(t.asTriple()));
+    }
+
     @Override
     public AskBuilder addOptional(Object s, Object p, Object o) {
-        getWhereHandler().addOptional(makeTriplePath(s, p, o));
+        getWhereHandler().addOptional(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -240,19 +250,19 @@ public class AskBuilder extends AbstractQueryBuilder<AskBuilder>
 
     @Override
     public AskBuilder addGraph(Object graph, FrontsTriple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple.asTriple()));
+        addGraph(graph, new TriplePath(triple.asTriple()));
         return this;
     }
 
     @Override
     public AskBuilder addGraph(Object graph, Object subject, Object predicate, Object object) {
-        getWhereHandler().addGraph(makeNode(graph), makeTriplePath(subject, predicate, object));
+        getWhereHandler().addGraph(makeNode(graph), makeTriplePaths(subject, predicate, object));
         return this;
     }
 
     @Override
     public AskBuilder addGraph(Object graph, Triple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple));
+        addGraph(graph, new TriplePath(triple));
         return this;
     }
 
@@ -262,6 +272,12 @@ public class AskBuilder extends AbstractQueryBuilder<AskBuilder>
         return this;
     }
 
+    @Override
+    public AskBuilder addGraph(Object graph, Collection<TriplePath> collection) {
+        getWhereHandler().addGraph(makeNode(graph), collection);
+        return this;
+    }
+
     @Override
     public AskBuilder addBind(Expr expression, Object var) {
         getWhereHandler().addBind(expression, Converters.makeVar(var));
@@ -363,6 +379,10 @@ public class AskBuilder extends AbstractQueryBuilder<AskBuilder>
         return handlerBlock.getModifierHandler();
     }
 
+    /*
+     * @deprecated use {@code addWhere(Converters.makeCollection(List.of(Object...)))}, or simply call {@link #addWhere(Object, Object, Object)} passing the collection for one of the objects.
+     */
+    @Deprecated(since="5.0.0")
     @Override
     public Node list(Object... objs) {
         return getWhereHandler().list(objs);
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java
index 669d527172..3a9b30dd5c 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java
@@ -17,6 +17,7 @@
  */
 package org.apache.jena.arq.querybuilder;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -210,6 +211,12 @@ public class ConstructBuilder extends AbstractQueryBuilder<ConstructBuilder> imp
         return this;
     }
 
+    @Override
+    public ConstructBuilder addWhere(Collection<TriplePath> collection) {
+        getWhereHandler().addWhere(collection);
+        return this;
+    }
+    
     @Override
     public ConstructBuilder addWhere(Triple t) {
         getWhereHandler().addWhere(new TriplePath(t));
@@ -224,7 +231,7 @@ public class ConstructBuilder extends AbstractQueryBuilder<ConstructBuilder> imp
 
     @Override
     public ConstructBuilder addWhere(Object s, Object p, Object o) {
-        getWhereHandler().addWhere(makeTriplePath(s, p, o));
+        getWhereHandler().addWhere(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -276,15 +283,20 @@ public class ConstructBuilder extends AbstractQueryBuilder<ConstructBuilder> imp
 
     @Override
     public ConstructBuilder addOptional(TriplePath t) {
-        getWhereHandler().addOptional(t);
+        getWhereHandler().addOptional(Arrays.asList(t));
         return this;
     }
 
     @Override
-    public ConstructBuilder addOptional(Triple t) {
-        getWhereHandler().addOptional(new TriplePath(t));
+    public ConstructBuilder addOptional(Collection<TriplePath> collection) {
+        getWhereHandler().addOptional(collection);
         return this;
     }
+    
+    @Override
+    public ConstructBuilder addOptional(Triple t) {
+        return addOptional(new TriplePath(t));
+    }
 
     @Override
     public ConstructBuilder addOptional(AbstractQueryBuilder<?> t) {
@@ -294,13 +306,12 @@ public class ConstructBuilder extends AbstractQueryBuilder<ConstructBuilder> imp
 
     @Override
     public ConstructBuilder addOptional(FrontsTriple t) {
-        getWhereHandler().addOptional(new TriplePath(t.asTriple()));
-        return this;
+        return addOptional(new TriplePath(t.asTriple()));
     }
 
     @Override
     public ConstructBuilder addOptional(Object s, Object p, Object o) {
-        getWhereHandler().addOptional(makeTriplePath(s, p, o));
+        getWhereHandler().addOptional(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -337,25 +348,29 @@ public class ConstructBuilder extends AbstractQueryBuilder<ConstructBuilder> imp
 
     @Override
     public ConstructBuilder addGraph(Object graph, FrontsTriple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple.asTriple()));
-        return this;
+        return addGraph(graph, new TriplePath(triple.asTriple()));
     }
 
     @Override
     public ConstructBuilder addGraph(Object graph, Object subject, Object predicate, Object object) {
-        getWhereHandler().addGraph(makeNode(graph), makeTriplePath(subject, predicate, object));
+        getWhereHandler().addGraph(makeNode(graph), makeTriplePaths(subject, predicate, object));
         return this;
     }
 
     @Override
     public ConstructBuilder addGraph(Object graph, Triple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple));
-        return this;
+        return addGraph(graph, new TriplePath(triple));
     }
 
     @Override
     public ConstructBuilder addGraph(Object graph, TriplePath triplePath) {
-        getWhereHandler().addGraph(makeNode(graph), triplePath);
+        getWhereHandler().addGraph(makeNode(graph), Arrays.asList(triplePath));
+        return this;
+    }
+    
+    @Override
+    public ConstructBuilder addGraph(Object graph, Collection<TriplePath> collection) {
+        getWhereHandler().addGraph(makeNode(graph), collection);
         return this;
     }
 
@@ -387,6 +402,10 @@ public class ConstructBuilder extends AbstractQueryBuilder<ConstructBuilder> imp
         return addConstruct(Triple.create(makeNode(s), makeNode(p), makeNode(o)));
     }
 
+    /*
+     * @deprecated use {@code addWhere(Converters.makeCollection(List.of(Object...)))}, or simply call {@link #addWhere(Object, Object, Object)} passing the collection for one of the objects.
+     */
+    @Deprecated(since="5.0.0")
     @Override
     public Node list(Object... objs) {
         return getWhereHandler().list(objs);
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/Converters.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/Converters.java
index 3c80e248e0..066a87a98e 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/Converters.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/Converters.java
@@ -17,11 +17,18 @@
  */
 package org.apache.jena.arq.querybuilder;
 
+import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Predicate;
 
+import org.apache.jena.arq.querybuilder.rewriters.AbstractRewriter;
+import org.apache.jena.arq.querybuilder.rewriters.PathRewriter;
 import org.apache.jena.datatypes.BaseDatatype;
 import org.apache.jena.datatypes.DatatypeFormatException;
 import org.apache.jena.datatypes.RDFDatatype;
@@ -29,16 +36,22 @@ import org.apache.jena.datatypes.TypeMapper;
 import org.apache.jena.graph.FrontsNode;
 import org.apache.jena.graph.Node;
 import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.graph.Triple;
 import org.apache.jena.riot.RiotException;
 import org.apache.jena.riot.system.PrefixMapFactory;
 import org.apache.jena.shared.PrefixMapping;
 import org.apache.jena.sparql.ARQInternalErrorException;
+import org.apache.jena.sparql.core.TriplePath;
 import org.apache.jena.sparql.core.Var;
 import org.apache.jena.sparql.expr.ExprVar;
+import org.apache.jena.sparql.lang.arq.ARQParser;
+import org.apache.jena.sparql.lang.arq.ParseException;
 import org.apache.jena.sparql.path.P_Link;
 import org.apache.jena.sparql.path.Path;
 import org.apache.jena.sparql.path.PathParser;
+import org.apache.jena.sparql.syntax.TripleCollectorMark;
 import org.apache.jena.sparql.util.NodeFactoryExtra;
+import org.apache.jena.vocabulary.RDF;
 
 /**
  * A collection of static methods to convert from Objects to various types used
@@ -50,6 +63,16 @@ public class Converters {
         // do not make instance
     }
 
+    /**
+     * @param o the object to test.
+     * @return true if the object is a Java collection or a string starting with '(' and ending with ')'
+     */
+    private static boolean isCollection(Object o) {
+        Predicate<String> isLiteralCollection = (s) -> s.charAt(0) == '(' && s.charAt(s.length()-1) == ')';
+        return o != null && (o instanceof Collection || 
+               (o instanceof String && isLiteralCollection.test(((String) o).trim())));
+    }
+
     /**
      * Converts any Node_Variable nodes into Var nodes.
      *
@@ -160,13 +183,13 @@ public class Converters {
         if (o instanceof Node) {
             return checkVar((Node) o);
         }
+
         if (o instanceof String) {
             try {
                 return checkVar(NodeFactoryExtra.parseNode((String) o, PrefixMapFactory.create(pMapping)));
             } catch (final RiotException e) {
                 // expected in some cases -- do nothing
             }
-
         }
         return makeLiteral(o);
     }
@@ -317,4 +340,365 @@ public class Converters {
         return values;
     }
 
+    /**
+     * Gathers the triples and adds them to the collector.
+     * @param collector the collector for the triples.
+     * @param s Subject object may be expanded to an RDF collection.
+     * @param p Subject object may be expanded to an RDF collection.
+     * @param o Subject object may be expanded to an RDF collection.
+     * @param prefixMapping the prefix mapping to use for URI resolution.
+     */
+    private static void gatherTriples(ReadableTripleCollectorMark collector, Object s, Object p, Object o,
+            PrefixMapping prefixMapping) {
+        Node sNode = null;
+        Object pNode = null;
+        Node oNode = null;
+
+        Function<Object, Node> processNode = (n) -> {
+            if (isCollection(n)) {
+                int mark = collector.mark();
+                gatherTriples(collector, n, prefixMapping);
+                return collector.getSubject(mark);
+            }
+            return makeNode(n, prefixMapping);
+        };
+
+        sNode = processNode.apply(s);
+
+        if (isCollection(p)) {
+            int mark = collector.mark();
+            gatherTriples(collector, p, prefixMapping);
+            pNode = collector.getSubject(mark);
+        } else {
+            pNode = makeNodeOrPath(p, prefixMapping);
+        }
+
+        oNode = processNode.apply(o);
+
+        if (pNode instanceof Path) {
+            collector.addTriplePath(new TriplePath(sNode, (Path) pNode, oNode));
+        } else {
+            collector.addTriple(Triple.create(sNode, (Node) pNode, oNode));
+        }
+
+    }
+
+    /**
+     * Creates a collection of {@code TriplePath}s from the {@code s, p, o}. If
+     * {@code s}, {@code p}, or {@code o} is a collection or a String representation of a 
+     * collection like {@code "(a, b, c)"} the
+     * {@code makeCollectionTriplePaths()} conversions are applied. If {@code s} and/or
+     * {@code o} is not a collection the {@code makeNode()} conversions are applied.
+     * if {@code p} is not a collection the @{code makeNodeOrPath()} conversion is
+     * applied.
+     * <p><em>Note: Path objects are not supported in RDF collections.  A custom Datatype would need
+     * to be registered to place them in collections</em></p>
+     * 
+     * @param s the object for the subject.
+     * @param p the object for the predicate.
+     * @param o the object for the object.
+     * @param prefixMapping the PrefixMapping to resolve nodes.
+     * @return A list of {@code TriplePath} objects.
+     * @see #makeNodeOrPath(Object, PrefixMapping)
+     * @see #makeCollectionTriplePaths(Object, PrefixMapping)
+     * @see #makeNode(Object, PrefixMapping)
+     */
+    public static List<TriplePath> makeTriplePaths(Object s, Object p, Object o, PrefixMapping prefixMapping) {
+        ConvertersTriplePathCollector result = new ConvertersTriplePathCollector();
+        gatherTriples(result, s, p, o, prefixMapping);
+        return result.result;
+    }
+
+    /**
+     * Creates a collection of {@code Triple}s from the {@code s, p, o}. If
+     * {@code s}, {@code p}, or {@code o} is a collection or a String representation of a 
+     * collection like {@code "(a, b, c)"} the
+     * {@code makeCollectionTriples()} conversions are applied. If {@code s}, {@code p}, or
+     * {@code o} is not a collection the {@code makeNode()} conversions are applied.
+     * This differs from
+     * {@link #makeTriplePaths(Object, Object, Object, PrefixMapping)} in that the
+     * {@code p} may not be a path.
+     * 
+     * <p><em>Note: Path objects are not supported in RDF collections.  A custom Datatype would need
+     * to be registered to place them in collections</em></p>
+     *  
+     * @param s the object for the subject.
+     * @param p the object for the predicate.
+     * @param o the object for the object.
+     * @param prefixMapping the PrefixMapping to resolve nodes.
+     * @return A list of {@code Triple} objects.
+     * @see #makeNodeOrPath(Object, PrefixMapping)
+     * @see #makeCollectionTriples(Object, PrefixMapping)
+     * @see #makeNode(Object, PrefixMapping)
+     */
+    public static List<Triple> makeTriples(Object s, Object p, Object o, PrefixMapping prefixMapping) {
+        ConvertersTripleCollector result = new ConvertersTripleCollector();
+        gatherTriples(result, s, p, o, prefixMapping);
+        return result.result;
+    }
+
+    /**
+     * Creates an RDF collection from a collection object. The collection object may be either 
+     * a Java collection or an ARQParser collection literal like {@code "(a, b, c)"}. 
+     * @param collector the TripleCollector to add the triples to.
+     * @param collection the collection of objects or string representation of collection to convert.
+     * @param prefixMapping the prefix mapping to use.
+     */
+    @SuppressWarnings("unchecked")
+    private static void gatherTriples(ReadableTripleCollectorMark collector, Object collection,
+            PrefixMapping prefixMapping) {
+        if (collection instanceof Collection) {
+            Node previous = null;
+            for (Object obj : (Collection<Object>) collection) {
+                Node current = NodeFactory.createBlankNode();
+                if (previous != null) {
+                    collector.addTriple(Triple.create(previous, RDF.rest.asNode(), current));
+                }
+                if (isCollection(obj)) {
+                    int mark = collector.mark();
+                    gatherTriples(collector, obj, prefixMapping);
+                    collector.addTriple(Triple.create(current, RDF.first.asNode(), collector.getSubject(mark)));
+                } else {
+                    collector.addTriple(Triple.create(current, RDF.first.asNode(), makeNode(obj, prefixMapping)));
+                }
+                previous = current;
+            }
+            collector.addTriple(Triple.create(previous, RDF.rest.asNode(), RDF.nil.asNode()));
+        } else {
+            String parserInput = collection.toString().trim();
+            ARQParser parser = new ARQParser(new StringReader(parserInput));
+            int mark = collector.mark();
+            try {
+                parser.CollectionPath(collector);
+            } catch (ParseException e) {
+                throw new IllegalArgumentException(String.format("Unable to parse: %s", collection), e);
+            }
+            collector.rewriteFrom(mark);
+        }
+    }
+
+    /**
+     * Create an RDF collection from a collection of objects as per
+     * <a href='http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#collections'>
+     * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#collections</a>
+     * <p>
+     * Embedded collections are recursively expanded and added to the resulting
+     * list. Other object types in the collections are converted using
+     * {@code makeNode} PrefixMapping)}.
+     * <p>
+     * <p><em>Note: Path objects are not supported in RDF collections.  A custom Datatype would need
+     * to be registered to place them in collections</em></p>
+     * Usage:
+     * <ul>
+     * <li>In most cases direct calls to makeCollection are unnecessary as passing
+     * the collection to methods like {@code addWhere(Object, Object, Object)} will
+     * correctly create and add the list.</li>
+     * <li>In cases where makeCollectionTriples is called the Subject of the first
+     * {@code Triple} is the RDF Collection node.</li>
+     * </ul>
+     * </p>
+     * 
+     * @param collection the collections of objects for the list.
+     * @return A list of {@code Triple} objects.
+     * @see #makeNode(Object, PrefixMapping)
+     */
+    public static List<Triple> makeCollectionTriples(Object collection, PrefixMapping prefixMapping) {
+        ConvertersTripleCollector collector = new ConvertersTripleCollector();
+        gatherTriples(collector, collection, prefixMapping);
+        return collector.result;
+    }
+
+    /**
+     * Create an RDF collection from a collection of objects as per
+     * <a href='http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#collections'>
+     * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#collections</a>.
+     * <p>
+     * Embedded collections are recursively expanded and added to the resulting
+     * list. Other object types in the collections are converted using
+     * {@code makeNode} PrefixMapping)}.
+     * <p>
+     * <p><em>Note: Path objects are not supported in RDF collections.  A custom Datatype would need
+     * to be registered to place them in collections</em></p>
+     * Usage:
+     * <ul>
+     * <li>In most cases direct calls to makeCollectionTriplePaths are unnecessary
+     * as passing the collection to methods like
+     * {@code addWhere(Object, Object, Object)} will correctly create and add the
+     * list.</li>
+     * <li>In cases where makeCollectionTriplePath is called the Subject of the
+     * first {@code TriplePath} is the RDF Collection node.</li>
+     * </ul>
+     * </p>
+     * 
+     * @param n the collections of objects for the list.
+     * @return A list of {@code TriplePath} objects.
+     * @see #makeNode(Object, PrefixMapping)
+     */
+    public static List<TriplePath> makeCollectionTriplePaths(Object n, PrefixMapping prefixMapping) {
+        ConvertersTriplePathCollector collector = new ConvertersTriplePathCollector();
+        gatherTriples(collector, n, prefixMapping);
+        return collector.result;
+    }
+
+    /**
+     * defines methods needed by converters to convert collections into into RDF collections.
+     */
+    interface ReadableTripleCollectorMark extends TripleCollectorMark {
+        /**
+         * Get the subject from the entry in the collection at the {@code mark} location.
+         * @param mark the location to retrieve from.
+         * @return the Subject node
+         */
+        Node getSubject(int mark);
+
+        /**
+         * Rewrite the variable nodes in the triples from {@code mark} to the end.
+         * This is required because the parser that converts from literal {@code "(a, b, c)"} 
+         * to the RDF list will number the variables from 0.
+         * @param mark the position to start the rewrite from.
+         */
+        void rewriteFrom(int mark);
+    }
+
+    /**
+     * Collects triples only.
+     */
+    private static class ConvertersTripleCollector implements ReadableTripleCollectorMark {
+        List<Triple> result = new ArrayList<>();
+
+        @Override
+        public void addTriple(Triple t) {
+            result.add(t);
+        }
+
+        @Override
+        public void addTriplePath(TriplePath tPath) {
+            throw new IllegalArgumentException("Path is not allowed in a Triple");
+        }
+
+        @Override
+        public int mark() {
+            return result.size();
+        }
+
+        @Override
+        public void addTriple(int index, Triple t) {
+            result.add(index, t);
+        }
+
+        @Override
+        public void addTriplePath(int index, TriplePath tPath) {
+            throw new IllegalArgumentException("Path is not allowed in a Triple");
+        }
+
+        @Override
+        public Node getSubject(int mark) {
+            return result.get(mark).getSubject();
+        }
+
+        @Override
+        public void rewriteFrom(int mark) {
+            Map<Var, Node> values = new HashMap<>();
+            TripleRewriter rewriter = new TripleRewriter(values);
+            for (int i = mark; i < mark(); i++) {
+                result.set(i, rewriter.rewrite(result.get(i)));
+            }
+        }
+    }
+
+    /**
+     * Collects triple paths.
+     */
+    private static class ConvertersTriplePathCollector implements ReadableTripleCollectorMark {
+        List<TriplePath> result = new ArrayList<>();
+
+        @Override
+        public void addTriple(Triple t) {
+            result.add(new TriplePath(t));
+        }
+
+        @Override
+        public void addTriplePath(TriplePath tPath) {
+            result.add(tPath);
+        }
+
+        @Override
+        public int mark() {
+            return result.size();
+        }
+
+        @Override
+        public void addTriple(int index, Triple t) {
+            result.add(index, new TriplePath(t));
+        }
+
+        @Override
+        public void addTriplePath(int index, TriplePath tPath) {
+            result.add(index, tPath);
+        };
+
+        @Override
+        public Node getSubject(int mark) {
+            return result.get(mark).getSubject();
+        }
+
+        @Override
+        public void rewriteFrom(int mark) {
+            Map<Var, Node> values = new HashMap<>();
+            TripleRewriter rewriter = new TripleRewriter(values);
+            for (int i = mark; i < mark(); i++) {
+                result.set(i, rewriter.rewrite(result.get(i)));
+            }
+        }
+    }
+
+    /**
+     * Rewriter implementation to convert the numbered variables to blank nodes.
+     */
+    private static class TripleRewriter extends AbstractRewriter<Node> {
+        private PathRewriter pathRewriter;
+
+        protected TripleRewriter(Map<Var, Node> values) {
+            super(values);
+            pathRewriter = new PathRewriter(values) {
+                @Override
+                protected Node changeNode(Node n) {
+                    return TripleRewriter.this.changeNode(n);
+                }
+            };
+        }
+
+        @Override
+        protected Node changeNode(Node n) {
+            if (n == null) {
+                return n;
+            }
+            if (n.isVariable() && n.toString().startsWith("??")) {
+                Var key = Var.alloc(n);
+                Node result = values.get(key);
+                if (result == null) {
+                    result = NodeFactory.createBlankNode();
+                    values.put(key, result);
+                }
+                return result;
+            }
+            return n;
+        }
+
+        /**
+         * Rewrite a triple path.
+         * 
+         * @param t The triple path to rewrite.
+         * @return the triple path after rewriting.
+         */
+        @Override
+        public TriplePath rewrite(TriplePath t) {
+            if (t.getPath() == null) {
+                return new TriplePath(Triple.create(changeNode(t.getSubject()), changeNode(t.getPredicate()),
+                        changeNode(t.getObject())));
+            }
+            t.getPath().visit(pathRewriter);
+            return new TriplePath(changeNode(t.getSubject()), pathRewriter.getResult(), changeNode(t.getObject()));
+        }
+    }
 }
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/DescribeBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/DescribeBuilder.java
index a80b45a82d..5fdd9f494b 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/DescribeBuilder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/DescribeBuilder.java
@@ -17,6 +17,7 @@
  */
 package org.apache.jena.arq.querybuilder;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -197,6 +198,13 @@ public class DescribeBuilder extends AbstractQueryBuilder<DescribeBuilder> imple
         getWhereHandler().addWhere(t);
         return this;
     }
+    
+
+    @Override
+    public DescribeBuilder addWhere(Collection<TriplePath> collection) {
+        getWhereHandler().addWhere(collection);
+        return this;
+    }
 
     @Override
     public DescribeBuilder addWhere(FrontsTriple t) {
@@ -206,7 +214,7 @@ public class DescribeBuilder extends AbstractQueryBuilder<DescribeBuilder> imple
 
     @Override
     public DescribeBuilder addWhere(Object s, Object p, Object o) {
-        getWhereHandler().addWhere(makeTriplePath(s, p, o));
+        getWhereHandler().addWhere(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -258,25 +266,29 @@ public class DescribeBuilder extends AbstractQueryBuilder<DescribeBuilder> imple
 
     @Override
     public DescribeBuilder addOptional(Triple t) {
-        getWhereHandler().addOptional(new TriplePath(t));
-        return this;
+        return addOptional(new TriplePath(t));
     }
 
     @Override
     public DescribeBuilder addOptional(TriplePath t) {
-        getWhereHandler().addOptional(t);
+        getWhereHandler().addOptional(Arrays.asList(t));
         return this;
     }
 
     @Override
     public DescribeBuilder addOptional(FrontsTriple t) {
-        getWhereHandler().addOptional(new TriplePath(t.asTriple()));
+        return addOptional(new TriplePath(t.asTriple()));
+    }
+
+    @Override
+    public DescribeBuilder addOptional(Collection<TriplePath> collection) {
+        getWhereHandler().addOptional(collection);
         return this;
     }
 
     @Override
     public DescribeBuilder addOptional(Object s, Object p, Object o) {
-        getWhereHandler().addOptional(makeTriplePath(s, p, o));
+        getWhereHandler().addOptional(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -319,25 +331,30 @@ public class DescribeBuilder extends AbstractQueryBuilder<DescribeBuilder> imple
 
     @Override
     public DescribeBuilder addGraph(Object graph, FrontsTriple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple.asTriple()));
+        addGraph(graph, new TriplePath(triple.asTriple()));
         return this;
     }
 
     @Override
     public DescribeBuilder addGraph(Object graph, Object subject, Object predicate, Object object) {
-        getWhereHandler().addGraph(makeNode(graph), makeTriplePath(subject, predicate, object));
+        getWhereHandler().addGraph(makeNode(graph), makeTriplePaths(subject, predicate, object));
         return this;
     }
 
     @Override
     public DescribeBuilder addGraph(Object graph, Triple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple));
-        return this;
+        return addGraph(graph, new TriplePath(triple));
     }
 
     @Override
     public DescribeBuilder addGraph(Object graph, TriplePath triplePath) {
-        getWhereHandler().addGraph(makeNode(graph), triplePath);
+        getWhereHandler().addGraph(makeNode(graph), Arrays.asList(triplePath));
+        return this;
+    }
+    
+    @Override
+    public DescribeBuilder addGraph(Object graph, Collection<TriplePath> collection) {
+        getWhereHandler().addGraph(makeNode(graph), collection);
         return this;
     }
 
@@ -353,6 +370,10 @@ public class DescribeBuilder extends AbstractQueryBuilder<DescribeBuilder> imple
         return this;
     }
 
+    /*
+     * @deprecated use {@code addWhere(Converters.makeCollection(List.of(Object...)))}, or simply call {@link #addWhere(Object, Object, Object)} passing the collection for one of the objects.
+     */
+    @Deprecated(since="5.0.0")
     @Override
     public Node list(Object... objs) {
         return getWhereHandler().list(objs);
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java
index efc3af28be..2c0a11671c 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java
@@ -17,6 +17,7 @@
  */
 package org.apache.jena.arq.querybuilder;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -302,6 +303,14 @@ public class SelectBuilder extends AbstractQueryBuilder<SelectBuilder> implement
         return this;
     }
 
+    @Override
+    public SelectBuilder addWhere(Collection<TriplePath> collection) {
+        getWhereHandler().addWhere(collection);
+        return this;
+    }
+    
+    
+
     @Override
     public SelectBuilder addWhere(Triple t) {
         getWhereHandler().addWhere(new TriplePath(t));
@@ -316,7 +325,7 @@ public class SelectBuilder extends AbstractQueryBuilder<SelectBuilder> implement
 
     @Override
     public SelectBuilder addWhere(Object s, Object p, Object o) {
-        getWhereHandler().addWhere(makeTriplePath(s, p, o));
+        getWhereHandler().addWhere(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -368,25 +377,29 @@ public class SelectBuilder extends AbstractQueryBuilder<SelectBuilder> implement
 
     @Override
     public SelectBuilder addOptional(TriplePath t) {
-        getWhereHandler().addOptional(t);
+        getWhereHandler().addOptional(Arrays.asList(t));
         return this;
     }
 
     @Override
     public SelectBuilder addOptional(Triple t) {
-        getWhereHandler().addOptional(new TriplePath(t));
-        return this;
+        return addOptional(new TriplePath(t));
     }
 
     @Override
     public SelectBuilder addOptional(FrontsTriple t) {
-        getWhereHandler().addOptional(new TriplePath(t.asTriple()));
+        return addOptional(new TriplePath(t.asTriple()));
+    }
+
+    @Override
+    public SelectBuilder addOptional(Collection<TriplePath> collection) {
+        getWhereHandler().addOptional(collection);
         return this;
     }
 
     @Override
     public SelectBuilder addOptional(Object s, Object p, Object o) {
-        getWhereHandler().addOptional(makeTriplePath(s, p, o));
+        getWhereHandler().addOptional(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -429,28 +442,32 @@ public class SelectBuilder extends AbstractQueryBuilder<SelectBuilder> implement
 
     @Override
     public SelectBuilder addGraph(Object graph, FrontsTriple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple.asTriple()));
-        return this;
+        return addGraph(graph, new TriplePath(triple.asTriple()));
     }
 
     @Override
     public SelectBuilder addGraph(Object graph, Object subject, Object predicate, Object object) {
-        getWhereHandler().addGraph(makeNode(graph), makeTriplePath(subject, predicate, object));
+        getWhereHandler().addGraph(makeNode(graph), makeTriplePaths(subject, predicate, object));
         return this;
     }
 
     @Override
     public SelectBuilder addGraph(Object graph, Triple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple));
-        return this;
+        return addGraph(graph, new TriplePath(triple));
     }
 
     @Override
     public SelectBuilder addGraph(Object graph, TriplePath triplePath) {
-        getWhereHandler().addGraph(makeNode(graph), triplePath);
+        getWhereHandler().addGraph(makeNode(graph), Arrays.asList(triplePath));
         return this;
     }
 
+    @Override
+    public SelectBuilder addGraph(Object graph, Collection<TriplePath> collection) {
+        getWhereHandler().addGraph(makeNode(graph), collection);
+        return this;
+    }
+    
     @Override
     public SelectBuilder addBind(Expr expression, Object var) {
         getWhereHandler().addBind(expression, Converters.makeVar(var));
@@ -468,7 +485,10 @@ public class SelectBuilder extends AbstractQueryBuilder<SelectBuilder> implement
         return handlerBlock.getSelectHandler();
     }
 
-    @Override
+    /*
+     * @deprecated use {@code addWhere(Converters.makeCollection(List.of(Object...)))}, or simply call {@link #addWhere(Object, Object, Object)} passing the collection for one of the objects.
+     */
+    @Deprecated(since="5.0.0")    @Override
     public Node list(Object... objs) {
         return getWhereHandler().list(objs);
     }
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/UpdateBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/UpdateBuilder.java
index b77418d141..4e021e8c3c 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/UpdateBuilder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/UpdateBuilder.java
@@ -254,7 +254,9 @@ public class UpdateBuilder {
      * @param p the predicate object
      * @param o the object object.
      * @return a TriplePath
+     * @deprecatd use {@link #makeTriplePaths(Object, Object, Object)}
      */
+    @Deprecated(since="5.0.0")
     public TriplePath makeTriplePath(Object s, Object p, Object o) {
         final Object po = Converters.makeNodeOrPath(p, prefixHandler.getPrefixes());
         if (po instanceof Path) {
@@ -262,6 +264,21 @@ public class UpdateBuilder {
         }
         return new TriplePath(Triple.create(makeNode(s), (Node) po, makeNode(o)));
     }
+   
+    /**
+     * Make a collection of one or more {@code TriplePath} objects from the objects.
+     *
+     * Uses {@code Converters.makeTriplePaths} to perform the conversions using the prefixes
+     * defined in this UpdateBuilder.
+     *
+     * @param s The subject object
+     * @param p the predicate object
+     * @param o the object object.
+     * @return a collection of {@code TriplePath}s
+     */
+    public Collection<TriplePath> makeTriplePaths(Object s, Object p, Object o) {
+        return Converters.makeTriplePaths(s, p, o, prefixHandler.getPrefixes());
+    }
 
     /**
      * Convert the object to a node.
@@ -310,6 +327,18 @@ public class UpdateBuilder {
         return Converters.quoted(s);
     }
 
+    /**
+     * Converts the {@code s,p,o} triple into a list of Triples.  List will contain multiple
+     * triples if {@code s} or {@code o} are collections.
+     * @param s The subject object
+     * @param p the predicate object.
+     * @param o the object object.
+     * @return A list of triples.
+     */
+    private List<Triple> makeTriples(Object s, Object p, Object o) {
+        return Converters.makeTriples(s, p, o, prefixHandler.getPrefixes());
+    }
+    
     /**
      * Add a quad to the insert statement.
      *
@@ -323,7 +352,8 @@ public class UpdateBuilder {
      * @return this builder for chaining.
      */
     public UpdateBuilder addInsert(Object g, Object s, Object p, Object o) {
-        return addInsert(new Quad(makeNode(g), makeNode(s), makeNode(p), makeNode(o)));
+        List<Triple> lst = makeTriples(s, p, o);
+        return lst.size()>1? addInsert(g, lst) : addInsert(g, lst.get(0));
     }
 
     /**
@@ -350,8 +380,8 @@ public class UpdateBuilder {
      * @return this builder for chaining.
      */
     public UpdateBuilder addInsert(Object s, Object p, Object o) {
-        addInsert(Triple.create(makeNode(s), makeNode(p), makeNode(o)));
-        return this;
+        List<Triple> lst = makeTriples(s, p, o);
+        return lst.size()>1? addInsert(lst) : addInsert(lst.get(0));
     }
 
     /**
@@ -513,7 +543,8 @@ public class UpdateBuilder {
      * @return this builder for chaining.
      */
     public UpdateBuilder addDelete(Object g, Object s, Object p, Object o) {
-        return addDelete(new Quad(makeNode(g), makeNode(s), makeNode(p), makeNode(o)));
+        List<Triple> lst = makeTriples(s, p, o);
+        return lst.size()>1? addDelete(g, lst) : addDelete(g, lst.get(0));
     }
 
     /**
@@ -550,8 +581,8 @@ public class UpdateBuilder {
      * @return this builder for chaining.
      */
     public UpdateBuilder addDelete(Object s, Object p, Object o) {
-        addDelete(Triple.create(makeNode(s), makeNode(p), makeNode(o)));
-        return this;
+        List<Triple> lst = makeTriples(s, p, o);
+        return lst.size()>1? addDelete(lst) : addDelete(lst.get(0));
     }
 
     /**
@@ -849,6 +880,19 @@ public class UpdateBuilder {
         return this;
     }
 
+    /**
+     * Add an optional triple to the where clause
+     *
+     * @param collection The collection of {@code TriplePath} path to add.
+     * @return The Builder for chaining.
+     * @throws IllegalArgumentException If the triple is not a valid triple for a
+     * where clause.
+     */
+    public UpdateBuilder addOptional(Collection<TriplePath> collection) throws IllegalArgumentException {
+        whereProcessor.addOptional(collection);
+        return this;
+    }
+    
     /**
      * Add the contents of a where handler as an optional statement.
      *
@@ -941,7 +985,10 @@ public class UpdateBuilder {
      *
      * @param objs the list of objects for the list.
      * @return the first blank node in the list.
+     * @deprecated use makeList
+     * @see #makeList(Object...)
      */
+    @Deprecated(since="5.0.0")
     public Node list(Object... objs) {
         Node retval = NodeFactory.createBlankNode();
         Node lastObject = retval;
@@ -960,6 +1007,42 @@ public class UpdateBuilder {
 
         return retval;
     }
+    
+    /**
+     * Create a list node from a list of objects as per RDF Collections.
+     *
+     * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#collections
+     *
+     * See {@link AbstractQueryBuilder#makeNode} for conversion of the param values.
+     * <p>
+     * usage:
+     * <ul>
+     * <li>list( param1, param2, param3, ... )</li>
+     * <li>addWhere( list( param1, param2, param3, ... ), p, o )</li>
+     * <li>addOptional( list( param1, param2, param3, ... ), p, o )</li>
+     * </ul>
+     *
+     * @param objs the list of objects for the list.
+     * @return the first blank node in the list.
+     */
+    public Node makeList(Object... objs) {
+        Node retval = NodeFactory.createBlankNode();
+        Node lastObject = retval;
+        for (int i = 0; i < objs.length; i++) {
+            Node n = makeNode(objs[i]);
+            addWhere(new TriplePath(Triple.create(lastObject, RDF.first.asNode(), n)));
+            if (i + 1 < objs.length) {
+                Node nextObject = NodeFactory.createBlankNode();
+                addWhere(new TriplePath(Triple.create(lastObject, RDF.rest.asNode(), nextObject)));
+                lastObject = nextObject;
+            } else {
+                addWhere(new TriplePath(Triple.create(lastObject, RDF.rest.asNode(), RDF.nil.asNode())));
+            }
+
+        }
+
+        return retval;
+    }
 
     /**
      * Adds a triple to the where clause.
@@ -993,7 +1076,8 @@ public class UpdateBuilder {
      * @return The Builder for chaining.
      */
     public UpdateBuilder addWhere(Object s, Object p, Object o) {
-        return addWhere(makeTriplePath(s, p, o));
+        makeTriplePaths(s, p, o).forEach(whereProcessor::addWhere);
+        return this;
     }
 
     /**
@@ -1028,7 +1112,8 @@ public class UpdateBuilder {
      * @return The Builder for chaining.
      */
     public UpdateBuilder addOptional(Object s, Object p, Object o) {
-        return addOptional(makeTriplePath(s, p, o));
+        makeTriplePaths(s, p, o).forEach(whereProcessor::addOptional);
+        return this;
     }
 
     /**
@@ -1154,4 +1239,5 @@ public class UpdateBuilder {
         QuadAcc quadAcc = new QuadAcc(new QBQuadHolder(queryBuilder).getQuads().toList());
         return new UpdateDeleteWhere(quadAcc);
     }
+
 }
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/WhereBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/WhereBuilder.java
index d152a7ddb2..3b05fa7aaa 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/WhereBuilder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/WhereBuilder.java
@@ -18,6 +18,7 @@
 
 package org.apache.jena.arq.querybuilder;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -63,6 +64,12 @@ public class WhereBuilder extends AbstractQueryBuilder<WhereBuilder> implements
         return this;
     }
 
+    @Override
+    public WhereBuilder addWhere(Collection<TriplePath> collection) {
+        getWhereHandler().addWhere(collection);
+        return this;
+    }
+
     @Override
     public WhereBuilder addWhere(FrontsTriple t) {
         return addWhere(t.asTriple());
@@ -70,7 +77,8 @@ public class WhereBuilder extends AbstractQueryBuilder<WhereBuilder> implements
 
     @Override
     public WhereBuilder addWhere(Object s, Object p, Object o) {
-        return addWhere(makeTriplePath(s, p, o));
+        handler.addWhere(makeTriplePaths(s, p, o));
+        return this;
     }
 
     @Override
@@ -125,21 +133,27 @@ public class WhereBuilder extends AbstractQueryBuilder<WhereBuilder> implements
         return this;
     }
 
+    @Override
+    public WhereBuilder addOptional(Collection<TriplePath> collection) {
+        getWhereHandler().addOptional(collection);
+        return this;
+    }
+
     @Override
     public WhereBuilder addOptional(Triple t) {
-        getWhereHandler().addOptional(new TriplePath(t));
+        addOptional(new TriplePath(t));
         return this;
     }
 
     @Override
     public WhereBuilder addOptional(FrontsTriple t) {
-        getWhereHandler().addOptional(new TriplePath(t.asTriple()));
+        addOptional(new TriplePath(t.asTriple()));
         return this;
     }
 
     @Override
     public WhereBuilder addOptional(Object s, Object p, Object o) {
-        getWhereHandler().addOptional(makeTriplePath(s, p, o));
+        getWhereHandler().addOptional(makeTriplePaths(s, p, o));
         return this;
     }
 
@@ -182,28 +196,34 @@ public class WhereBuilder extends AbstractQueryBuilder<WhereBuilder> implements
 
     @Override
     public WhereBuilder addGraph(Object graph, FrontsTriple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple.asTriple()));
+        addGraph(graph, new TriplePath(triple.asTriple()));
         return this;
     }
 
     @Override
     public WhereBuilder addGraph(Object graph, Object subject, Object predicate, Object object) {
-        getWhereHandler().addGraph(makeNode(graph), makeTriplePath(subject, predicate, object));
+        getWhereHandler().addGraph(makeNode(graph), makeTriplePaths(subject, predicate, object));
         return this;
     }
 
     @Override
     public WhereBuilder addGraph(Object graph, Triple triple) {
-        getWhereHandler().addGraph(makeNode(graph), new TriplePath(triple));
+        addGraph(makeNode(graph), new TriplePath(triple));
         return this;
     }
 
     @Override
     public WhereBuilder addGraph(Object graph, TriplePath triplePath) {
-        getWhereHandler().addGraph(makeNode(graph), triplePath);
+        getWhereHandler().addGraph(makeNode(graph), Arrays.asList(triplePath));
         return this;
     }
 
+    @Override
+    public WhereBuilder addGraph(Object graph, Collection<TriplePath> collection) {
+        getWhereHandler().addGraph(makeNode(graph), collection);
+        return this;
+    }
+    
     @Override
     public WhereBuilder addBind(Expr expression, Object var) {
         getWhereHandler().addBind(expression, Converters.makeVar(var));
@@ -216,7 +236,10 @@ public class WhereBuilder extends AbstractQueryBuilder<WhereBuilder> implements
         return this;
     }
 
-    @Override
+    /*
+     * @deprecated use {@code addWhere(Converters.makeCollection(List.of(Object...)))}, or simply call {@link #addWhere(Object, Object, Object)} passing the collection for one of the objects.
+     */
+    @Deprecated(since="5.0.0")    @Override
     public Node list(Object... objs) {
         return getWhereHandler().list(objs);
     }
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/WhereClause.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/WhereClause.java
index 5cae86d6ae..1c5dcf914e 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/WhereClause.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/WhereClause.java
@@ -43,7 +43,7 @@ public interface WhereClause<T extends AbstractQueryBuilder<T>> {
     /**
      * Adds a triple to the where clause.
      *
-     * @param t The triple path to add
+     * @param t The triple to add
      * @return This Builder for chaining.
      */
     public T addWhere(Triple t);
@@ -55,6 +55,15 @@ public interface WhereClause<T extends AbstractQueryBuilder<T>> {
      * @return This Builder for chaining.
      */
     public T addWhere(TriplePath t);
+    
+    /**
+     * Adds a collections of triple paths to the where clause.
+     *
+     * @param collection The collection of triple paths to add
+     * @return This Builder for chaining.
+     */
+    public T addWhere(Collection<TriplePath> collection);
+
 
     /**
      * Adds a triple to the where clause.
@@ -227,6 +236,14 @@ public interface WhereClause<T extends AbstractQueryBuilder<T>> {
      * @return This Builder for chaining.
      */
     public T addOptional(TriplePath t);
+    
+    /**
+     * Adds a collection of triple paths as the optional clauses.
+     *
+     * @param collection The collection of triple paths to add
+     * @return This Builder for chaining.
+     */
+    public T addOptional(Collection<TriplePath> collection);
 
     /**
      * Adds an optional triple as to the where clause.
@@ -357,6 +374,15 @@ public interface WhereClause<T extends AbstractQueryBuilder<T>> {
      * @return This builder for chaining.
      */
     public T addGraph(Object graph, TriplePath triplePath);
+    
+    /**
+     * Adds a collection of triple paths as the optional clauses.
+     *
+     * @param graph The iri or variable identifying the graph.
+     * @param collection The collection of triple paths to add
+     * @return This Builder for chaining.
+     */
+    public T addGraph(Object graph, Collection<TriplePath> collection);
 
     /**
      * Add a bind statement to the query *
@@ -401,7 +427,9 @@ public interface WhereClause<T extends AbstractQueryBuilder<T>> {
      *
      * @param objs the list of objects for the list.
      * @return the first blank node in the list.
+     * @deprecated use {@code addWhere(Converters.makeCollection(List.of(Object...)))}, or simply call {@link #addWhere(Object, Object, Object)} passing the collection for one of the objects.
      */
+    @Deprecated(since="5.0.0")
     public Node list(Object... objs);
 
     /**
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
index 565cc13f8b..76582a1787 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
@@ -189,11 +189,11 @@ public class WhereHandler implements Handler {
                         t.getSubject()));
             }
             if (!validPredicate) {
-                sb.append(String.format("Predicate (%s) must be a Path, URI , variable, or a wildcard. %n",
+                sb.append(String.format("Predicate (%s) must be a Path, URI, variable, or a wildcard. %n",
                         t.getPredicate()));
             }
             if (!validObject) {
-                sb.append(String.format("Object (%s) must be a URI, literal, blank, , variable, or a wildcard. %n",
+                sb.append(String.format("Object (%s) must be a URI, literal, blank, variable, or a wildcard. %n",
                         t.getObject()));
             }
             if (!validSubject || !validPredicate) {
@@ -227,13 +227,24 @@ public class WhereHandler implements Handler {
                 ElementPathBlock epb = (ElementPathBlock) e;
                 epb.addTriple(t);
             } else {
-                ElementPathBlock etb = new ElementPathBlock();
-                etb.addTriple(t);
-                eg.addElement(etb);
+                ElementPathBlock epb = new ElementPathBlock();
+                epb.addTriple(t);
+                eg.addElement(epb);
             }
 
         }
     }
+    
+    /**
+     * Add the triple path to the where clause
+     *
+     * @param t The triple path to add.
+     * @throws IllegalArgumentException If the triple path is not a valid triple
+     * path for a where clause.
+     */
+    public void addWhere(Collection<TriplePath> t) throws IllegalArgumentException {
+        t.forEach(this::addWhere);
+    }
 
     /**
      * Add the triple path to the where clause
@@ -254,9 +265,19 @@ public class WhereHandler implements Handler {
      * where clause.
      */
     public void addOptional(TriplePath t) throws IllegalArgumentException {
-        testTriple(t);
+        addOptional(Arrays.asList(t));
+    }
+    
+    /**
+     * Add an optional triple to the where clause
+     *
+     * @param t The triple path to add.
+     * @throws IllegalArgumentException If the triple is not a valid triple for a
+     * where clause.
+     */
+    public void addOptional(Collection<TriplePath> t) throws IllegalArgumentException {
         ElementPathBlock epb = new ElementPathBlock();
-        epb.addTriple(t);
+        t.forEach( tp -> {testTriple(tp);epb.addTriple(tp);});
         ElementOptional opt = new ElementOptional(epb);
         getClause().addElement(opt);
     }
@@ -381,6 +402,20 @@ public class WhereHandler implements Handler {
         epb.addTriple(subQuery);
         getClause().addElement(new ElementNamedGraph(graph, epb));
     }
+    
+    /**
+     * Add a graph to the where clause.
+     *
+     * Short hand for graph { s, p, o }
+     *
+     * @param graph The name of the graph.
+     * @param subQuery A triple path to add to the graph.
+     */
+    public void addGraph(Node graph, Collection<TriplePath> subQuery) {
+        ElementPathBlock epb = new ElementPathBlock();
+        subQuery.forEach(epb::addTriple);
+        getClause().addElement(new ElementNamedGraph(graph, epb));
+    }
 
     /**
      * Add a binding to the where clause.
@@ -445,7 +480,9 @@ public class WhereHandler implements Handler {
      *
      * @param objs the list of objects for the list.
      * @return the first blank node in the list.
+     * @deprecated use {code Converters.makeCollection(List.of(Object...))}.
      */
+    @Deprecated(since="5.0.0")
     public Node list(Object... objs) {
         Node retval = NodeFactory.createBlankNode();
         Node lastObject = retval;
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/AbstractRewriter.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/AbstractRewriter.java
index 3531a8d1f3..ceb4bff159 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/AbstractRewriter.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/AbstractRewriter.java
@@ -100,7 +100,7 @@ public class AbstractRewriter<T> {
      * @param t The triple path to rewrite.
      * @return the triple path after rewriting.
      */
-    protected final TriplePath rewrite(TriplePath t) {
+    public TriplePath rewrite(TriplePath t) {
         if (t.getPath() == null) {
             return new TriplePath(
                     Triple.create(changeNode(t.getSubject()), changeNode(t.getPredicate()), changeNode(t.getObject())));
@@ -116,7 +116,7 @@ public class AbstractRewriter<T> {
      * @param t The triple to rewrite.
      * @return The rewritten triple.
      */
-    protected final Triple rewrite(Triple t) {
+    public final Triple rewrite(Triple t) {
         return Triple.create(changeNode(t.getSubject()), changeNode(t.getPredicate()), changeNode(t.getObject()));
     }
 
@@ -127,7 +127,7 @@ public class AbstractRewriter<T> {
      * @param n The node to rewrite.
      * @return the rewritten node.
      */
-    protected final Node changeNode(Node n) {
+    protected Node changeNode(Node n) {
         if (n == null) {
             return n;
         }
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/WhereQuadHolder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/WhereQuadHolder.java
index 83fac9e6cf..9a3299786d 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/WhereQuadHolder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/WhereQuadHolder.java
@@ -17,6 +17,7 @@
  */
 package org.apache.jena.arq.querybuilder.updatebuilder;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -221,6 +222,17 @@ public class WhereQuadHolder implements QuadHolder {
         }
     }
 
+    /**
+     * Add a {@code TriplePath} collection to the where clause
+     *
+     * @param t The triple path to add.
+     * @throws IllegalArgumentException If the triple path is not a valid triple
+     * path for a where clause.
+     */
+    public void addWhere(Collection<TriplePath> t) throws IllegalArgumentException {
+        t.forEach(this::addWhere);
+    }
+    
     /**
      * Add an optional triple to the where clause
      *
@@ -235,6 +247,20 @@ public class WhereQuadHolder implements QuadHolder {
         ElementOptional opt = new ElementOptional(epb);
         getClause().addElement(opt);
     }
+    
+    /**
+     * Add an optional TriplePath to the where clause
+     *
+     * @param t The triple path to add.
+     * @throws IllegalArgumentException If the triple is not a valid triple for a
+     * where clause.
+     */
+    public void addOptional(Collection<TriplePath> t) throws IllegalArgumentException {
+        ElementPathBlock epb = new ElementPathBlock();
+        t.forEach( tp -> {testTriple(tp);epb.addTriple(tp);});
+        ElementOptional opt = new ElementOptional(epb);
+        getClause().addElement(opt);
+    }
 
     /**
      * Add the contents of a where handler as an optional statement.
@@ -379,7 +405,9 @@ public class WhereQuadHolder implements QuadHolder {
      *
      * @param objs the list of objects for the list.
      * @return the first blank node in the list.
+     * @deprecated use {@code Converters.makeCollection(List.of(Object...))}
      */
+    @Deprecated(since="5.0.0")
     public Node list(Object... objs) {
         Node retval = NodeFactory.createBlankNode();
         Node lastObject = retval;
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/TestAbstractQueryBuilder.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/TestAbstractQueryBuilder.java
new file mode 100644
index 0000000000..08439f8cab
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/TestAbstractQueryBuilder.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq;
+
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.arq.querybuilder.handlers.HandlerBlock;
+import org.apache.jena.query.QueryFactory;
+
+/**
+ * Class to create AbstractQueryBuilders for AbstractQueryBuilder parameter tests.
+ */
+@SuppressWarnings("rawtypes")
+public class TestAbstractQueryBuilder extends AbstractQueryBuilder {
+    
+    public HandlerBlock handlerBlock = new HandlerBlock( QueryFactory.create());
+
+    @Override
+    public HandlerBlock getHandlerBlock() {
+        return handlerBlock;
+    }
+
+}
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilderTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilderTest.java
index faa20e7d1b..32c804434e 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilderTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilderTest.java
@@ -30,8 +30,8 @@ import org.apache.jena.arq.querybuilder.handlers.HandlerBlock;
 import org.apache.jena.datatypes.xsd.XSDDatatype;
 import org.apache.jena.graph.Node;
 import org.apache.jena.graph.NodeFactory;
-import org.apache.jena.graph.impl.LiteralLabel;
-import org.apache.jena.graph.impl.LiteralLabelFactory;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.sparql.core.TriplePath;
 import org.apache.jena.sparql.core.Var;
 import org.apache.jena.vocabulary.RDF;
 import org.junit.Before;
@@ -131,9 +131,47 @@ public class AbstractQueryBuilderTest {
         assertTrue(result.contains(NodeFactory.createURI("one")));
 
         Node n = NodeFactory.createLiteral("5", XSDDatatype.XSDint);
-        LiteralLabel ll = LiteralLabelFactory.createTypedLiteral(Integer.valueOf(5));
         assertTrue(result.contains(n));
 
     }
+    
+    private void assertTripleMatch(Triple expected, Triple actual) {
+        if (!expected.matches(actual)) {
+            fail("expected: "+expected+" actual: "+actual);
+        }
+    }
+    
+    private void assertTripleMatch(Triple expected, TriplePath actual) {
+        assertTripleMatch(expected, actual.asTriple());
+    }
+    
+    @Test
+    public void testMakeTriplePaths() {
+        List<Object> list = new ArrayList<Object>();
+        list.add(RDF.type);
+        builder.addPrefix("demo", "http://example.com/");
+        list.add("demo:type");
+        list.add("<one>");
+        list.add(Integer.valueOf(5));
+        
+        Triple[] expected = {
+            Triple.create(Node.ANY, RDF.first.asNode(), RDF.type.asNode()),
+            Triple.create(Node.ANY, RDF.rest.asNode(), Node.ANY),
+            Triple.create(Node.ANY, RDF.first.asNode(), NodeFactory.createURI("http://example.com/type")),
+            Triple.create(Node.ANY, RDF.rest.asNode(), Node.ANY),
+            Triple.create(Node.ANY, RDF.first.asNode(), NodeFactory.createURI("one")), 
+            Triple.create(Node.ANY, RDF.rest.asNode(), Node.ANY), 
+            Triple.create(Node.ANY, RDF.first.asNode(), NodeFactory.createLiteral("5", XSDDatatype.XSDint)),
+            Triple.create(Node.ANY, RDF.rest.asNode(), RDF.nil.asNode()),
+            Triple.create(Var.alloc("s"), Var.alloc("p"), Node.ANY),
+        };
+
+        List<TriplePath> result = builder.makeTriplePaths("?s", "?p", list);
+
+        assertEquals(expected.length, result.size());
+        for (int i=0;i<expected.length;i++) {
+            assertTripleMatch( expected[i], result.get(i));
+        }
+    }
 
 }
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AskBuilderTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AskBuilderTest.java
index 76df142fe0..1bcaa7811e 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AskBuilderTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AskBuilderTest.java
@@ -99,6 +99,7 @@ public class AskBuilderTest extends AbstractRegexpBasedTest {
                 query);
     }
 
+    @SuppressWarnings("deprecation")
     @Test
     public void testList() {
         builder.addWhere(builder.list("<one>", "?two", "'three'"), "<foo>", "<bar>");
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConstructBuilderTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConstructBuilderTest.java
index 9eb7c72434..87bba2a9e4 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConstructBuilderTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConstructBuilderTest.java
@@ -102,6 +102,7 @@ public class ConstructBuilderTest extends AbstractRegexpBasedTest {
                 query);
     }
 
+    @SuppressWarnings("deprecation")
     @Test
     public void testList() {
         builder.addWhere(builder.list("<one>", "?two", "'three'"), "<foo>", "<bar>");
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConvertersTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConvertersTest.java
index c1c64276d9..e3c3b8ebf8 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConvertersTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConvertersTest.java
@@ -18,7 +18,11 @@
 
 package org.apache.jena.arq.querybuilder;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -34,11 +38,15 @@ import org.apache.jena.datatypes.xsd.XSDDatatype;
 import org.apache.jena.graph.FrontsNode;
 import org.apache.jena.graph.Node;
 import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.graph.Triple;
 import org.apache.jena.reasoner.rulesys.Node_RuleVariable;
 import org.apache.jena.shared.PrefixMapping;
+import org.apache.jena.sparql.core.TriplePath;
 import org.apache.jena.sparql.core.Var;
 import org.apache.jena.sparql.expr.ExprVar;
+import org.apache.jena.sparql.path.P_Link;
 import org.apache.jena.sparql.path.Path;
+import org.apache.jena.sparql.util.NodeIsomorphismMap;
 import org.apache.jena.vocabulary.RDF;
 import org.junit.After;
 import org.junit.Test;
@@ -293,6 +301,121 @@ public class ConvertersTest {
         assertEquals("\"'I am the \"one\"'\"", Converters.quoted("'I am the \"one\"'"));
     }
 
+    private Node getSubject(Object o) {
+        if (o instanceof Triple) {
+            return ((Triple) o).getSubject();
+        }
+        if (o instanceof TriplePath) {
+            return ((TriplePath) o).getSubject();
+        }
+        throw new IllegalArgumentException("o must be Triple or TriplePath");
+    }
+
+    private static List<Object> theTestList = List.of("<one>", "(<two>)", "('an' <embedded> \"array\")", Node.ANY);
+
+    private void assertExpectedTripleList(List<?> lst) {
+
+        assertTriplePath(Triple.create(Node.ANY, RDF.first.asNode(), NodeFactory.createURI("one")), lst.get(0));
+        assertTriplePath(Triple.create(getSubject(lst.get(0)), RDF.rest.asNode(), getSubject(lst.get(4))), lst.get(1));
+        // sublist 1
+        assertTriplePath(Triple.create(Node.ANY, RDF.first.asNode(), NodeFactory.createURI("two")), lst.get(2));
+        assertTriplePath(Triple.create(getSubject(lst.get(2)), RDF.rest.asNode(), RDF.nil.asNode()), lst.get(3));
+        // end of sublist 1
+        assertTriplePath(Triple.create(Node.ANY, RDF.first.asNode(), getSubject(lst.get(2))), lst.get(4));
+        assertTriplePath(Triple.create(getSubject(lst.get(4)), RDF.rest.asNode(), getSubject(lst.get(12))), lst.get(5));
+        // sublist 2
+        assertTriplePath(Triple.create(Node.ANY, RDF.first.asNode(), NodeFactory.createLiteral("an")), lst.get(6));
+        assertTriplePath(Triple.create(getSubject(lst.get(6)), RDF.rest.asNode(), getSubject(lst.get(8))), lst.get(7));
+        assertTriplePath(Triple.create(Node.ANY, RDF.first.asNode(), NodeFactory.createURI("embedded")), lst.get(8));
+        assertTriplePath(Triple.create(getSubject(lst.get(8)), RDF.rest.asNode(), getSubject(lst.get(10))), lst.get(9));
+        assertTriplePath(Triple.create(Node.ANY, RDF.first.asNode(), NodeFactory.createLiteral("array")), lst.get(10));
+        assertTriplePath(Triple.create(getSubject(lst.get(10)), RDF.rest.asNode(), RDF.nil.asNode()), lst.get(11));
+        // end of sublist 2
+        assertTriplePath(Triple.create(Node.ANY, RDF.first.asNode(), getSubject(lst.get(6))), lst.get(12));
+        assertTriplePath(Triple.create(getSubject(lst.get(12)), RDF.rest.asNode(), getSubject(lst.get(14))),
+                lst.get(13));
+        assertTriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY), lst.get(14));
+        assertTriplePath(Triple.create(getSubject(lst.get(14)), RDF.rest.asNode(), RDF.nil.asNode()), lst.get(15));
+    }
+
+    @Test
+    public void makeCollectionTriplesTest() {
+        PrefixMapping pMap = PrefixMapping.Factory.create();
+        pMap.setNsPrefixes(PrefixMapping.Standard);
+
+        List<Triple> lst = Converters.makeCollectionTriples(theTestList, pMap);
+        assertEquals(16, lst.size());
+        assertExpectedTripleList(lst);
+    }
+
+    private Triple asTriple(Object o) {
+        if (o instanceof Triple) {
+            return (Triple) o;
+        }
+        if (o instanceof TriplePath) {
+            return ((TriplePath) o).asTriple();
+        }
+        throw new IllegalArgumentException("o must be Triple or TriplePath");
+    }
+
+    private TriplePath asTriplePath(Object o) {
+        if (o instanceof Triple) {
+            return new TriplePath((Triple) o);
+        }
+        if (o instanceof TriplePath) {
+            return (TriplePath) o;
+        }
+        throw new IllegalArgumentException("o must be Triple or TriplePath");
+    }
+
+    private void assertTriplePath(TriplePath expected, Object actual) {
+        String errMsg = String.format("Expected '%s', actual '%s'", expected, actual);
+        if (expected.isTriple()) {
+            assertTrue(errMsg, expected.asTriple().matches(asTriple(actual)));
+        } else {
+            assertTrue(errMsg, expected.getSubject().matches(asTriplePath(actual).getSubject()));
+            assertTrue(errMsg, expected.getObject().matches(asTriplePath(actual).getObject()));
+            assertTrue(errMsg, expected.getPath().equalTo(asTriplePath(actual).getPath(), new NodeIsomorphismMap()));
+        }
+    }
+
+    private void assertTriplePath(Triple expected, Object actual) {
+        String errMsg = String.format("Expected '%s', actual '%s'", expected, actual);
+        assertTrue(errMsg, expected.matches(asTriple(actual)));
+    }
+
+    @Test
+    public void makeCollectionTriplePathsTest() {
+        PrefixMapping pMap = PrefixMapping.Factory.create();
+        pMap.setNsPrefixes(PrefixMapping.Standard);
+        List<TriplePath> lst = Converters.makeCollectionTriplePaths(theTestList, pMap);
+        assertEquals(16, lst.size());
+        assertExpectedTripleList(lst);
+    }
+
+    @Test
+    public void makeTriplePathsTest() {
+        PrefixMapping pMap = PrefixMapping.Factory.create();
+        Path p = new P_Link(NodeFactory.createURI("foo"));
+
+        List<TriplePath> result = Converters.makeTriplePaths("<s>", p, theTestList, pMap);
+        assertExpectedTripleList(result);
+        assertEquals(17, result.size());
+        assertTriplePath(new TriplePath(NodeFactory.createURI("s"), p, result.get(0).getSubject()), result.get(16));
+    }
+
+    @Test
+    public void makeTriplesTest() {
+        PrefixMapping pMap = PrefixMapping.Factory.create();
+
+        List<Triple> result = Converters.makeTriples("<s>", "<p>", theTestList, pMap);
+        assertExpectedTripleList(result);
+        assertEquals(17, result.size());
+        assertTriplePath(
+                Triple.create(NodeFactory.createURI("s"), NodeFactory.createURI("p"), result.get(0).getSubject()),
+                result.get(16));
+    }
+
     private class NodeFront implements FrontsNode {
         Node n;
 
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderTest.java
index 2183f7b646..de96b2ea53 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderTest.java
@@ -36,7 +36,6 @@ import org.apache.jena.rdf.model.ModelFactory;
 import org.apache.jena.rdf.model.Resource;
 import org.apache.jena.sparql.core.TriplePath;
 import org.apache.jena.sparql.core.Var;
-import org.apache.jena.sparql.lang.sparql_11.ParseException;
 import org.apache.jena.sparql.syntax.ElementPathBlock;
 import org.apache.jena.vocabulary.RDF;
 import org.apache.jena.vocabulary.XSD;
@@ -55,7 +54,7 @@ public class SelectBuilderTest extends AbstractRegexpBasedTest {
     @Test
     public void testSelectAsterisk() {
         builder.addVar("*").addWhere("?s", "?p", "?o");
-
+        
         assertContainsRegex(SELECT + "\\*" + SPACE + WHERE + OPEN_CURLY + var("s") + SPACE + var("p") + SPACE + var("o")
                 + OPT_SPACE + CLOSE_CURLY, builder.buildString());
 
@@ -126,14 +125,13 @@ public class SelectBuilderTest extends AbstractRegexpBasedTest {
     @Test
     public void testNoVars() {
         builder.addWhere("?s", "?p", "?o");
-        String query = builder.buildString();
-
-        assertContainsRegex(SELECT + "\\*" + SPACE, query);
+        Query q = builder.build();
+        assertTrue( q.isQueryResultStar() );
     }
 
+    @SuppressWarnings("deprecation")
     @Test
     public void testList() {
-
         builder.addVar("*").addWhere(builder.list("<one>", "?two", "'three'"), "<foo>", "<bar>");
         Query query = builder.build();
 
@@ -175,7 +173,7 @@ public class SelectBuilderTest extends AbstractRegexpBasedTest {
     }
 
     @Test
-    public void testAggregatorsInSelect() throws ParseException {
+    public void testAggregatorsInSelect() {
         builder.addVar("?x").addVar("count(*)", "?c").addWhere("?x", "?p", "?o").addGroupBy("?x");
 
         Model m = ModelFactory.createDefaultModel();
@@ -218,7 +216,7 @@ public class SelectBuilderTest extends AbstractRegexpBasedTest {
     }
 
     @Test
-    public void testAggregatorsInSubQuery() throws ParseException {
+    public void testAggregatorsInSubQuery() {
 
         Model m = ModelFactory.createDefaultModel();
         Resource r = m.createResource("urn:one");
@@ -250,7 +248,7 @@ public class SelectBuilderTest extends AbstractRegexpBasedTest {
     }
 
     @Test
-    public void testVarReplacementInSubQuery() throws ParseException {
+    public void testVarReplacementInSubQuery() {
 
         Model m = ModelFactory.createDefaultModel();
         Resource r = m.createResource("urn:one");
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/SolutionModifierTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/SolutionModifierTest.java
index 2180e5acb9..e3011486eb 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/SolutionModifierTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/SolutionModifierTest.java
@@ -37,7 +37,6 @@ import org.apache.jena.sparql.expr.E_Random;
 import org.apache.jena.sparql.expr.Expr;
 import org.apache.jena.sparql.expr.ExprVar;
 import org.apache.jena.sparql.expr.nodevalue.NodeValueInteger;
-import org.apache.jena.sparql.lang.sparql_11.ParseException;
 import org.junit.After;
 import org.junit.Assert;
 import org.xenei.junit.contract.Contract;
@@ -297,7 +296,7 @@ public class SolutionModifierTest<T extends SolutionModifierClause<?>> extends A
     }
 
     @ContractTest
-    public void testAddHavingString() throws ParseException {
+    public void testAddHavingString() {
         SolutionModifierClause<?> solutionModifier = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = solutionModifier.addHaving("?foo<10");
 
@@ -334,7 +333,7 @@ public class SolutionModifierTest<T extends SolutionModifierClause<?>> extends A
     }
 
     @ContractTest
-    public void testAddHavingObject() throws ParseException {
+    public void testAddHavingObject() {
         SolutionModifierClause<?> solutionModifier = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = solutionModifier.addHaving(Var.alloc("foo"));
         
@@ -361,7 +360,7 @@ public class SolutionModifierTest<T extends SolutionModifierClause<?>> extends A
     }
 
     @ContractTest
-    public void testAddHavingExpr() throws ParseException {
+    public void testAddHavingExpr() {
         SolutionModifierClause<?> solutionModifier = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = solutionModifier.addHaving(new E_Random());
         
@@ -468,7 +467,7 @@ public class SolutionModifierTest<T extends SolutionModifierClause<?>> extends A
     }
 
     @ContractTest
-    public void testSetVarsHaving() throws ParseException {
+    public void testSetVarsHaving() {
         Var v = Var.alloc("v");
         SolutionModifierClause<?> solutionModifier = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = solutionModifier.addHaving("?v");
@@ -484,7 +483,7 @@ public class SolutionModifierTest<T extends SolutionModifierClause<?>> extends A
     }
 
     @ContractTest
-    public void testSetVarsHaving_Node_Variable() throws ParseException {
+    public void testSetVarsHaving_Node_Variable() {
         Node v = NodeFactory.createVariable("v");
         SolutionModifierClause<?> solutionModifier = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = solutionModifier.addHaving(v);
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/WhereClauseTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/WhereClauseTest.java
index 14824a6792..c2cd83338f 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/WhereClauseTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/WhereClauseTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.*;
 
+import org.apache.jena.arq.TestAbstractQueryBuilder;
 import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
 import org.apache.jena.arq.querybuilder.SelectBuilder;
 import org.apache.jena.arq.querybuilder.WhereBuilder;
@@ -44,7 +45,6 @@ import org.apache.jena.sparql.expr.E_Random;
 import org.apache.jena.sparql.expr.Expr;
 import org.apache.jena.sparql.expr.ExprVar;
 import org.apache.jena.sparql.expr.nodevalue.NodeValueInteger;
-import org.apache.jena.sparql.lang.sparql_11.ParseException;
 import org.apache.jena.sparql.path.P_Link;
 import org.apache.jena.sparql.path.P_Seq;
 import org.apache.jena.sparql.path.Path;
@@ -59,7 +59,7 @@ import org.xenei.junit.contract.IProducer;
 @Contract(WhereClause.class)
 public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTest {
 
-    // the producer we will user
+    // the producer we will use
     private IProducer<T> producer;
 
     @Contract.Inject
@@ -78,7 +78,7 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
     }
 
     @ContractTest
-    public void testAddWhereStrings() {
+    public void testAddWhere3Objects() {
         WhereClause<?> whereClause = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = whereClause.addWhere("<one>", "<two>", "three");
 
@@ -91,6 +91,102 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
         builder.build().getQueryPattern().visit(visitor);
         assertTrue(visitor.matching);
     }
+    
+
+    @ContractTest
+    public void testAddWhereAbstractQueryBuilder() {
+        WhereClause<?> whereClause = getProducer().newInstance();
+        TriplePath tp = new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"), NodeFactory.createURI("three")));
+
+        TestAbstractQueryBuilder abstractQueryBuilder = new TestAbstractQueryBuilder();
+        abstractQueryBuilder.getHandlerBlock().getWhereHandler().addWhere(tp);
+        AbstractQueryBuilder<?> builder = whereClause.addWhere(abstractQueryBuilder);
+        
+        ElementPathBlock epb = new ElementPathBlock();
+        epb.addTriplePath(tp);
+        WhereValidator visitor = new WhereValidator(epb);
+        builder.build().getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
+    
+    @ContractTest
+    public void testAddWhereTriplePath() {
+        WhereClause<?> whereClause = getProducer().newInstance();
+        PrefixMapping pmap = new PrefixMappingImpl();
+        pmap.setNsPrefix("ts", "urn:test:");
+        Path path = PathParser.parse("ts:two/ts:dos", pmap);
+        TriplePath first = new TriplePath(NodeFactory.createURI("one"), path, NodeFactory.createURI("three"));
+        
+        AbstractQueryBuilder<?> builder = whereClause
+                .addWhere(first);
+
+        ElementPathBlock epb = new ElementPathBlock();
+        epb.addTriplePath(first);
+
+        WhereValidator visitor = new WhereValidator(epb);
+        builder.build().getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
+    
+
+    @ContractTest
+    public void testAddWhereTriple() {
+        WhereClause<?> whereClause = getProducer().newInstance();
+        Triple triple = Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"), NodeFactory.createURI("three"));
+
+        AbstractQueryBuilder<?> builder = whereClause
+                .addWhere(triple);
+
+        ElementPathBlock epb = new ElementPathBlock();
+        epb.addTriple(triple);
+
+        WhereValidator visitor = new WhereValidator(epb);
+        builder.build().getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
+
+    @ContractTest
+    public void testAddWhereFrontsTriple() {
+        WhereClause<?> whereClause = getProducer().newInstance();
+        Triple triple = Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"), NodeFactory.createURI("three"));
+        FrontsTriple front = new FrontsTriple() {
+
+            @Override
+            public Triple asTriple() {
+                return triple;
+            }};
+        
+        AbstractQueryBuilder<?> builder = whereClause
+                .addWhere(front);
+
+        ElementPathBlock epb = new ElementPathBlock();
+        epb.addTriple(triple);
+
+        WhereValidator visitor = new WhereValidator(epb);
+        builder.build().getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
+
+    @ContractTest
+    public void testAddWhereTriplePathCollection() {
+        WhereClause<?> whereClause = getProducer().newInstance();
+        PrefixMapping pmap = new PrefixMappingImpl();
+        pmap.setNsPrefix("ts", "urn:test:");
+        Path path = PathParser.parse("ts:two/ts:dos", pmap);
+        TriplePath first = new TriplePath(NodeFactory.createURI("one"), path, NodeFactory.createURI("three"));
+        TriplePath second = new TriplePath(NodeFactory.createURI("for"), path, NodeFactory.createURI("six"));
+
+        AbstractQueryBuilder<?> builder = whereClause
+                .addWhere(List.of(first, second));
+
+        ElementPathBlock epb = new ElementPathBlock();
+        epb.addTriplePath(first);
+        epb.addTriplePath(second);
+
+        WhereValidator visitor = new WhereValidator(epb);
+        builder.build().getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
 
     @ContractTest
     public void testAddWhereWhereClause() {
@@ -196,6 +292,28 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
         assertTrue(visitor.matching);
     }
 
+    @ContractTest
+    public void testAddOptionalTriplePathCollection() {
+        WhereClause<?> whereClause = getProducer().newInstance();
+        PrefixMapping pmap = new PrefixMappingImpl();
+        pmap.setNsPrefix("ts", "urn:test:");
+        Path path = PathParser.parse("ts:two/ts:dos", pmap);
+        TriplePath first = new TriplePath(NodeFactory.createURI("one"), path, NodeFactory.createURI("three"));
+        TriplePath second = new TriplePath(NodeFactory.createURI("for"), path, NodeFactory.createURI("six"));
+
+        AbstractQueryBuilder<?> builder = whereClause
+                .addOptional(List.of(first, second));
+
+        ElementPathBlock epb = new ElementPathBlock();
+        ElementOptional optional = new ElementOptional(epb);
+        epb.addTriplePath(first);
+        epb.addTriplePath(second);
+
+        WhereValidator visitor = new WhereValidator(optional);
+        builder.build().getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
+    
     @ContractTest
     public void testAddOptionalObjectsWithPath() {
         WhereClause<?> whereClause = getProducer().newInstance();
@@ -275,7 +393,7 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
     }
 
     @ContractTest
-    public void testAddFilter() throws ParseException {
+    public void testAddFilter() {
         WhereClause<?> whereClause = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = whereClause.addFilter("?one<10");
 
@@ -437,7 +555,7 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
     }
 
     @ContractTest
-    public void testSetVarsInFilter() throws ParseException {
+    public void testSetVarsInFilter() {
         WhereClause<?> whereClause = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = whereClause.addFilter("?one < ?v");
 
@@ -697,7 +815,7 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
     }
 
     @ContractTest
-    public void testBindStringVar() throws ParseException {
+    public void testBindStringVar() {
         Var v = Var.alloc("foo");
         WhereClause<?> whereClause = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = whereClause.addBind("rand()", v);
@@ -719,7 +837,7 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
     }
 
     @ContractTest
-    public void testBindStringVar_Node_Variable() throws ParseException {
+    public void testBindStringVar_Node_Variable() {
         Node v = NodeFactory.createVariable("foo");
         WhereClause<?> whereClause = getProducer().newInstance();
         AbstractQueryBuilder<?> builder = whereClause.addBind("rand()", v);
@@ -780,6 +898,7 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
 
     }
 
+    @SuppressWarnings("deprecation")
     @ContractTest
     public void testList() {
         WhereClause<?> whereClause = getProducer().newInstance();
@@ -832,7 +951,25 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
     }
 
     @ContractTest
-    public void testAddGraph_frontsTriple() {
+    public void testAddGraphAbstractQueryBuilder() {
+        WhereClause<?> whereClause = getProducer().newInstance();
+        TriplePath tp = new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"), NodeFactory.createURI("three")));
+
+        TestAbstractQueryBuilder abstractQueryBuilder = new TestAbstractQueryBuilder();
+        abstractQueryBuilder.getHandlerBlock().getWhereHandler().addWhere(tp);
+        AbstractQueryBuilder<?> builder = whereClause.addGraph( "<g>", abstractQueryBuilder);
+        
+        ElementPathBlock epb = new ElementPathBlock();
+        ElementNamedGraph eng = new ElementNamedGraph(NodeFactory.createURI("g"), epb);
+        
+        epb.addTriplePath(tp);
+        WhereValidator visitor = new WhereValidator(eng);
+        builder.build().getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
+    
+    @ContractTest
+    public void testAddGraphFrontsTriple() {
         final Node s = NodeFactory.createURI("s");
         final Node p = NodeFactory.createURI("p");
         final Node o = NodeFactory.createURI("o");
@@ -877,7 +1014,7 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
     }
 
     @ContractTest
-    public void testAddGraph_triple() {
+    public void testAddGraphTriple() {
         final Node s = NodeFactory.createURI("s");
         final Node p = NodeFactory.createURI("p");
         final Node o = NodeFactory.createURI("o");
@@ -896,7 +1033,7 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
     }
 
     @ContractTest
-    public void testAddGraph_triplePath() {
+    public void testAddGraphTriplePath() {
         final Node s = NodeFactory.createURI("s");
         final Node p = NodeFactory.createURI("p");
         final Node o = NodeFactory.createURI("o");
@@ -914,6 +1051,28 @@ public class WhereClauseTest<T extends WhereClause<?>> extends AbstractClauseTes
         query.getQueryPattern().visit(visitor);
         assertTrue(visitor.matching);
     }
+    
+    @ContractTest
+    public void testAddGraphTriplePathCollection() {
+        WhereClause<?> whereClause = getProducer().newInstance();
+        PrefixMapping pmap = new PrefixMappingImpl();
+        pmap.setNsPrefix("ts", "urn:test:");
+        Path path = PathParser.parse("ts:two/ts:dos", pmap);
+        TriplePath first = new TriplePath(NodeFactory.createURI("one"), path, NodeFactory.createURI("three"));
+        TriplePath second = new TriplePath(NodeFactory.createURI("for"), path, NodeFactory.createURI("six"));
+
+        AbstractQueryBuilder<?> builder = whereClause
+                .addGraph("<g>", List.of(first, second));
+
+        ElementPathBlock epb = new ElementPathBlock();
+        ElementNamedGraph eng = new ElementNamedGraph(NodeFactory.createURI("g"), epb);
+        epb.addTriplePath(first);
+        epb.addTriplePath(second);
+
+        WhereValidator visitor = new WhereValidator(eng);
+        builder.build().getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
 
     @ContractTest
     public void testAddWhereValueVar_var() {
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/SolutionModifierHandlerTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/SolutionModifierHandlerTest.java
index 5154a5faf6..4b2d82ab4f 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/SolutionModifierHandlerTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/SolutionModifierHandlerTest.java
@@ -28,7 +28,6 @@ import org.apache.jena.query.Query;
 import org.apache.jena.query.SortCondition;
 import org.apache.jena.sparql.core.Var;
 import org.apache.jena.sparql.expr.E_Random;
-import org.apache.jena.sparql.lang.sparql_11.ParseException;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -44,7 +43,7 @@ public class SolutionModifierHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddAll() throws ParseException {
+    public void testAddAll() {
         SolutionModifierHandler solutionModifier2 = new SolutionModifierHandler(new Query());
         solutionModifier2.addOrderBy(Var.alloc("orderBy"));
         solutionModifier2.addGroupBy(Var.alloc("groupBy"));
@@ -63,7 +62,7 @@ public class SolutionModifierHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAll() throws ParseException {
+    public void testAll() {
         solutionModifier.addOrderBy(Var.alloc("orderBy"));
         solutionModifier.addGroupBy(Var.alloc("groupBy"));
         solutionModifier.addHaving("SUM(?lprice) > 10");
@@ -130,7 +129,7 @@ public class SolutionModifierHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddHavingString() throws ParseException {
+    public void testAddHavingString() {
         solutionModifier.addHaving("?having<10");
         assertContainsRegex(HAVING + OPEN_PAREN + var("having") + OPT_SPACE + LT + 10 + CLOSE_PAREN, query.toString());
 
@@ -141,7 +140,7 @@ public class SolutionModifierHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddHavingVar() throws ParseException {
+    public void testAddHavingVar() {
         solutionModifier.addHaving(Var.alloc("foo"));
         assertContainsRegex(HAVING + var("foo"), query.toString());
 
@@ -150,7 +149,7 @@ public class SolutionModifierHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddHavingExpr() throws ParseException {
+    public void testAddHavingExpr() {
         solutionModifier.addHaving(new E_Random());
         assertContainsRegex(HAVING + "rand" + OPEN_PAREN + CLOSE_PAREN, query.toString());
 
diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/WhereHandlerTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/WhereHandlerTest.java
index 908b5558bd..ffbb84f3f2 100644
--- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/WhereHandlerTest.java
+++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/WhereHandlerTest.java
@@ -32,6 +32,7 @@ import org.apache.jena.query.Query;
 import org.apache.jena.rdf.model.ResourceFactory;
 import org.apache.jena.shared.PrefixMapping;
 import org.apache.jena.shared.impl.PrefixMappingImpl;
+import org.apache.jena.sparql.core.PathBlock;
 import org.apache.jena.sparql.core.TriplePath;
 import org.apache.jena.sparql.core.Var;
 import org.apache.jena.sparql.engine.binding.Binding;
@@ -41,7 +42,6 @@ import org.apache.jena.sparql.expr.E_Function;
 import org.apache.jena.sparql.expr.E_LessThan;
 import org.apache.jena.sparql.expr.E_Random;
 import org.apache.jena.sparql.expr.aggregate.AggCount;
-import org.apache.jena.sparql.lang.sparql_11.ParseException;
 import org.apache.jena.sparql.path.P_Link;
 import org.apache.jena.sparql.path.Path;
 import org.apache.jena.sparql.path.PathParser;
@@ -127,7 +127,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddWhereObjects() {
+    public void testAddWhere3Objects() {
         handler.addWhere(
                 new TriplePath(Triple.create(NodeFactory.createURI("one"), ResourceFactory.createResource("two").asNode(),
                         ResourceFactory.createLangLiteral("three", "en-US").asNode())));
@@ -144,7 +144,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddWhereObjectsWithPath() {
+    public void testAddWhere3ObjectsWithPath() {
         PrefixMapping pmap = new PrefixMappingImpl();
         pmap.setNsPrefix("ts", "urn:test:");
         Path path = PathParser.parse("ts:two/ts:dos", pmap);
@@ -161,46 +161,59 @@ public class WhereHandlerTest extends AbstractHandlerTest {
         assertTrue(wv.matching);
 
     }
-
+    
     @Test
-    public void testAddWhereAnonymous() {
-        handler.addWhere(new TriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY)));
+    public void testAddWhereCollection() {
+        PrefixMapping pmap = new PrefixMappingImpl();
+        pmap.setNsPrefix("ts", "urn:test:");
+        Path path = PathParser.parse("ts:two/ts:dos", pmap);
+        
+        TriplePath[] expected = {
+                new TriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY)),
+                new TriplePath(Triple.create(NodeFactory.createURI("one"), ResourceFactory.createResource("two").asNode(),
+                        ResourceFactory.createLangLiteral("three", "en-US").asNode())),
+                new TriplePath(NodeFactory.createURI("one"), path, ResourceFactory.createLangLiteral("three", "en-US").asNode())
+        };
+        
+        handler.addWhere(Arrays.asList(expected));
         handler.build();
 
-        TriplePath tp = new TriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY));
         ElementPathBlock epb = new ElementPathBlock();
-        epb.addTriple(tp);
+        PathBlock pb = epb.getPattern();
+        Arrays.stream(expected).forEach(pb::add);
+
         WhereValidator wv = new WhereValidator(epb);
         query.getQueryPattern().visit(wv);
         assertTrue(wv.matching);
-
     }
 
     @Test
-    public void testAddOptionalStrings() {
-        handler.addOptional(new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"),
-                NodeFactory.createURI("three"))));
+    public void testAddWhereWithAnonymous() {
+        handler.addWhere(new TriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY)));
         handler.build();
 
-        TriplePath tp = new TriplePath(
-                Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"), NodeFactory.createURI("three")));
+        TriplePath tp = new TriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY));
         ElementPathBlock epb = new ElementPathBlock();
         epb.addTriple(tp);
-        ElementOptional opt = new ElementOptional(epb);
-        WhereValidator wv = new WhereValidator(opt);
+        WhereValidator wv = new WhereValidator(epb);
         query.getQueryPattern().visit(wv);
         assertTrue(wv.matching);
 
     }
 
     @Test
-    public void testAddOptionalAnonymous() {
-        handler.addOptional(new TriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY)));
+    public void testAddOptionalList() {
+        TriplePath[] expected = {
+                new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"),
+                        NodeFactory.createURI("three"))),
+                new TriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY))
+                        };
+        
+        handler.addOptional(Arrays.asList(expected));
         handler.build();
-
-        TriplePath tp = new TriplePath(Triple.create(Node.ANY, RDF.first.asNode(), Node.ANY));
+        
         ElementPathBlock epb = new ElementPathBlock();
-        epb.addTriple(tp);
+        Arrays.stream(expected).forEach(epb::addTriple);
         ElementOptional opt = new ElementOptional(epb);
         WhereValidator wv = new WhereValidator(opt);
         query.getQueryPattern().visit(wv);
@@ -238,9 +251,10 @@ public class WhereHandlerTest extends AbstractHandlerTest {
 
     @Test
     public void testAddOptionalObjects() {
-        handler.addOptional(
+        
+        handler.addOptional(Arrays.asList(
                 new TriplePath(Triple.create(NodeFactory.createURI("one"), ResourceFactory.createResource("two").asNode(),
-                        ResourceFactory.createLangLiteral("three", "en-US").asNode())));
+                        ResourceFactory.createLangLiteral("three", "en-US").asNode()))));
         handler.build();
 
         ElementPathBlock epb = new ElementPathBlock();
@@ -261,8 +275,8 @@ public class WhereHandlerTest extends AbstractHandlerTest {
         pmap.setNsPrefix("ts", "urn:test:");
         Path path = PathParser.parse("ts:two/ts:dos", pmap);
 
-        handler.addOptional(new TriplePath(NodeFactory.createURI("one"), path,
-                ResourceFactory.createLangLiteral("three", "en-US").asNode()));
+        handler.addOptional(Arrays.asList(new TriplePath(NodeFactory.createURI("one"), path,
+                ResourceFactory.createLangLiteral("three", "en-US").asNode())));
         handler.build();
 
         ElementPathBlock epb = new ElementPathBlock();
@@ -294,7 +308,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddFilter() throws ParseException {
+    public void testAddFilter() {
         handler.addFilter("?one < 10");
         handler.build();
 
@@ -306,7 +320,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddFilterWithNamespace() throws ParseException {
+    public void testAddFilterWithNamespace(){
         query.setPrefix("afn", "http://jena.apache.org/ARQ/function#");
         handler.addFilter("afn:namespace(?one) = 'foo'");
         handler.build();
@@ -321,7 +335,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddFilterVarOnly() throws ParseException {
+    public void testAddFilterVarOnly()  {
         handler.addFilter("?one");
         handler.build();
 
@@ -356,7 +370,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testAddSubQueryWithVarExpressions() throws ParseException {
+    public void testAddSubQueryWithVarExpressions() {
         SelectBuilder sb = new SelectBuilder();
         sb.addPrefix("pfx", "uri").addVar("count(*)", "?x").addWhere("<one>", "<two>", "three");
         handler.addSubQuery(sb);
@@ -541,7 +555,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void addGraph() {
+    public void testAddGraph() {
 
         WhereHandler handler2 = new WhereHandler(new Query());
         handler2.addWhere(new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"),
@@ -560,6 +574,27 @@ public class WhereHandlerTest extends AbstractHandlerTest {
         handler.getQueryPattern().visit(visitor);
         assertTrue(visitor.matching);
     }
+    
+    @Test
+    public void testAddGraphTriplePaths() {
+
+        TriplePath[] expected = {
+                new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"),
+                        NodeFactory.createURI("three"))),
+                new TriplePath(Triple.create(NodeFactory.createURI("four"), NodeFactory.createURI("five"),
+                        NodeFactory.createURI("six"))) };
+        
+        handler.addGraph(NodeFactory.createURI("graph"), Arrays.asList(expected));
+        handler.build();
+
+        ElementPathBlock epb = new ElementPathBlock();
+        Arrays.stream(expected).forEach(epb::addTriple);
+        ElementNamedGraph eng = new ElementNamedGraph(NodeFactory.createURI("graph"), epb);
+
+        WhereValidator visitor = new WhereValidator(eng);
+        handler.getQueryPattern().visit(visitor);
+        assertTrue(visitor.matching);
+    }
 
     @Test
     public void testSetVarsInTriple() {
@@ -589,7 +624,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testSetVarsInFilter() throws ParseException {
+    public void testSetVarsInFilter() {
         handler.addFilter("?one < ?v");
         handler.build();
 
@@ -614,7 +649,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     @Test
     public void testSetVarsInOptional() {
         Var v = Var.alloc("v");
-        handler.addOptional(new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"), v)));
+        handler.addOptional(Arrays.asList(new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"), v))));
         handler.build();
 
         TriplePath tp = new TriplePath(Triple.create(NodeFactory.createURI("one"), NodeFactory.createURI("two"), v));
@@ -720,7 +755,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
     }
 
     @Test
-    public void testBindStringVar() throws ParseException {
+    public void testBindStringVar() {
         Var v = Var.alloc("foo");
         handler.addBind("rand()", v);
         handler.build();
@@ -744,6 +779,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
         assertTrue(visitor.matching);
     }
 
+    @SuppressWarnings("deprecation")
     @Test
     public void testList() {
         Node n = handler.list("<one>", "?var", "'three'");
@@ -771,6 +807,7 @@ public class WhereHandlerTest extends AbstractHandlerTest {
         assertTrue(n.isBlank());
     }
 
+    @SuppressWarnings("deprecation")
     @Test
     public void testListInTriple() {
         handler.addWhere(new TriplePath(Triple.create(handler.list("<one>", "?var", "'three'"),