You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2016/10/03 10:35:48 UTC

[16/41] jena git commit: calling the json-ld (0.8.3) method that assumes no duplicates in dataset (cf. https://github.com/jsonld-java/jsonld-java/pull/173) Changes following Andy's comments: RDFFormatVariant, indentation using spaces

calling the json-ld (0.8.3) method that assumes no duplicates in dataset
(cf. https://github.com/jsonld-java/jsonld-java/pull/173)
Changes following Andy's comments: RDFFormatVariant, indentation using
spaces


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/39c881ad
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/39c881ad
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/39c881ad

Branch: refs/heads/master
Commit: 39c881ad8fe599b3e830fef3ced71d3da3b9faf3
Parents: 7f0f061
Author: Franc\u0327ois-Paul Servant <fp...@semanlink.net>
Authored: Sun Aug 28 23:38:01 2016 +0200
Committer: Franc\u0327ois-Paul Servant <fp...@semanlink.net>
Committed: Sun Aug 28 23:38:01 2016 +0200

----------------------------------------------------------------------
 .../java/org/apache/jena/riot/RDFFormat.java    |  61 +-
 .../org/apache/jena/riot/WriterDatasetRIOT.java |   7 +-
 .../org/apache/jena/riot/out/JsonLDWriter.java  | 328 ++++----
 .../jena/riot/writer/TestJsonLDWriter.java      | 764 +++++++++----------
 4 files changed, 584 insertions(+), 576 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/39c881ad/jena-arq/src/main/java/org/apache/jena/riot/RDFFormat.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/RDFFormat.java b/jena-arq/src/main/java/org/apache/jena/riot/RDFFormat.java
index 311b21b..c5e1065 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/RDFFormat.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/RDFFormat.java
@@ -40,7 +40,7 @@ public class RDFFormat {
     public static final RDFFormatVariant UTF8           = new RDFFormatVariant("utf-8") ;
     /** Variant for RDF Thrift using values */
     public static final RDFFormatVariant ValueEncoding  = new RDFFormatVariant("Value") ;
-    
+
     /** Turtle - pretty form */
     public static final RDFFormat        TURTLE_PRETTY  = new RDFFormat(Lang.TURTLE, PRETTY) ;
     /** Turtle - default form */
@@ -79,19 +79,52 @@ public class RDFFormat {
     /** TriG - one line per triple  */ 
     public static final RDFFormat        TRIG_FLAT      = new RDFFormat(Lang.TRIG, FLAT) ;
 
+    //
+    // JSONLD related
+    //
+
+    public static class JSONLDVariant extends RDFFormatVariant {
+        private static enum JSONLD_FORMAT {
+            COMPACT,
+            FLATTEN,
+            EXPAND,
+            FRAME
+        }
+
+        private JSONLD_FORMAT format ;
+        private boolean prettyJson ;
+
+        JSONLDVariant(String name, boolean prettyJson, JSONLD_FORMAT format) { 
+            super(name) ;
+            this.format = format ;
+            this.prettyJson = prettyJson ;
+        }
+
+        public boolean isPretty() { return prettyJson ; }
+
+        private boolean isFormat(JSONLD_FORMAT fmt) {
+            return (fmt == format);
+        }
+
+        public boolean isCompact() { return isFormat(JSONLD_FORMAT.COMPACT); }
+        public boolean isFlatten() { return isFormat(JSONLD_FORMAT.FLATTEN); }
+        public boolean isExpand() { return isFormat(JSONLD_FORMAT.EXPAND); }
+        public boolean isFrame() { return isFormat(JSONLD_FORMAT.FRAME); }
+
+    }
+
     // variants for the JsonLD outputs.
-    // because of the prexisting JSONLD_PRETTY and JSONLD_FLAT,
+    // because of the preexisting JSONLD_PRETTY and JSONLD_FLAT,
     // we're more or less obliged to create all of these
-    // (I'd have preferred to use a flag for pretty vs flat)
-    
-    private static final RDFFormatVariant EXPAND_PRETTY      = new RDFFormatVariant("expand pretty") ;
-    private static final RDFFormatVariant EXPAND_FLAT        = new RDFFormatVariant("expand flat") ;
-    private static final RDFFormatVariant COMPACT_PRETTY     = new RDFFormatVariant("compact pretty") ;
-    private static final RDFFormatVariant COMPACT_FLAT       = new RDFFormatVariant("compact flat") ;
-    private static final RDFFormatVariant FLATTEN_PRETTY     = new RDFFormatVariant("flatten pretty") ;
-    private static final RDFFormatVariant FLATTEN_FLAT       = new RDFFormatVariant("flatten flat") ;
-    private static final RDFFormatVariant FRAME_PRETTY       = new RDFFormatVariant("frame pretty") ;
-    private static final RDFFormatVariant FRAME_FLAT         = new RDFFormatVariant("frame flat") ;
+
+    private static final RDFFormatVariant EXPAND_PRETTY      = new JSONLDVariant("expand pretty", true, JSONLDVariant.JSONLD_FORMAT.EXPAND) ;
+    private static final RDFFormatVariant EXPAND_FLAT        = new JSONLDVariant("expand flat", false, JSONLDVariant.JSONLD_FORMAT.EXPAND) ;
+    private static final RDFFormatVariant COMPACT_PRETTY     = new JSONLDVariant("compact pretty", true, JSONLDVariant.JSONLD_FORMAT.COMPACT) ;
+    private static final RDFFormatVariant COMPACT_FLAT       = new JSONLDVariant("compact flat", false, JSONLDVariant.JSONLD_FORMAT.COMPACT) ;
+    private static final RDFFormatVariant FLATTEN_PRETTY     = new JSONLDVariant("flatten pretty", true, JSONLDVariant.JSONLD_FORMAT.FLATTEN) ;
+    private static final RDFFormatVariant FLATTEN_FLAT       = new JSONLDVariant("flatten flat", false, JSONLDVariant.JSONLD_FORMAT.FLATTEN) ;
+    private static final RDFFormatVariant FRAME_PRETTY       = new JSONLDVariant("frame pretty", true, JSONLDVariant.JSONLD_FORMAT.FRAME) ;
+    private static final RDFFormatVariant FRAME_FLAT         = new JSONLDVariant("frame flat", false, JSONLDVariant.JSONLD_FORMAT.FRAME) ;
 
     public static final RDFFormat        JSONLD_EXPAND_PRETTY   = new RDFFormat(Lang.JSONLD, EXPAND_PRETTY) ;
     public static final RDFFormat        JSONLD_EXPAND_FLAT     = new RDFFormat(Lang.JSONLD, EXPAND_FLAT) ;
@@ -102,7 +135,7 @@ public class RDFFormat {
     public static final RDFFormat        JSONLD_FRAME_PRETTY    = new RDFFormat(Lang.JSONLD, FRAME_PRETTY) ;
     public static final RDFFormat        JSONLD_FRAME_FLAT      = new RDFFormat(Lang.JSONLD, FRAME_FLAT) ;
 
-     // redefine following ones in a way that preserve what they were doing in previous version
+    // redefine following ones in a way that preserve what they were doing in previous version
     public static final RDFFormat        JSONLD_PRETTY  = JSONLD_COMPACT_PRETTY ;
     public static final RDFFormat        JSONLD         = JSONLD_COMPACT_PRETTY ;
     public static final RDFFormat        JSONLD_FLAT    = JSONLD_COMPACT_FLAT ;
@@ -127,7 +160,7 @@ public class RDFFormat {
      *
      * @see #RDF_THRIFT_VALUES
      */
-    
+
     public static final RDFFormat RDF_THRIFT            = new RDFFormat(THRIFT) ;
     /**
      * A variant of an an RDFFormat that uses value encoding (e.g. integers,

http://git-wip-us.apache.org/repos/asf/jena/blob/39c881ad/jena-arq/src/main/java/org/apache/jena/riot/WriterDatasetRIOT.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/WriterDatasetRIOT.java b/jena-arq/src/main/java/org/apache/jena/riot/WriterDatasetRIOT.java
index f7f21c6..9eb4347 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/WriterDatasetRIOT.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/WriterDatasetRIOT.java
@@ -18,11 +18,12 @@
 
 package org.apache.jena.riot;
 
-import java.io.OutputStream ;
+import java.io.OutputStream;
 import java.io.Writer ;
 
 import org.apache.jena.riot.Lang ;
 import org.apache.jena.riot.system.PrefixMap ;
+import org.apache.jena.riot.system.RiotLib;
 import org.apache.jena.sparql.core.DatasetGraph ;
 import org.apache.jena.sparql.util.Context ;
 
@@ -47,6 +48,10 @@ public interface WriterDatasetRIOT
      * @param context       Context (see specific implementation for details) 
      */
     public void  write(OutputStream out, DatasetGraph datasetGraph, PrefixMap prefixMap, String baseURI, Context context) ;
+    
+    default public void write(OutputStream out, DatasetGraph datasetGraph, String baseURI, Context context) {
+        write(out, datasetGraph, RiotLib.prefixMap(datasetGraph), baseURI, context);
+    }
 
 //    /** Use of Writer is discouraged - let the serializer manage character sets in accordance with the format */
 //    public void  write(Writer out, DatasetGraph datasetGraph) ;

http://git-wip-us.apache.org/repos/asf/jena/blob/39c881ad/jena-arq/src/main/java/org/apache/jena/riot/out/JsonLDWriter.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/out/JsonLDWriter.java b/jena-arq/src/main/java/org/apache/jena/riot/out/JsonLDWriter.java
index 0bbba9f..919e308 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/out/JsonLDWriter.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/out/JsonLDWriter.java
@@ -53,20 +53,24 @@ import org.apache.log4j.Logger;
 import com.fasterxml.jackson.core.JsonGenerationException ;
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.databind.JsonMappingException ;
+import com.github.jsonldjava.core.JsonLdApi;
 import com.github.jsonldjava.core.JsonLdError ;
 import com.github.jsonldjava.core.JsonLdOptions ;
 import com.github.jsonldjava.core.JsonLdProcessor ;
+import com.github.jsonldjava.core.RDFDataset;
 import com.github.jsonldjava.utils.JsonUtils ;
 
 /**
  * Writer that prints out JSON-LD.
  * 
- * By default, the output is "compact" (in JSON-LD terminology).
+ * By default, the output is "compact" (in JSON-LD terminology), and the JSON is "pretty" (using line breaks).
  * One can choose another form using one of the dedicated RDFFormats (JSONLD_EXPAND_PRETTY, etc.).
+ * 
  * For formats using a context ("@context" node), (compact and expand), this automatically generates a default one.
  * One can pass a jsonld context using the (jena) Context mechanism, defining a (jena) Context
- * (sorry for this clash of contexts), (cf. 4th argument in
+ * (sorry for this clash of contexts), (cf. last argument in
  * {@link org.apache.jena.riot.RDFDataMgr#write(OutputStream out, Model model, RDFFormat serialization, Context ctx)})
+ * {@link java.io.OutputStream.WriterDatasetRIOT.write(OutputStream out, DatasetGraph datasetGraph, PrefixMap prefixMap, String baseURI, Context context)})
  * with:
  * <pre>
  * Context jenaContext = new Context()
@@ -74,40 +78,43 @@ import com.github.jsonldjava.utils.JsonUtils ;
  * </pre>
  * where contextAsJsonString is a JSON string containing the value of the "@context".
  * 
- * One can also pass a frame with the {@link #JSONLD_FRAME}, or define the options expected
- * by JSONLD-java using {@link #JSONLD_OPTIONS} 
+ * It is possible to change the content of the "@context" node in the output using the {@link #JSONLD_CONTEXT_SUBSTITUTION} Symbol.
+ * 
+ * For a frame output, one must pass a frame in the jenaContext using the {@link #JSONLD_FRAME} Symbol.
+ * 
+ * It is also possible to define the different options supported
+ * by JSONLD-java using the {@link #JSONLD_OPTIONS} Symbol 
  * 
  * 
  */
 public class JsonLDWriter extends WriterDatasetRIOTBase
 {
-		/** Expected value: the value of the "@context" (a JSON String) */
-		public static final Symbol JSONLD_CONTEXT = Symbol.create("JSONLD_CONTEXT");
-		/**
-		 * Expected value: the value of the "@context" to be put in final output (a JSON String) 
-		 * This is NOT the context used to produce the output (given by JSONLD_CONTEXT,
-		 * or computed from the input RDF. It is something that will replace the @content content
-		 * This is useful 1) for the cases you want to have a URI as value of @context,
-		 * without having JSON-LD java to download it and 2) as a trick to
-		 * change the URIs in your result. 
-		 * 
-		 * Only for compact and flatten formats.
-		 * 
-		 * Note that it is supposed to be a JSON String: to set the value of @context to a URI,
-		 * the String to use must be quoted.*/
-		public static final Symbol JSONLD_CONTEXT_SUBSTITUTION = Symbol.create("JSONLD_CONTEXT_SUBSTITUTION");		
-		/** value: the frame object expected by JsonLdProcessor.frame */
-		public static final Symbol JSONLD_FRAME = Symbol.create("JSONLD_FRAME");
-		/** value: the option object expected by JsonLdProcessor (instance of JsonLdOptions) */
-		public static final Symbol JSONLD_OPTIONS = Symbol.create("JSONLD_OPTIONS");
-		private static enum JSONLD_FORMAT {
-			COMPACT,
-			FLATTEN,
-			EXPAND,
-			FRAME
-		}
-
-		private final RDFFormat format ;
+    private static final String SYMBOLS_NS = "http://jena.apache.org/riot/jsonld#" ;
+    private static Symbol createSymbol(String localName) {
+        return Symbol.create(SYMBOLS_NS + localName);
+    }
+
+    /** Expected value: the value of the "@context" (a JSON String) */
+    public static final Symbol JSONLD_CONTEXT = createSymbol("JSONLD_CONTEXT");
+    /**
+     * Expected value: the value of the "@context" to be put in final output (a JSON String) 
+     * This is NOT the context used to produce the output (given by JSONLD_CONTEXT,
+     * or computed from the input RDF. It is something that will replace the @context content.
+     * This is useful<ol><li>for the cases you want to have a URI as value of @context,
+     * without having JSON-LD java to download it and</li><li>as a trick to
+     * change the URIs in your result.</li></ol>
+     * 
+     * Only for compact and flatten formats.
+     * 
+     * Note that it is supposed to be a JSON String: to set the value of @context to a URI,
+     * the String must be quoted.*/
+    public static final Symbol JSONLD_CONTEXT_SUBSTITUTION = createSymbol("JSONLD_CONTEXT_SUBSTITUTION");		
+    /** value: the frame object expected by JsonLdProcessor.frame */
+    public static final Symbol JSONLD_FRAME = createSymbol("JSONLD_FRAME");
+    /** value: the option object expected by JsonLdProcessor (instance of JsonLdOptions) */
+    public static final Symbol JSONLD_OPTIONS = createSymbol("JSONLD_OPTIONS");
+
+    private final RDFFormat format ;
 
     public JsonLDWriter(RDFFormat syntaxForm) {
         format = syntaxForm ;
@@ -130,85 +137,81 @@ public class JsonLDWriter extends WriterDatasetRIOTBase
         IO.flush(w) ;
     }
 
-    private JSONLD_FORMAT getOutputFormat() {
-	  		if ((RDFFormat.JSONLD_COMPACT_PRETTY.equals(format)) || (RDFFormat.JSONLD_COMPACT_FLAT.equals(format))) return JSONLD_FORMAT.COMPACT;
-	  		if ((RDFFormat.JSONLD_EXPAND_PRETTY.equals(format)) || (RDFFormat.JSONLD_EXPAND_FLAT.equals(format))) return JSONLD_FORMAT.EXPAND;
-	  		if ((RDFFormat.JSONLD_FLATTEN_PRETTY.equals(format)) || (RDFFormat.JSONLD_FLATTEN_FLAT.equals(format))) return JSONLD_FORMAT.FLATTEN;
-	  		if ((RDFFormat.JSONLD_FRAME_PRETTY.equals(format)) || (RDFFormat.JSONLD_FRAME_FLAT.equals(format))) return JSONLD_FORMAT.FRAME;
-	  		throw new RuntimeException("Unexpected output format");
-    }
-    
-    private boolean isPretty() {
-    		return (((RDFFormat.JSONLD_COMPACT_PRETTY.equals(format))
-    				|| (RDFFormat.JSONLD_FLATTEN_PRETTY.equals(format))
-    				|| (RDFFormat.JSONLD_EXPAND_PRETTY.equals(format)))
-    				|| (RDFFormat.JSONLD_FRAME_PRETTY.equals(format))) ;
+    private RDFFormat.JSONLDVariant getVariant() {
+        return (RDFFormat.JSONLDVariant) format.getVariant();
     }
-    
+
     private JsonLdOptions getJsonLdOptions(String baseURI, Context jenaContext) {
-	  		JsonLdOptions opts = null;
-	  		if (jenaContext != null) {
-	  			opts = (JsonLdOptions) jenaContext.get(JSONLD_OPTIONS);
-	  		}
-	  		if (opts == null) {
-	        opts = new JsonLdOptions(baseURI);
-	        opts.useNamespaces = true ;
-	        //opts.setUseRdfType(true);
-	        opts.setUseNativeTypes(true);
-	        opts.setCompactArrays(true);	  			
-	  		} 
-	  		return opts;
+        JsonLdOptions opts = null;
+        if (jenaContext != null) {
+            opts = (JsonLdOptions) jenaContext.get(JSONLD_OPTIONS);
+        }
+        if (opts == null) {
+            opts = new JsonLdOptions(baseURI);
+            // maybe we should have used the same defaults as jsonld-java. Too late now
+            opts.useNamespaces = true ;
+            //opts.setUseRdfType(true); // false -> use "@type"
+            opts.setUseNativeTypes(true);
+            opts.setCompactArrays(true);	  			
+        } 
+        return opts;
     }
 
+    @SuppressWarnings("deprecation") // JsonLdApi.fromRDF(RDFDataset, boolean) is "experimental" rather than "deprecated", cf. https://github.com/jsonld-java/jsonld-java/pull/173
     private void serialize(Writer writer, DatasetGraph dataset, PrefixMap prefixMap, String baseURI, Context jenaContext) {
         try {
-        		JsonLdOptions opts = getJsonLdOptions(baseURI, jenaContext) ;
-        		
-            Object obj = JsonLdProcessor.fromRDF(dataset, opts, new JenaRDF2JSONLD()) ;
+            JsonLdOptions opts = getJsonLdOptions(baseURI, jenaContext) ;
+
+            // we can benefit from the fact we know that there are no duplicates in the jsonld RDFDataset that we create
+            // cf. cf. https://github.com/jsonld-java/jsonld-java/pull/173
             
-            JSONLD_FORMAT outputForm = getOutputFormat() ;
-      	    if (outputForm == JSONLD_FORMAT.EXPAND) {
-      	    	// nothing more to do
-      	    
-      	    } else if (outputForm == JSONLD_FORMAT.FRAME) {
-      	    	Object frame = null;
-      	    	if (jenaContext != null) 
-      	    		frame = jenaContext.get(JSONLD_FRAME);
-      	    	
-      	    	if (frame == null) {
-      	    		throw new IllegalArgumentException("No frame object found in context");
-      	    	}
-      	    	obj = JsonLdProcessor.frame(obj, frame, opts);
-
-      	    } else {
-      	    	// we need a (jsonld) context. Get it from jenaContext, or make one:
-      	  		Object ctx = getJsonldContext(dataset, prefixMap, jenaContext);
-      	  		
-      	  		if (outputForm == JSONLD_FORMAT.COMPACT) {
-      	      	obj = JsonLdProcessor.compact(obj, ctx, opts);
-      	      	
-      	      } else if (outputForm == JSONLD_FORMAT.FLATTEN) {
-      	      	obj = JsonLdProcessor.flatten(obj, ctx, opts);
-      	      	
-      	      } else {
-      	      	throw new IllegalArgumentException("Unexpected output form " + outputForm);
-      	      }
-      	  		
-      	  		// replace @context in output?
-      	  		if (jenaContext != null) {
-	      	  		Object ctxReplacement = jenaContext.get(JSONLD_CONTEXT_SUBSTITUTION);
-	      	  		if (ctxReplacement != null) {
-	      	  			if (obj instanceof Map) {
-	      	  				Map map = (Map) obj;
-	      	  				if (map.containsKey("@context")) {
-	      	  					map.put("@context", JsonUtils.fromString((String) ctxReplacement));
-	      	  				}
-	      	  			}
-	      	  		}
-      	  		}
-      	    }
-
-      	    if ( isPretty() )
+            // with this, we cannot call the json-ld fromRDF method that assumes no duplicates in RDFDataset
+            // Object obj = JsonLdProcessor.fromRDF(dataset, opts, new JenaRDF2JSONLD()) ;
+            final RDFDataset jsonldDataset = (new JenaRDF2JSONLD()).parse(dataset);
+            Object obj = (new JsonLdApi(opts)).fromRDF(jsonldDataset, true); // true because we know that we don't have any duplicate in jsonldDataset
+
+            RDFFormat.JSONLDVariant variant = getVariant();
+            if (variant.isExpand()) {
+                // nothing more to do
+
+            } else if (variant.isFrame()) {
+                Object frame = null;
+                if (jenaContext != null) frame = jenaContext.get(JSONLD_FRAME);
+
+                if (frame == null) {
+                    throw new IllegalArgumentException("No frame object found in jena Context");
+                }
+                obj = JsonLdProcessor.frame(obj, frame, opts);
+
+            } else { // compact or flatten
+                // we need a (jsonld) context. Get it from jenaContext, or make one:
+                Object ctx = getJsonldContext(dataset, prefixMap, jenaContext);
+
+                if (variant.isCompact()) {
+                    obj = JsonLdProcessor.compact(obj, ctx, opts);
+
+                } else if (variant.isFlatten()) {
+                    obj = JsonLdProcessor.flatten(obj, ctx, opts);
+
+                } else {
+                    throw new IllegalArgumentException("Unexpected " + RDFFormat.JSONLDVariant.class.getName() + ": " + variant);
+                }
+
+                // replace @context in output?
+                if (jenaContext != null) {
+                    Object ctxReplacement = jenaContext.get(JSONLD_CONTEXT_SUBSTITUTION);
+                    if (ctxReplacement != null) {
+                        if (obj instanceof Map) {
+                            Map map = (Map) obj;
+                            if (map.containsKey("@context")) {
+                                map.put("@context", JsonUtils.fromString((String) ctxReplacement));
+                            }
+                        }
+                    }
+                }
+            }
+
+            if ( variant.isPretty() )
                 JsonUtils.writePrettyPrint(writer, obj) ;
             else
                 JsonUtils.write(writer, obj) ;
@@ -225,72 +228,73 @@ public class JsonLDWriter extends WriterDatasetRIOTBase
     //
     // getting / creating a (jsonld) context
     //
-    
+
     /** Get the (jsonld) context from the jena context, or create one */
     private static Object getJsonldContext(DatasetGraph dataset, PrefixMap prefixMap, Context jenaContext) throws JsonParseException, IOException {
-  		Object ctx = null;
-  		boolean isCtxDefined = false; // to allow jenaContext to set ctx to null. Useful?
-
-  		if (jenaContext != null) {
-  			if (jenaContext.isDefined(JSONLD_CONTEXT)) {
-  				isCtxDefined = true;
-  				Object o = jenaContext.get(JSONLD_CONTEXT);
-  				if (o != null) {
-  					// I won't assume it is a string, to leave the possibility to pass
-  					// the context object expected by JSON-LD JsonLdProcessor.compact and flatten
-  					// (should not be useful)
-  					if (o instanceof String) {
-  	  				String jsonString = (String) jenaContext.get(JSONLD_CONTEXT);
-  	  				if (jsonString != null) ctx = JsonUtils.fromString(jsonString);     	  						
-  					} else {
-  						Logger.getLogger(JsonLDWriter.class).warn("JSONLD_CONTEXT value is not a String. Assuming a context object expected by JSON-LD JsonLdProcessor.compact or flatten");
-  						ctx = o;
-  					}
-  				}
-  			}
-  		}
-
-  		if (!isCtxDefined) {
-  			// if no ctx passed via jenaContext, create one in order to have localnames as keys for properties
-  			ctx = createJsonldContext(dataset.getDefaultGraph(), prefixMap) ;
-  			
-        // I don't think this should be done: the JsonLdProcessor begins
-        // by looking whether the argument passed is a map with key "@context" and takes corresponding value
-        // Better not to do this: we create a map for nothing, and worse,
-  			// if the context object has been created by a user and passed through the (jena) context
-        // in case he got the same idea, we would end up with 2 levels of maps an it would work
-//        Map<String, Object> localCtx = new HashMap<>() ;
-//        localCtx.put("@context", ctx) ;
-//      	obj = JsonLdProcessor.compact(obj, localCtx, opts) ;
-  		}
-  		return ctx;
+        Object ctx = null;
+        boolean isCtxDefined = false; // to allow jenaContext to set ctx to null. Useful?
+
+        if (jenaContext != null) {
+            if (jenaContext.isDefined(JSONLD_CONTEXT)) {
+                isCtxDefined = true;
+                Object o = jenaContext.get(JSONLD_CONTEXT);
+                if (o != null) {
+                    // I won't assume it is a string, to leave the possibility to pass
+                    // the context object expected by JSON-LD JsonLdProcessor.compact and flatten
+                    // (should not be useful)
+                    if (o instanceof String) {
+                        String jsonString = (String) o;
+                        if (jsonString != null) ctx = JsonUtils.fromString(jsonString);     	  						
+                    } else {
+                        Logger.getLogger(JsonLDWriter.class).warn("JSONLD_CONTEXT value is not a String. Assuming a context object expected by JSON-LD JsonLdProcessor.compact or flatten");
+                        ctx = o;
+                    }
+                }
+            }
+        }
+
+        if (!isCtxDefined) {
+            // if no ctx passed via jenaContext, create one in order to have localnames as keys for properties
+            ctx = createJsonldContext(dataset.getDefaultGraph(), prefixMap) ;
+
+            // I don't think this should be done: the JsonLdProcessor begins
+            // by looking whether the argument passed is a map with key "@context" and if so, takes corresponding value
+            // Then, better not to do this: we create a map for nothing, and worse,
+            // if the context object has been created by a user and passed through the (jena) context
+            // in case he got the same idea, we would end up with 2 levels of maps an it would not work
+            //        Map<String, Object> localCtx = new HashMap<>() ;
+            //        localCtx.put("@context", ctx) ;
+        }
+        return ctx;
     }
-    
-  	// useful to help people wanting to create their own context?
+
+    // useful to help people who want to create their own context?
     // It is used in TestJsonLDWriter (marginally) (TestJsonLDWriter which happens to be in another package,
-    // so either I remove the test, or this has to be public)
-  	public static Object createJsonldContext(Graph g) {
-  		return createJsonldContext(g, PrefixMapFactory.create(g.getPrefixMapping()));
-  	}
-
-  	private static Object createJsonldContext(Graph g, PrefixMap prefixMap) {
-  		final Map<String, Object> ctx = new LinkedHashMap<>() ;
-  		addProperties(ctx, g) ;
-  		addPrefixes(ctx, prefixMap) ;	
-  		return ctx ;
-  	}
+    // so either I remove the test in question, or this has to be public)
+    public static Object createJsonldContext(Graph g) {
+        return createJsonldContext(g, PrefixMapFactory.create(g.getPrefixMapping()));
+    }
+
+    private static Object createJsonldContext(Graph g, PrefixMap prefixMap) {
+        final Map<String, Object> ctx = new LinkedHashMap<>() ;
+        addProperties(ctx, g) ;
+        addPrefixes(ctx, prefixMap) ;	
+        return ctx ;
+    }
 
     private static void addPrefixes(Map<String, Object> ctx, PrefixMap prefixMap) {
-        Map<String, IRI> pmap = prefixMap.getMapping() ;
-        for ( Entry<String, IRI> e : pmap.entrySet() ) {
-            String key = e.getKey() ;
-            if ( key.isEmpty() ) {
-                // Prefix "" is not allowed in JSON-LD
-            		// we could replace "" with "@vocab"
-              	// key = "@vocab" ;
-            		continue;
+        if (prefixMap != null) {
+            Map<String, IRI> pmap = prefixMap.getMapping() ;
+            for ( Entry<String, IRI> e : pmap.entrySet() ) {
+                String key = e.getKey() ;
+                if ( key.isEmpty() ) {
+                    // Prefix "" is not allowed in JSON-LD
+                    // we could replace "" with "@vocab"
+                    // key = "@vocab" ;
+                    continue;
+                }
+                ctx.put(key, e.getValue().toString()) ;
             }
-            ctx.put(key, e.getValue().toString()) ;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/39c881ad/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJsonLDWriter.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJsonLDWriter.java b/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJsonLDWriter.java
index 440d39a..e79edc2 100644
--- a/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJsonLDWriter.java
+++ b/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJsonLDWriter.java
@@ -23,6 +23,7 @@ import java.io.StringReader;
 
 import org.apache.jena.atlas.json.JsonObject;
 import org.apache.jena.atlas.junit.BaseTest;
+import org.apache.jena.query.DatasetFactory;
 import org.apache.jena.rdf.model.Model;
 import org.apache.jena.rdf.model.ModelFactory;
 import org.apache.jena.rdf.model.Property;
@@ -30,7 +31,11 @@ import org.apache.jena.rdf.model.RDFNode;
 import org.apache.jena.rdf.model.Resource;
 import org.apache.jena.riot.RDFDataMgr;
 import org.apache.jena.riot.RDFFormat;
+import org.apache.jena.riot.WriterDatasetRIOT;
 import org.apache.jena.riot.out.JsonLDWriter;
+import org.apache.jena.riot.system.PrefixMap;
+import org.apache.jena.riot.system.RiotLib;
+import org.apache.jena.sparql.core.DatasetGraph;
 import org.apache.jena.sparql.util.Context;
 import org.apache.jena.vocabulary.RDF;
 import org.apache.log4j.Logger;
@@ -41,417 +46,378 @@ import com.github.jsonldjava.utils.JsonUtils;
 
 public class TestJsonLDWriter extends BaseTest {
 
-/**
- * Checks that JSON-LD RDFFormats supposed to be pretty are pretty
- * and that those supposed to be flat are flat
- */
-@Test public final void prettyIsNotFlat() {
-	Model m = simpleModel();
-	m.setNsPrefix("ex", "http://www.a.com/foo/");
-	String s;
-	
-	// pretty is pretty
-	
-	s = toString(m, RDFFormat.JSONLD_EXPAND_PRETTY, null);
-	assertTrue(s.trim().indexOf("\n") > -1);
-	s = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
-	assertTrue(s.trim().indexOf("\n") > -1);
-	s = toString(m, RDFFormat.JSONLD_FLATTEN_PRETTY, null);
-	assertTrue(s.trim().indexOf("\n") > -1);
-
-	// and flat is flat
-	
-	s = toString(m, RDFFormat.JSONLD_EXPAND_FLAT, null);
-	assertTrue(s.trim().indexOf("\n") < 0);
-	s = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, null);
-	assertTrue(s.trim().indexOf("\n") < 0);
-	s = toString(m, RDFFormat.JSONLD_FLATTEN_FLAT, null);
-	assertTrue(s.trim().indexOf("\n") < 0);
-	assertTrue(s.trim().indexOf("\n") < 0);
-	// JSON_LD FRAME case not tested here, but in testFrames
-}
+    /**
+     * Checks that JSON-LD RDFFormats supposed to be pretty are pretty
+     * and that those supposed to be flat are flat
+     */
+    @Test public final void prettyIsNotFlat() {
+        Model m = simpleModel();
+        m.setNsPrefix("ex", "http://www.a.com/foo/");
+        String s;
 
-/**
- * Checks that JSON-LD RDFFormats that are supposed to return a "@context"
- * actually do so.
- */
-@Test public final void contextOrNot() {
-	Model m = simpleModel();
-	m.setNsPrefix("ex", "http://www.a.com/foo/");
-	String s;
-	
-	// there's no "@context" in expand
-	
-	s = toString(m, RDFFormat.JSONLD_EXPAND_PRETTY, null);
-	assertTrue(s.indexOf("@context") < 0);
-	s = toString(m, RDFFormat.JSONLD_EXPAND_FLAT, null);
-	assertTrue(s.indexOf("@context") < 0);
-	
-	// there's an "@context" in compact and flatten
-	
-	s = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
-	assertTrue(s.indexOf("@context") > -1);
-	s = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, null);
-	assertTrue(s.indexOf("@context") > -1);
-	s = toString(m, RDFFormat.JSONLD_FLATTEN_PRETTY, null);
-	assertTrue(s.indexOf("@context") > -1);
-	s = toString(m, RDFFormat.JSONLD_FLATTEN_FLAT, null);
-	assertTrue(s.indexOf("@context") > -1);
-}
+        // pretty is pretty
 
-private Model simpleModel() {
-	Model m = ModelFactory.createDefaultModel();
-	String url = "http://www.a.com/foo/";
-	Resource s = m.createResource(url + "s");
-	Property p = m.createProperty(url + "p");
-	Resource o = m.createResource(url + "o");
-	m.add(s,p,o);
-	return m;
-}
+        s = toString(m, RDFFormat.JSONLD_EXPAND_PRETTY, null);
+        assertTrue(s.trim().indexOf("\n") > -1);
+        s = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
+        assertTrue(s.trim().indexOf("\n") > -1);
+        s = toString(m, RDFFormat.JSONLD_FLATTEN_PRETTY, null);
+        assertTrue(s.trim().indexOf("\n") > -1);
 
-/**
- * Write a model and parse it back: you should get the same thing
- * (except with frame)
- */
-@Test public final void roundTrip() {
-	Model m = simpleModel();
-	m.setNsPrefix("ex", "http://www.a.com/foo/");
-	for (RDFFormat f : JSON_LD_FORMATS) {
-		if (f.getVariant().toString().indexOf("frame") > -1) continue;
-		String s = toString(m, f, null);
-		Model m2 = parse(s);
-		assertTrue(m2.isIsomorphicWith(m));		
-	}
-}
+        // and flat is flat
 
-//@Test public final void supportEmptyNs() {
-//	Model m = ModelFactory.createDefaultModel();
-//	String ns = "http://www.a.com/foo/";
-//	Resource s = m.createResource(ns + "s");
-//	Property p = m.createProperty(ns + "p");
-//	Resource o = m.createResource(ns + "o");
-//	m.add(s,p,o);
-//	m.add(m.createResource(ns + "s2"),p,m.createResource(ns + "o2"));
-//	m.setNsPrefix("ns", ns);
-//	Model m2 = parse(toJsonLDString(m));
-//	assertTrue(m2.isIsomorphicWith(m));
-//	
-//	// RDFDataMgr.write(DevNull.out, m, RDFFormat.JSONLD) ;
-//	RDFDataMgr.write(System.out, m2, RDFFormat.TURTLE);
-//	RDFDataMgr.write(System.out, m, RDFFormat.JSONLD);
-//}
-
-/** verify that one may pass a context as a JSON string, and that it is actually used in the output */
-@Test public void testSettingContextAsJsonString() {
-	// 1) get the context generated by default by jena
-	// for a simple model with a prefix declaration
-	// 2) remove prefix declaration from model,
-	// output as jsonld is different
-	// 3) output the model as jsonld using the context:
-	// we should get the same output as in 1
-	Model m = ModelFactory.createDefaultModel();
-	String url = "http://www.semanlink.net/test/";
-	Resource s = m.createResource(url + "s");
-	Property p = m.createProperty(url + "p");
-	Resource o = m.createResource(url + "o");
-	m.add(s,p,o);
-	m.setNsPrefix("ex", url);
-	
-	String s1 = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, null);
-	// there's a prefix in m, and we find it in the output
-	String prefixStringInResult = "\"ex\":\"" + url + "\"";
-	assertTrue(s1.indexOf(prefixStringInResult) > 0);
-	Model m1 = parse(s1);
-	
-	// must we pass the json object associated to "@context",
-	// or its parent node (that is, with the "@context") ?
-	// Actually, we can do both (JSONLD-java's code ensure it)
-	// We check it for here
-	
-	// this is json object associated to "@context" in s1
-	// it includes the "ex" prefix
-	
-	String js = "{\"p\":{\"@id\":\"http://www.semanlink.net/test/p\",\"@type\":\"@id\"},\"ex\":\"http://www.semanlink.net/test/\"}";
-
-	// remove the prefix from m
-	m.removeNsPrefix("ex");	// RDFDataMgr.write(System.out, m, RDFFormat.JSONLD) ;
-	String s2 = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
-	// model wo prefix -> no more prefix string in result:
-	assertTrue(s2.indexOf(prefixStringInResult) < 0);
-
-	// the model wo prefix, outputed as jsonld using a context that defines the prefix	
-	Context jenaCtx = new Context();
-	jenaCtx.set(JsonLDWriter.JSONLD_CONTEXT, js);
-	String s3 = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, jenaCtx);
-	
-	assertTrue(s3.length() == s1.length());
-	assertTrue(s3.indexOf(prefixStringInResult) > 0);
-	Model m3 = parse(s3);
-	assertTrue(m3.isIsomorphicWith(m));
-	assertTrue(m3.isIsomorphicWith(m1));
-	
-	// same thing, but passing also the "@context"
-	js = "{\"@context\":" + js + "}";
-	jenaCtx.set(JsonLDWriter.JSONLD_CONTEXT, js);
-	String s4 = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, jenaCtx);
-	
-	assertTrue(s4.length() == s1.length());
-	assertTrue(s4.indexOf(prefixStringInResult) > 0);
-	Model m4 = parse(s4);
-	assertTrue(m4.isIsomorphicWith(m));
-	assertTrue(m4.isIsomorphicWith(m1));
-}
+        s = toString(m, RDFFormat.JSONLD_EXPAND_FLAT, null);
+        assertTrue(s.trim().indexOf("\n") < 0);
+        s = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, null);
+        assertTrue(s.trim().indexOf("\n") < 0);
+        s = toString(m, RDFFormat.JSONLD_FLATTEN_FLAT, null);
+        assertTrue(s.trim().indexOf("\n") < 0);
+        assertTrue(s.trim().indexOf("\n") < 0);
+        // JSON_LD FRAME case not tested here, but in testFrames
+    }
 
-/**
- * Checks that one can pass a context defined by its URI
- */
-@Test public final void testContextByUri() {
-	Model m = ModelFactory.createDefaultModel();
-	String ns = "http://schema.org/";
-	Resource s = m.createResource();
-	m.add(s, m.createProperty(ns + "name"), "Jane Doe");
-	m.add(s, m.createProperty(ns + "url"), "http://www.janedoe.com");
-	m.add(s, RDF.type, "Person");
-	
-	// we can pass a uri in the context, as a quoted string (it is a JSON string)
-	Context jenaContext = new Context();
-	try {
-		// jenaContext.set(JsonLDWriter.JSONLD_CONTEXT, "http://schema.org/");
-		// beware, it must be quoted, as it is supposed to be a json string
-		jenaContext.set(JsonLDWriter.JSONLD_CONTEXT, "\"http://schema.org/\"");
-		String jsonld = toString(m, RDFFormat.JSONLD, jenaContext);
-	} catch (Throwable e) {
-		Logger.getLogger(getClass()).info("Sorry to get this exception",e);
-	}
-
-	// It seems to work, but there's a problem with httpclient version: the one used by jena
-	// is not compatible with the one expected by JSONLD-java API. We get
-	/*
-java.lang.NoSuchMethodError: org.apache.http.impl.client.cache.CacheConfig.custom()Lorg/apache/http/impl/client/cache/CacheConfig$Builder;
-	at com.github.jsonldjava.utils.JsonUtils.createDefaultHttpClient(JsonUtils.java:333)
-	at com.github.jsonldjava.utils.JsonUtils.getDefaultHttpClient(JsonUtils.java:323)
-	at com.github.jsonldjava.core.DocumentLoader.getHttpClient(DocumentLoader.java:84)
-	at com.github.jsonldjava.core.DocumentLoader.fromURL(DocumentLoader.java:59)
-	at com.github.jsonldjava.core.DocumentLoader.loadDocument(DocumentLoader.java:29)
-	at com.github.jsonldjava.core.Context.parse(Context.java:169)
-	at com.github.jsonldjava.core.Context.parse(Context.java:252)
-	at com.github.jsonldjava.core.JsonLdProcessor.compact(JsonLdProcessor.java:57)
-	at org.apache.jena.riot.out.JsonLDWriter.serialize(JsonLDWriter.java:179)
-	at org.apache.jena.riot.out.JsonLDWriter.write(JsonLDWriter.java:85)
-	at org.apache.jena.riot.out.JsonLDWriter.write(JsonLDWriter.java:126)
-	at org.apache.jena.riot.system.RiotLib$WriterAdapter.write(RiotLib.java:376)
-	at org.apache.jena.riot.RDFDataMgr.write$(RDFDataMgr.java:1235)
-	at org.apache.jena.riot.RDFDataMgr.write(RDFDataMgr.java:1026)
-	at org.apache.jena.riot.RDFDataMgr.write(RDFDataMgr.java:956)
-	at org.apache.jena.riot.out.TestJsonLD.toString(TestJsonLD.java:232)
-	at org.apache.jena.riot.out.TestJsonLD.testContextByUri(TestJsonLD.java:186)
-	*/
-	// 
-	// httpclient-cache 4.2.6 from jena
-	// httpclient.version 4.5.1 from jsonld-java
-	// No chance to see this solved, as jena parent's pom says:
-	/*
-      <dependency>
-        <groupId>com.github.jsonld-java</groupId>
-        <artifactId>jsonld-java</artifactId>
-        <version>${ver.jsonldjava}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>commons-logging</groupId>
-            <artifactId>commons-logging</artifactId>
-          </exclusion>
-          <!-- Exclude so we use our choice of versions -->
-          <exclusion>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient-cache</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
-          </exclusion>
-	*/
-	
-	// But anyway, that's not what we want to do:
-	// there's no point in passing the uri of a context to have it dereferenced by jsonld-java
-	// (this is for a situation where one would want to parse a jsonld file containing a context defined by a uri)
-	// What we want is to pass a context to jsonld-java (in order for json-ld java to produce the correct jsonls output
-	// and then we want to replace the @context in the output by "@context":"ourUri"
-	
-	// How would we do that?
-}
+    /**
+     * Checks that JSON-LD RDFFormats that are supposed to return a "@context" do so.
+     */
+    @Test public final void contextOrNot() {
+        Model m = simpleModel();
+        m.setNsPrefix("ex", "http://www.a.com/foo/");
+        String s;
 
-/**
- * This generates a waring, but one may pass a context directly as the object
- * used by the JSON-LD java API.
-*/
-@Test public void testSettingContextAsObjectExpectedByJsonldAPI() {
-	// 1) get the context generated by default by jena
-	// for a simple model with a prefix declaration
-	// 2) remove prefix declaration from model,
-	// output as jsonld is different
-	// 3) output the model as jsonld using the context:
-	// we should get the same output as in 1
-	Model m = ModelFactory.createDefaultModel();
-	String url = "http://www.semanlink.net/test/";
-	Resource s = m.createResource(url + "s");
-	Property p = m.createProperty(url + "p");
-	Resource o = m.createResource(url + "o");
-	m.add(s,p,o);
-	m.setNsPrefix("ex", url);
-	
-	String s1 = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
-	// there's a prefix in m, and we find it in the output
-	String prefixStringInResult = "\"ex\" : \"" + url + "\"";
-	assertTrue(s1.indexOf(prefixStringInResult) > 0);
-	Model m1 = parse(s1);
-	
-	// the context used in this case, created automatically by jena as none is set
-	// it includes one prefix
-	Object ctx = JsonLDWriter.createJsonldContext(m.getGraph());
-	
-	// remove the prefix from m
-	m.removeNsPrefix("ex");	// RDFDataMgr.write(System.out, m, RDFFormat.JSONLD) ;
-	String s2 = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
-	// model wo prefix -> no more prefix string in result:
-	assertTrue(s2.indexOf(prefixStringInResult) < 0);
-
-	// the model wo prefix, outputed as jsonld using a context that defines the prefix	
-	Context jenaCtx = new Context();
-	jenaCtx.set(JsonLDWriter.JSONLD_CONTEXT, ctx);
-	String s3 = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, jenaCtx);
-	
-	assertTrue(s3.length() == s1.length());
-	assertTrue(s3.indexOf(prefixStringInResult) > 0);
-	Model m3 = parse(s3);
-	assertTrue(m3.isIsomorphicWith(m));
-	assertTrue(m3.isIsomorphicWith(m1));
+        // there's no "@context" in expand
 
-}
+        s = toString(m, RDFFormat.JSONLD_EXPAND_PRETTY, null);
+        assertTrue(s.indexOf("@context") < 0);
+        s = toString(m, RDFFormat.JSONLD_EXPAND_FLAT, null);
+        assertTrue(s.indexOf("@context") < 0);
 
-/**
- * Test using a context to compute the output, and replacing the @context with a given value
- */
-@Test public void testSubstitutingContext() {
-	Model m = ModelFactory.createDefaultModel();
-	String ns = "http://schema.org/";
-	Resource person = m.createResource(ns + "Person");
-	Resource s = m.createResource();
-	m.add(s, m.createProperty(ns + "name"), "Jane Doe");
-	m.add(s, m.createProperty(ns + "url"), "http://www.janedoe.com");
-	m.add(s, m.createProperty(ns + "jobTitle"), "Professor");
-	m.add(s, RDF.type, person);
-	
-	Context jenaCtx = new Context();
-	jenaCtx.set(JsonLDWriter.JSONLD_CONTEXT_SUBSTITUTION, "\"" + ns + "\"");
-
-	String jsonld = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, jenaCtx);
-	String c = "\"@context\":\"http://schema.org/\"";
-	assertTrue(jsonld.indexOf(c) > -1);
-}
+        // there's an "@context" in compact and flatten
 
+        s = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
+        assertTrue(s.indexOf("@context") > -1);
+        s = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, null);
+        assertTrue(s.indexOf("@context") > -1);
+        s = toString(m, RDFFormat.JSONLD_FLATTEN_PRETTY, null);
+        assertTrue(s.indexOf("@context") > -1);
+        s = toString(m, RDFFormat.JSONLD_FLATTEN_FLAT, null);
+        assertTrue(s.indexOf("@context") > -1);
+    }
 
-/**
- * Checking frames
- */
-@Test public final void testFrames() throws JsonParseException, IOException {
-	Model m = ModelFactory.createDefaultModel();
-	String ns = "http://schema.org/";
-	Resource person = m.createResource(ns + "Person");
-	Resource s = m.createResource();
-	m.add(s, m.createProperty(ns + "name"), "Jane Doe");
-	m.add(s, m.createProperty(ns + "url"), "http://www.janedoe.com");
-	m.add(s, m.createProperty(ns + "jobTitle"), "Professor");
-	m.add(s, RDF.type, person);
-	s = m.createResource();
-	m.add(s, m.createProperty(ns + "name"), "Gado Salamatou");
-	m.add(s, m.createProperty(ns + "url"), "http://www.salamatou.com");
-	m.add(s, RDF.type, person);
-	s = m.createResource();
-	m.add(s, m.createProperty(ns + "name"), "Not a person");
-	m.add(s, RDF.type, m.createResource(ns + "Event"));
-	
-	Context jenaCtx = new Context();
-	JsonObject frame = new JsonObject();
-	
-	// only ouput the persons using a frame
-	
-	frame.put("@type", ns +"Person");
-	jenaCtx.set(JsonLDWriter.JSONLD_FRAME, JsonUtils.fromString(frame.toString()));
-	String jsonld = toString(m, RDFFormat.JSONLD_FRAME_PRETTY, jenaCtx);
-	Model m2 = parse(jsonld);
-	// 2 subjects with a type in m2
-	assertTrue(m2.listStatements((Resource) null, RDF.type, (RDFNode) null).toList().size() == 2);
-	// 2 persons in m2
-	assertTrue(m2.listStatements((Resource) null, RDF.type, person).toList().size() == 2);
-	// something we hadn't tested in prettyIsNotFlat
-	assertTrue(jsonld.trim().indexOf("\n") > -1);
-	
-	// only output the subjects which have a jobTitle
-	
-	frame = new JsonObject();
-	frame.put("http://schema.org/jobTitle", new JsonObject());
-	jenaCtx.set(JsonLDWriter.JSONLD_FRAME, JsonUtils.fromString(frame.toString()));
-	jsonld = toString(m, RDFFormat.JSONLD_FRAME_FLAT, jenaCtx);
-	m2 = parse(jsonld);
-	// 1 subject with a type in m2
-	assertTrue(m2.listStatements((Resource) null, RDF.type, (RDFNode) null).toList().size() == 1);
-	// 1 subject with a jobTitle in m2
-	assertTrue(m2.listStatements((Resource) null, m.createProperty(ns + "jobTitle"), (RDFNode) null).toList().size() == 1);
-	// something we hadn't tested in prettyIsNotFlat
-	assertTrue(jsonld.trim().indexOf("\n") < 0);
-}
+    private Model simpleModel() {
+        Model m = ModelFactory.createDefaultModel();
+        String url = "http://www.a.com/foo/";
+        Resource s = m.createResource(url + "s");
+        Property p = m.createProperty(url + "p");
+        Resource o = m.createResource(url + "o");
+        m.add(s,p,o);
+        return m;
+    }
 
-/**
- * There was a problem with props taking a string as value.
- * cf https://mail-archives.apache.org/mod_mbox/jena-users/201604.mbox/%3c218AC4A3-030B-4248-A7DA-2B2597328242@gmail.com%3e
- */
-@Test public final void testStringPropsInContext() {
-	Model m = ModelFactory.createDefaultModel();
-	String ns = "http://www.a.com/foo/";
-	Resource s = m.createResource(ns + "s");
-	m.add(s,m.createProperty(ns + "plangstring"),"a langstring","fr");
-	m.add(s, m.createProperty(ns + "pint"), m.createTypedLiteral(42));
-	m.add(s, m.createProperty(ns + "pfloat"), m.createTypedLiteral((float) 1789.14));
-	m.add(s, m.createProperty(ns + "pstring"), m.createTypedLiteral("a TypedLiteral atring"));
-
-	String jsonld = toString(m, RDFFormat.JSONLD_FLAT, null);
-	
-	// without following line in JsonLDWriter, the test fails 
-	// if (! isLangString(o) && ! isSimpleString(o) )
-	String vv = "\"plangstring\":{\"@language\":\"fr\",\"@value\":\"a langstring\"}";
-	assertTrue(jsonld.indexOf(vv) > -1);
-}
+    /**
+     * Write a model and parse it back: you should get the same thing
+     * (except with frame)
+     */
+    @Test public final void roundTrip() {
+        Model m = simpleModel();
+        m.setNsPrefix("ex", "http://www.a.com/foo/");
+        for (RDFFormat f : JSON_LD_FORMATS) {
+            if (((RDFFormat.JSONLDVariant) f.getVariant()).isFrame()) continue;
+            String s = toString(m, f, null);
+            Model m2 = parse(s);
+            assertTrue(m2.isIsomorphicWith(m));        
+        }
+    }
 
-//
-// some utilities
-//
-
-private String toString(Model m, RDFFormat f, Context jenaContext) {
-	try {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		RDFDataMgr.write(out, m, f, jenaContext) ;
-		out.flush();
-		String x = out.toString("UTF-8");
-		out.close();
-		return x;
-	} catch (IOException e) { throw new RuntimeException(e); }
-}
+    //@Test public final void supportEmptyNs() {
+    //    Model m = ModelFactory.createDefaultModel();
+    //    String ns = "http://www.a.com/foo/";
+    //    Resource s = m.createResource(ns + "s");
+    //    Property p = m.createProperty(ns + "p");
+    //    Resource o = m.createResource(ns + "o");
+    //    m.add(s,p,o);
+    //    m.add(m.createResource(ns + "s2"),p,m.createResource(ns + "o2"));
+    //    m.setNsPrefix("ns", ns);
+    //    Model m2 = parse(toJsonLDString(m));
+    //    assertTrue(m2.isIsomorphicWith(m));
+    //    
+    //    // RDFDataMgr.write(DevNull.out, m, RDFFormat.JSONLD) ;
+    //    RDFDataMgr.write(System.out, m2, RDFFormat.TURTLE);
+    //    RDFDataMgr.write(System.out, m, RDFFormat.JSONLD);
+    //}
 
-private Model parse(String jsonld) {
-	Model m = ModelFactory.createDefaultModel();
-	StringReader reader = new StringReader(jsonld);
-	m.read(reader, null, "JSON-LD");
-	return m;
-}
+    /** verify that one may pass a context as a JSON string, and that it is actually used in the output */
+    @Test public void testSettingContextAsJsonString() {
+        // 1) get the context generated by default by jena
+        // for a simple model with a prefix declaration
+        // 2) remove prefix declaration from model,
+        // output as jsonld is different
+        // 3) output the model as jsonld using the context:
+        // we should get the same output as in 1
+        Model m = ModelFactory.createDefaultModel();
+        String url = "http://www.semanlink.net/test/";
+        Resource s = m.createResource(url + "s");
+        Property p = m.createProperty(url + "p");
+        Resource o = m.createResource(url + "o");
+        m.add(s,p,o);
+        m.setNsPrefix("ex", url);
+
+        String s1 = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, null);
+        // there's a prefix in m, and we find it in the output
+        String prefixStringInResult = "\"ex\":\"" + url + "\"";
+        assertTrue(s1.indexOf(prefixStringInResult) > 0);
+        Model m1 = parse(s1);
+
+        // must we pass the json object associated to "@context",
+        // or its parent node (that is, with the "@context") ?
+        // Actually, we can do both (JSONLD-java's code ensure it)
+        // We check it for here
+
+        // this is json object associated to "@context" in s1
+        // it includes the "ex" prefix
+
+        String js = "{\"p\":{\"@id\":\"http://www.semanlink.net/test/p\",\"@type\":\"@id\"},\"ex\":\"http://www.semanlink.net/test/\"}";
+
+        // remove the prefix from m
+        m.removeNsPrefix("ex");    // RDFDataMgr.write(System.out, m, RDFFormat.JSONLD) ;
+        String s2 = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
+        // model wo prefix -> no more prefix string in result:
+        assertTrue(s2.indexOf(prefixStringInResult) < 0);
+
+        // the model wo prefix, outputed as jsonld using a context that defines the prefix    
+        Context jenaCtx = new Context();
+        jenaCtx.set(JsonLDWriter.JSONLD_CONTEXT, js);
+        String s3 = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, jenaCtx);
+
+        assertTrue(s3.length() == s1.length());
+        assertTrue(s3.indexOf(prefixStringInResult) > 0);
+        Model m3 = parse(s3);
+        assertTrue(m3.isIsomorphicWith(m));
+        assertTrue(m3.isIsomorphicWith(m1));
+
+        // same thing, but passing also the "@context"
+        js = "{\"@context\":" + js + "}";
+        jenaCtx.set(JsonLDWriter.JSONLD_CONTEXT, js);
+        String s4 = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, jenaCtx);
+
+        assertTrue(s4.length() == s1.length());
+        assertTrue(s4.indexOf(prefixStringInResult) > 0);
+        Model m4 = parse(s4);
+        assertTrue(m4.isIsomorphicWith(m));
+        assertTrue(m4.isIsomorphicWith(m1));
+    }
+
+    /**
+     * Checks that one can pass a context defined by its URI
+     */
+    @Test public final void testContextByUri() {
+        Model m = ModelFactory.createDefaultModel();
+        String ns = "http://schema.org/";
+        Resource s = m.createResource();
+        m.add(s, m.createProperty(ns + "name"), "Jane Doe");
+        m.add(s, m.createProperty(ns + "url"), "http://www.janedoe.com");
+        m.add(s, RDF.type, "Person");
+
+        // we can pass a uri in the context, as a quoted string (it is a JSON string)
+        Context jenaContext = new Context();
+        try {
+            // jenaContext.set(JsonLDWriter.JSONLD_CONTEXT, "http://schema.org/");
+            // beware, it must be quoted, as it is supposed to be a json string
+            jenaContext.set(JsonLDWriter.JSONLD_CONTEXT, "\"http://schema.org/\"");
+            String jsonld = toString(m, RDFFormat.JSONLD, jenaContext);
+        } catch (Throwable e) {
+            Logger.getLogger(getClass()).info("Sorry to get this exception",e);
+        }
+
+        // But anyway, that's not what we want to do:
+        // there's no point in passing the uri of a context to have it dereferenced by jsonld-java
+        // (this is for a situation where one would want to parse a jsonld file containing a context defined by a uri)
+        // What we want is to pass a context to jsonld-java (in order for json-ld java to produce the correct jsonls output
+        // and then we want to replace the @context in the output by "@context":"ourUri"
+
+        // How would we do that? see testSubstitutingContext()
+    }
+
+    /**
+     * This generates a warning, but one may pass a context directly as the object
+     * used by the JSON-LD java API.
+     */
+    @Test public void testSettingContextAsObjectExpectedByJsonldAPI() {
+        // 1) get the context generated by default by jena
+        // for a simple model with a prefix declaration
+        // 2) remove prefix declaration from model,
+        // output as jsonld is different
+        // 3) output the model as jsonld using the context:
+        // we should get the same output as in 1
+        Model m = ModelFactory.createDefaultModel();
+        String url = "http://www.semanlink.net/test/";
+        Resource s = m.createResource(url + "s");
+        Property p = m.createProperty(url + "p");
+        Resource o = m.createResource(url + "o");
+        m.add(s,p,o);
+        m.setNsPrefix("ex", url);
+
+        String s1 = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
+        // there's a prefix in m, and we find it in the output
+        String prefixStringInResult = "\"ex\" : \"" + url + "\"";
+        assertTrue(s1.indexOf(prefixStringInResult) > 0);
+        Model m1 = parse(s1);
+
+        // the context used in this case, created automatically by jena as none is set
+        // it includes one prefix
+        Object ctx = JsonLDWriter.createJsonldContext(m.getGraph());
+
+        // remove the prefix from m
+        m.removeNsPrefix("ex");    // RDFDataMgr.write(System.out, m, RDFFormat.JSONLD) ;
+        String s2 = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, null);
+        // model wo prefix -> no more prefix string in result:
+        assertTrue(s2.indexOf(prefixStringInResult) < 0);
+
+        // the model wo prefix, output as jsonld using a context that defines the prefix
+        Context jenaCtx = new Context();
+        jenaCtx.set(JsonLDWriter.JSONLD_CONTEXT, ctx);
+        String s3 = toString(m, RDFFormat.JSONLD_COMPACT_PRETTY, jenaCtx);
+
+        assertTrue(s3.length() == s1.length());
+        assertTrue(s3.indexOf(prefixStringInResult) > 0);
+        Model m3 = parse(s3);
+        assertTrue(m3.isIsomorphicWith(m));
+        assertTrue(m3.isIsomorphicWith(m1));
+
+    }
+
+    /**
+     * Test using a context to compute the output, and replacing the @context with a given value
+     */
+    @Test public void testSubstitutingContext() {
+        Model m = ModelFactory.createDefaultModel();
+        String ns = "http://schema.org/";
+        Resource person = m.createResource(ns + "Person");
+        Resource s = m.createResource();
+        m.add(s, m.createProperty(ns + "name"), "Jane Doe");
+        m.add(s, m.createProperty(ns + "url"), "http://www.janedoe.com");
+        m.add(s, m.createProperty(ns + "jobTitle"), "Professor");
+        m.add(s, RDF.type, person);
+
+        Context jenaCtx = new Context();
+        jenaCtx.set(JsonLDWriter.JSONLD_CONTEXT_SUBSTITUTION, "\"" + ns + "\"");
+
+        String jsonld = toString(m, RDFFormat.JSONLD_COMPACT_FLAT, jenaCtx);
+        String c = "\"@context\":\"http://schema.org/\"";
+        assertTrue(jsonld.indexOf(c) > -1);
+    }
+
+
+    /**
+     * Checking frames
+     */
+    @Test public final void testFrames() throws JsonParseException, IOException {
+        Model m = ModelFactory.createDefaultModel();
+        String ns = "http://schema.org/";
+        Resource person = m.createResource(ns + "Person");
+        Resource s = m.createResource();
+        m.add(s, m.createProperty(ns + "name"), "Jane Doe");
+        m.add(s, m.createProperty(ns + "url"), "http://www.janedoe.com");
+        m.add(s, m.createProperty(ns + "jobTitle"), "Professor");
+        m.add(s, RDF.type, person);
+        s = m.createResource();
+        m.add(s, m.createProperty(ns + "name"), "Gado Salamatou");
+        m.add(s, m.createProperty(ns + "url"), "http://www.salamatou.com");
+        m.add(s, RDF.type, person);
+        s = m.createResource();
+        m.add(s, m.createProperty(ns + "name"), "Not a person");
+        m.add(s, RDF.type, m.createResource(ns + "Event"));
+
+        Context jenaCtx = new Context();
+        JsonObject frame = new JsonObject();
+
+        // only output the persons using a frame
+
+        frame.put("@type", ns +"Person");
+        jenaCtx.set(JsonLDWriter.JSONLD_FRAME, JsonUtils.fromString(frame.toString()));
+        String jsonld = toString(m, RDFFormat.JSONLD_FRAME_PRETTY, jenaCtx);
+        Model m2 = parse(jsonld);
+        // 2 subjects with a type in m2
+        assertTrue(m2.listStatements((Resource) null, RDF.type, (RDFNode) null).toList().size() == 2);
+        // 2 persons in m2
+        assertTrue(m2.listStatements((Resource) null, RDF.type, person).toList().size() == 2);
+        // something we hadn't tested in prettyIsNotFlat
+        assertTrue(jsonld.trim().indexOf("\n") > -1);
+
+        // only output the subjects which have a jobTitle
+
+        frame = new JsonObject();
+        frame.put("http://schema.org/jobTitle", new JsonObject());
+        jenaCtx.set(JsonLDWriter.JSONLD_FRAME, JsonUtils.fromString(frame.toString()));
+        jsonld = toString(m, RDFFormat.JSONLD_FRAME_FLAT, jenaCtx);
+        m2 = parse(jsonld);
+        // 1 subject with a type in m2
+        assertTrue(m2.listStatements((Resource) null, RDF.type, (RDFNode) null).toList().size() == 1);
+        // 1 subject with a jobTitle in m2
+        assertTrue(m2.listStatements((Resource) null, m.createProperty(ns + "jobTitle"), (RDFNode) null).toList().size() == 1);
+        // something we hadn't tested in prettyIsNotFlat
+        assertTrue(jsonld.trim().indexOf("\n") < 0);
+    }
+
+    /**
+     * There was a problem with props taking a string as value.
+     * cf https://mail-archives.apache.org/mod_mbox/jena-users/201604.mbox/%3c218AC4A3-030B-4248-A7DA-2B2597328242@gmail.com%3e
+     */
+    @Test public final void testStringPropsInContext() {
+        Model m = ModelFactory.createDefaultModel();
+        String ns = "http://www.a.com/foo/";
+        Resource s = m.createResource(ns + "s");
+        m.add(s,m.createProperty(ns + "plangstring"),"a langstring","fr");
+        m.add(s, m.createProperty(ns + "pint"), m.createTypedLiteral(42));
+        m.add(s, m.createProperty(ns + "pfloat"), m.createTypedLiteral((float) 1789.14));
+        m.add(s, m.createProperty(ns + "pstring"), m.createTypedLiteral("a TypedLiteral atring"));
+
+        String jsonld = toString(m, RDFFormat.JSONLD_FLAT, null);
+
+        // without following line in JsonLDWriter, the test fails 
+        // if (! isLangString(o) && ! isSimpleString(o) )
+        String vv = "\"plangstring\":{\"@language\":\"fr\",\"@value\":\"a langstring\"}";
+        assertTrue(jsonld.indexOf(vv) > -1);
+    }
+
+    //
+    // some utilities
+    //
+
+    private String toString(Model m, RDFFormat f, Context jenaContext) {
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            // RDFDataMgr.write(out, m, f, jenaContext) ;
+
+
+            WriterDatasetRIOT w = RDFDataMgr.createDatasetWriter(f) ;
+            DatasetGraph g = DatasetFactory.create(m).asDatasetGraph();
+            PrefixMap pm = RiotLib.prefixMap(g);
+            String base = null;
+            w.write(out,  g, pm, base, jenaContext) ;
+
+
+            out.flush();
+            String x = out.toString("UTF-8");
+            out.close();
+            return x;
+        } catch (IOException e) { throw new RuntimeException(e); }
+    }
+
+    private Model parse(String jsonld) {
+        Model m = ModelFactory.createDefaultModel();
+        StringReader reader = new StringReader(jsonld);
+        m.read(reader, null, "JSON-LD");
+        return m;
+    }
 
-private static RDFFormat[] JSON_LD_FORMATS = {
-		RDFFormat.JSONLD_COMPACT_PRETTY,
-		RDFFormat.JSONLD_FLATTEN_PRETTY,
-		RDFFormat.JSONLD_EXPAND_PRETTY,
-		RDFFormat.JSONLD_FRAME_PRETTY,
-		RDFFormat.JSONLD_COMPACT_FLAT,
-		RDFFormat.JSONLD_FLATTEN_FLAT,
-		RDFFormat.JSONLD_EXPAND_FLAT,
-		RDFFormat.JSONLD_FRAME_FLAT,
-};
+    private static RDFFormat[] JSON_LD_FORMATS = {
+            RDFFormat.JSONLD_COMPACT_PRETTY,
+            RDFFormat.JSONLD_FLATTEN_PRETTY,
+            RDFFormat.JSONLD_EXPAND_PRETTY,
+            RDFFormat.JSONLD_FRAME_PRETTY,
+            RDFFormat.JSONLD_COMPACT_FLAT,
+            RDFFormat.JSONLD_FLATTEN_FLAT,
+            RDFFormat.JSONLD_EXPAND_FLAT,
+            RDFFormat.JSONLD_FRAME_FLAT,
+    };
 }