001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.jena;
014
015import static org.apache.juneau.internal.CollectionUtils.*;
016
017import java.util.*;
018import java.util.concurrent.*;
019
020import org.apache.juneau.*;
021import org.apache.juneau.annotation.*;
022import org.apache.juneau.jena.annotation.*;
023import org.apache.juneau.serializer.*;
024import org.apache.juneau.xml.*;
025import org.apache.juneau.xml.annotation.*;
026
027/**
028 * Serializes POJOs to RDF.
029 *
030 * <h5 class='topic'>Behavior-specific subclasses</h5>
031 *
032 * The following direct subclasses are provided for language-specific serializers:
033 * <ul>
034 *    <li>{@link RdfXmlSerializer} - RDF/XML.
035 *    <li>{@link RdfXmlAbbrevSerializer} - RDF/XML-ABBREV.
036 *    <li>{@link NTripleSerializer} - N-TRIPLE.
037 *    <li>{@link TurtleSerializer} - TURTLE.
038 *    <li>{@link N3Serializer} - N3.
039 * </ul>
040 *
041 * <ul class='seealso'>
042 *    <li class='link'>{@doc juneau-marshall-rdf}
043 * </ul>
044 */
045@ConfigurableContext(prefixes={RdfCommon.PREFIX,RdfSerializer.PREFIX})
046public class RdfSerializer extends WriterSerializer implements RdfCommon, RdfMetaProvider {
047
048   private static final Namespace
049      DEFAULT_JUNEAU_NS = Namespace.create("j", "http://www.apache.org/juneau/"),
050      DEFAULT_JUNEAUBP_NS = Namespace.create("jp", "http://www.apache.org/juneaubp/");
051
052   //-------------------------------------------------------------------------------------------------------------------
053   // Configurable properties
054   //-------------------------------------------------------------------------------------------------------------------
055
056   static final String PREFIX = "RdfSerializer";
057
058   /**
059    * Configuration property:  Add <js>"_type"</js> properties when needed.
060    *
061    * <h5 class='section'>Property:</h5>
062    * <ul class='spaced-list'>
063    *    <li><b>ID:</b>  {@link org.apache.juneau.jena.RdfSerializer#RDF_addBeanTypes RDF_addBeanTypes}
064    *    <li><b>Name:</b>  <js>"RdfSerializer.addBeanTypes.b"</js>
065    *    <li><b>Data type:</b>  <jk>boolean</jk>
066    *    <li><b>System property:</b>  <c>RdfSerializer.addBeanTypes</c>
067    *    <li><b>Environment variable:</b>  <c>RDFSERIALIZER_ADDBEANTYPES</c>
068    *    <li><b>Default:</b>  <jk>false</jk>
069    *    <li><b>Session property:</b>  <jk>false</jk>
070    *    <li><b>Annotations:</b>
071    *       <ul>
072    *          <li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig#addBeanTypes()}
073    *       </ul>
074    *    <li><b>Methods:</b>
075    *       <ul>
076    *          <li class='jm'>{@link org.apache.juneau.jena.RdfSerializerBuilder#addBeanTypes(boolean)}
077    *       </ul>
078    * </ul>
079    *
080    * <h5 class='section'>Description:</h5>
081    * <p>
082    * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
083    * through reflection.
084    *
085    * <p>
086    * When present, this value overrides the {@link #SERIALIZER_addBeanTypes} setting and is
087    * provided to customize the behavior of specific serializers in a {@link SerializerGroup}.
088    */
089   public static final String RDF_addBeanTypes = PREFIX + ".addBeanTypes.b";
090
091   /**
092    * Configuration property:  Add XSI data types to non-<c>String</c> literals.
093    *
094    * <h5 class='section'>Property:</h5>
095    * <ul class='spaced-list'>
096    *    <li><b>ID:</b>  {@link org.apache.juneau.jena.RdfSerializer#RDF_addLiteralTypes RDF_addLiteralTypes}
097    *    <li><b>Name:</b>  <js>"RdfSerializer.addLiteralTypes.b"</js>
098    *    <li><b>Data type:</b>  <jk>boolean</jk>
099    *    <li><b>System property:</b>  <c>RdfSerializer.addLiteralTypes</c>
100    *    <li><b>Environment variable:</b>  <c>RDFSERIALIZER_ADDLITERALTYPES</c>
101    *    <li><b>Default:</b>  <jk>false</jk>
102    *    <li><b>Session property:</b>  <jk>false</jk>
103    *    <li><b>Annotations:</b>
104    *       <ul>
105    *          <li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig#addLiteralTypes()}
106    *       </ul>
107    *    <li><b>Methods:</b>
108    *       <ul>
109    *          <li class='jm'>{@link org.apache.juneau.jena.RdfSerializerBuilder#addLiteralTypes(boolean)}
110    *          <li class='jm'>{@link org.apache.juneau.jena.RdfSerializerBuilder#addLiteralTypes()}
111    *       </ul>
112    * </ul>
113    */
114   public static final String RDF_addLiteralTypes = PREFIX + ".addLiteralTypes.b";
115
116   /**
117    * Configuration property:  Add RDF root identifier property to root node.
118    *
119    * <h5 class='section'>Property:</h5>
120    * <ul class='spaced-list'>
121    *    <li><b>ID:</b>  {@link org.apache.juneau.jena.RdfSerializer#RDF_addRootProperty RDF_addRootProperty}
122    *    <li><b>Name:</b>  <js>"RdfSerializer.addRootProperty.b"</js>
123    *    <li><b>Data type:</b>  <jk>boolean</jk>
124    *    <li><b>System property:</b>  <c>RdfSerializer.addRootProperty</c>
125    *    <li><b>Environment variable:</b>  <c>RDFSERIALIZER_ADDROOTPROPERTY</c>
126    *    <li><b>Default:</b>  <jk>false</jk>
127    *    <li><b>Session property:</b>  <jk>false</jk>
128    *    <li><b>Annotations:</b>
129    *       <ul>
130    *          <li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig#addRootProperty()}
131    *       </ul>
132    *    <li><b>Methods:</b>
133    *       <ul>
134    *          <li class='jm'>{@link org.apache.juneau.jena.RdfSerializerBuilder#addRootProperty(boolean)}
135    *          <li class='jm'>{@link org.apache.juneau.jena.RdfSerializerBuilder#addRootProperty()}
136    *       </ul>
137    * </ul>
138    *
139    * <h5 class='section'>Description:</h5>
140    * <p>
141    * When enabled an RDF property <c>http://www.apache.org/juneau/root</c> is added with a value of <js>"true"</js>
142    * to identify the root node in the graph.
143    * <br>This helps locate the root node during parsing.
144    *
145    * <p>
146    * If disabled, the parser has to search through the model to find any resources without incoming predicates to
147    * identify root notes, which can introduce a considerable performance degradation.
148    */
149   public static final String RDF_addRootProperty = PREFIX + ".addRootProperty.b";
150
151   /**
152    * Configuration property:  Auto-detect namespace usage.
153    *
154    * <h5 class='section'>Property:</h5>
155    * <ul class='spaced-list'>
156    *    <li><b>ID:</b>  {@link org.apache.juneau.jena.RdfSerializer#RDF_autoDetectNamespaces RDF_autoDetectNamespaces}
157    *    <li><b>Name:</b>  <js>"RdfSerializer.autoDetectNamespaces.b"</js>
158    *    <li><b>Data type:</b>  <jk>boolean</jk>
159    *    <li><b>System property:</b>  <c>RdfSerializer.autoDetectNamespaces</c>
160    *    <li><b>Environment variable:</b>  <c>RDFSERIALIZER_AUTODETECTNAMESPACES</c>
161    *    <li><b>Default:</b>  <jk>true</jk>
162    *    <li><b>Session property:</b>  <jk>false</jk>
163    *    <li><b>Annotations:</b>
164    *       <ul>
165    *          <li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig#autoDetectNamespaces()}
166    *       </ul>
167    *    <li><b>Methods:</b>
168    *       <ul>
169    *          <li class='jm'>{@link org.apache.juneau.jena.RdfSerializerBuilder#autoDetectNamespaces(boolean)}
170    *       </ul>
171    * </ul>
172    *
173    * <h5 class='section'>Description:</h5>
174    * <p>
175    * Detect namespace usage before serialization.
176    *
177    * <p>
178    * If enabled, then the data structure will first be crawled looking for namespaces that will be encountered before
179    * the root element is serialized.
180    */
181   public static final String RDF_autoDetectNamespaces = PREFIX + ".autoDetectNamespaces.b";
182
183   /**
184    * Configuration property:  Default namespaces.
185    *
186    * <h5 class='section'>Property:</h5>
187    * <ul class='spaced-list'>
188    *    <li><b>ID:</b>  {@link org.apache.juneau.jena.RdfSerializer#RDF_namespaces RDF_namespaces}
189    *    <li><b>Name:</b>  <js>"RdfSerializer.namespaces.ls"</js>
190    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.xml.Namespace}&gt;</c>
191    *    <li><b>System property:</b>  <c>RdfSerializer.namespaces</c>
192    *    <li><b>Environment variable:</b>  <c>RDFSERIALIZER_NAMESPACES</c>
193    *    <li><b>Default:</b>  empty list
194    *    <li><b>Session property:</b>  <jk>false</jk>
195    *    <li><b>Annotations:</b>
196    *       <ul>
197    *          <li class='ja'>{@link org.apache.juneau.jena.annotation.Rdf#namespace()}
198    *          <li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig#namespaces()}
199    *       </ul>
200    *    <li><b>Methods:</b>
201    *       <ul>
202    *          <li class='jm'>{@link org.apache.juneau.jena.RdfSerializerBuilder#namespaces(Namespace...)}
203    *       </ul>
204    * </ul>
205    *
206    * <h5 class='section'>Description:</h5>
207    * <p>
208    * The default list of namespaces associated with this serializer.
209    */
210   public static final String RDF_namespaces = PREFIX + ".namespaces.ls";
211
212   /**
213    * Configuration property:  Reuse XML namespaces when RDF namespaces not specified.
214    *
215    * <h5 class='section'>Property:</h5>
216    * <ul class='spaced-list'>
217    *    <li><b>ID:</b>  {@link org.apache.juneau.jena.RdfSerializer#RDF_useXmlNamespaces RDF_useXmlNamespaces}
218    *    <li><b>Name:</b>  <js>"Rdf.useXmlNamespaces.b"</js>
219    *    <li><b>Data type:</b>  <jk>boolean</jk>
220    *    <li><b>System property:</b>  <c>Rdf.useXmlNamespaces</c>
221    *    <li><b>Environment variable:</b>  <c>RDFSERIALIZER_USEXMLNAMESPACES</c>
222    *    <li><b>Default:</b>  <jk>true</jk>
223    *    <li><b>Annotations:</b>
224    *       <ul>
225    *          <li class='ja'>{@link org.apache.juneau.jena.annotation.RdfConfig#useXmlNamespaces()}
226    *       </ul>
227    *    <li><b>Methods:</b>
228    *       <ul>
229    *          <li class='jm'>{@link org.apache.juneau.jena.RdfSerializerBuilder#useXmlNamespaces(boolean)}
230    *       </ul>
231    * </ul>
232    *
233    * <h5 class='section'>Description:</h5>
234    * <p>
235    * When specified, namespaces defined using {@link XmlNs @XmlNs} and {@link Xml @Xml} will be inherited by the RDF serializers.
236    * <br>Otherwise, namespaces will be defined using {@link RdfNs @RdfNs} and {@link Rdf @Rdf}.
237    */
238   public static final String RDF_useXmlNamespaces = PREFIX + ".useXmlNamespaces.b";
239
240   //-------------------------------------------------------------------------------------------------------------------
241   // Instance
242   //-------------------------------------------------------------------------------------------------------------------
243
244   private final boolean
245      addLiteralTypes,
246      addRootProperty,
247      useXmlNamespaces,
248      looseCollections,
249      autoDetectNamespaces,
250      addBeanTypes;
251   private final String rdfLanguage;
252   private final Namespace juneauNs;
253   private final Namespace juneauBpNs;
254   private final RdfCollectionFormat collectionFormat;
255   final Map<String,Object> jenaProperties;
256   final Namespace[] namespaces;
257
258   private final Map<ClassMeta<?>,RdfClassMeta> rdfClassMetas = new ConcurrentHashMap<>();
259   private final Map<BeanMeta<?>,RdfBeanMeta> rdfBeanMetas = new ConcurrentHashMap<>();
260   private final Map<BeanPropertyMeta,RdfBeanPropertyMeta> rdfBeanPropertyMetas = new ConcurrentHashMap<>();
261
262   private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>();
263   private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>();
264   private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>();
265
266   /**
267    * Constructor.
268    *
269    * @param ps
270    *    The property store containing all the settings for this object.
271    * @param produces
272    *    The media type that this serializer produces.
273    * @param accept
274    *    The accept media types that the serializer can handle.
275    *    <p>
276    *    Can contain meta-characters per the <c>media-type</c> specification of {@doc RFC2616.section14.1}
277    *    <p>
278    *    If empty, then assumes the only media type supported is <c>produces</c>.
279    *    <p>
280    *    For example, if this serializer produces <js>"application/json"</js> but should handle media types of
281    *    <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
282    *    <p class='bcode w800'>
283    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
284    *    </p>
285    *    <br>...or...
286    *    <p class='bcode w800'>
287    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
288    *    </p>
289    * <p>
290    * The accept value can also contain q-values.
291    */
292   public RdfSerializer(PropertyStore ps, String produces, String accept) {
293      super(ps, produces, accept);
294      addLiteralTypes = getBooleanProperty(RDF_addLiteralTypes, false);
295      addRootProperty = getBooleanProperty(RDF_addRootProperty, false);
296      useXmlNamespaces = getBooleanProperty(RDF_useXmlNamespaces, true);
297      looseCollections = getBooleanProperty(RDF_looseCollections, false);
298      autoDetectNamespaces = getBooleanProperty(RDF_autoDetectNamespaces, true);
299      rdfLanguage = getStringProperty(RDF_language, "RDF/XML-ABBREV");
300      juneauNs = getProperty(RDF_juneauNs, Namespace.class, DEFAULT_JUNEAU_NS);
301      juneauBpNs = getProperty(RDF_juneauBpNs, Namespace.class, DEFAULT_JUNEAUBP_NS);
302      collectionFormat = getProperty(RDF_collectionFormat, RdfCollectionFormat.class, RdfCollectionFormat.DEFAULT);
303      namespaces = getProperty(RDF_namespaces, Namespace[].class, new Namespace[0]);
304      addBeanTypes = getBooleanProperty(RDF_addBeanTypes, getBooleanProperty(SERIALIZER_addBeanTypes, false));
305
306      Map<String,Object> m = new TreeMap<>();
307      for (String k : getPropertyKeys("RdfCommon"))
308         if (k.startsWith("jena."))
309            m.put(k.substring(5), getProperty("RdfCommon." + k));
310      jenaProperties = unmodifiableMap(m);
311   }
312
313   /**
314    * Constructor.
315    *
316    * @param ps
317    *    The property store containing all the settings for this object.
318    */
319   public RdfSerializer(PropertyStore ps) {
320      this(ps, "text/xml+rdf", (String)null);
321   }
322
323
324   @Override /* Context */
325   public RdfSerializerBuilder builder() {
326      return new RdfSerializerBuilder(getPropertyStore());
327   }
328
329   /**
330    * Instantiates a new clean-slate {@link RdfSerializerBuilder} object.
331    *
332    * <p>
333    * This is equivalent to simply calling <code><jk>new</jk> RdfSerializerBuilder()</code>.
334    *
335    * <p>
336    * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies
337    * the settings of the object called on.
338    *
339    * @return A new {@link RdfSerializerBuilder} object.
340    */
341   public static RdfSerializerBuilder create() {
342      return new RdfSerializerBuilder();
343   }
344
345   @Override /* Context */
346   public  RdfSerializerSession createSession() {
347      return createSession(createDefaultSessionArgs());
348   }
349
350   @Override /* Serializer */
351   public RdfSerializerSession createSession(SerializerSessionArgs args) {
352      return new RdfSerializerSession(this, args);
353   }
354
355   //-----------------------------------------------------------------------------------------------------------------
356   // Extended metadata
357   //-----------------------------------------------------------------------------------------------------------------
358
359   @Override /* RdfMetaProvider */
360   public RdfClassMeta getRdfClassMeta(ClassMeta<?> cm) {
361      RdfClassMeta m = rdfClassMetas.get(cm);
362      if (m == null) {
363         m = new RdfClassMeta(cm, this);
364         rdfClassMetas.put(cm, m);
365      }
366      return m;
367   }
368
369   @Override /* RdfMetaProvider */
370   public RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm) {
371      RdfBeanMeta m = rdfBeanMetas.get(bm);
372      if (m == null) {
373         m = new RdfBeanMeta(bm, this);
374         rdfBeanMetas.put(bm, m);
375      }
376      return m;
377   }
378
379   @Override /* RdfMetaProvider */
380   public RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm) {
381      RdfBeanPropertyMeta m = rdfBeanPropertyMetas.get(bpm);
382      if (m == null) {
383         m = new RdfBeanPropertyMeta(bpm.getDelegateFor(), this);
384         rdfBeanPropertyMetas.put(bpm, m);
385      }
386      return m;
387   }
388
389   @Override /* XmlMetaProvider */
390   public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {
391      XmlClassMeta m = xmlClassMetas.get(cm);
392      if (m == null) {
393         m = new XmlClassMeta(cm, this);
394         xmlClassMetas.put(cm, m);
395      }
396      return m;
397   }
398
399   @Override /* XmlMetaProvider */
400   public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {
401      XmlBeanMeta m = xmlBeanMetas.get(bm);
402      if (m == null) {
403         m = new XmlBeanMeta(bm, this);
404         xmlBeanMetas.put(bm, m);
405      }
406      return m;
407   }
408
409   @Override /* XmlMetaProvider */
410   public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {
411      XmlBeanPropertyMeta m = xmlBeanPropertyMetas.get(bpm);
412      if (m == null) {
413         m = new XmlBeanPropertyMeta(bpm.getDelegateFor(), this);
414         xmlBeanPropertyMetas.put(bpm, m);
415      }
416      return m;
417   }
418
419   //-----------------------------------------------------------------------------------------------------------------
420   // Common properties
421   //-----------------------------------------------------------------------------------------------------------------
422
423   /**
424    * Configuration property:  RDF format for representing collections and arrays.
425    *
426    * @see #RDF_collectionFormat
427    * @return
428    *    RDF format for representing collections and arrays.
429    */
430   protected final RdfCollectionFormat getCollectionFormat() {
431      return collectionFormat;
432   }
433
434   /**
435    * Configuration property:  Default XML namespace for bean properties.
436    *
437    * @see #RDF_juneauBpNs
438    * @return
439    *    The XML namespace to use for bean properties.
440    */
441   protected final Namespace getJuneauBpNs() {
442      return juneauBpNs;
443   }
444
445   /**
446    * Configuration property:  XML namespace for Juneau properties.
447    *
448    * @see #RDF_juneauNs
449    * @return
450    *    The XML namespace to use for Juneau properties.
451    */
452   protected final Namespace getJuneauNs() {
453      return juneauNs;
454   }
455
456   /**
457    * Configuration property:  RDF language.
458    *
459    * @see #RDF_language
460    * @return
461    *    The RDF language to use.
462    */
463   protected final String getLanguage() {
464      return rdfLanguage;
465   }
466
467   /**
468    * Configuration property:  Collections should be serialized and parsed as loose collections.
469    *
470    * @see #RDF_looseCollections
471    * @return
472    *    <jk>true</jk> if collections of resources are handled as loose collections of resources in RDF instead of
473    *    resources that are children of an RDF collection (e.g. Sequence, Bag).
474    */
475   protected final boolean isLooseCollections() {
476      return looseCollections;
477   }
478
479   //-----------------------------------------------------------------------------------------------------------------
480   // Jena properties
481   //-----------------------------------------------------------------------------------------------------------------
482
483   /**
484    * Configuration property:  All Jena-related configuration properties.
485    *
486    * @return
487    *    A map of all Jena-related configuration properties.
488    */
489   protected final Map<String,Object> getJenaProperties() {
490      return jenaProperties;
491   }
492
493   //-----------------------------------------------------------------------------------------------------------------
494   // Properties
495   //-----------------------------------------------------------------------------------------------------------------
496
497   /**
498    * Configuration property:  Add <js>"_type"</js> properties when needed.
499    *
500    * @see #RDF_addBeanTypes
501    * @return
502    *    <jk>true</jk> if <js>"_type"</js> properties will be added to beans if their type cannot be inferred
503    *    through reflection.
504    */
505   @Override
506   protected final boolean isAddBeanTypes() {
507      return addBeanTypes;
508   }
509
510   /**
511    * Configuration property:  Add XSI data types to non-<c>String</c> literals.
512    *
513    * @see #RDF_addLiteralTypes
514    * @return
515    *    <jk>true</jk> if XSI data types should be added to string literals.
516    */
517   protected final boolean isAddLiteralTypes() {
518      return addLiteralTypes;
519   }
520
521   /**
522    * Configuration property:  Add RDF root identifier property to root node.
523    *
524    * @see RdfSerializer#RDF_addRootProperty
525    * @return
526    *    <jk>true</jk> if RDF property <c>http://www.apache.org/juneau/root</c> is added with a value of <js>"true"</js>
527    *    to identify the root node in the graph.
528    */
529   protected final boolean isAddRootProp() {
530      return addRootProperty;
531   }
532
533   /**
534    * Configuration property:  Auto-detect namespace usage.
535    *
536    * @see #RDF_autoDetectNamespaces
537    * @return
538    *    <jk>true</jk> if namespaces usage should be detected before serialization.
539    */
540   protected final boolean isAutoDetectNamespaces() {
541      return autoDetectNamespaces;
542   }
543
544   /**
545    * Configuration property:  Default namespaces.
546    *
547    * @see #RDF_namespaces
548    * @return
549    *    The default list of namespaces associated with this serializer.
550    */
551   public Namespace[] getNamespaces() {
552      return namespaces;
553   }
554
555   /**
556    * Configuration property:  Reuse XML namespaces when RDF namespaces not specified.
557    *
558    * @see #RDF_useXmlNamespaces
559    * @return
560    *    <jk>true</jk> if namespaces defined using {@link XmlNs @XmlNs} and {@link Xml @Xml} will be inherited by the RDF serializers.
561    *    <br>Otherwise, namespaces will be defined using {@link RdfNs @RdfNs} and {@link Rdf @Rdf}.
562    */
563   protected final boolean isUseXmlNamespaces() {
564      return useXmlNamespaces;
565   }
566
567   //-----------------------------------------------------------------------------------------------------------------
568   // Other methods
569   //-----------------------------------------------------------------------------------------------------------------
570
571   @Override /* Context */
572   public ObjectMap toMap() {
573      return super.toMap()
574         .append("RdfSerializer", new DefaultFilteringObjectMap()
575            .append("addLiteralTypes", addLiteralTypes)
576            .append("addRootProperty", addRootProperty)
577            .append("useXmlNamespaces", useXmlNamespaces)
578            .append("looseCollections", looseCollections)
579            .append("autoDetectNamespaces", autoDetectNamespaces)
580            .append("rdfLanguage", rdfLanguage)
581            .append("juneauNs", juneauNs)
582            .append("juneauBpNs", juneauBpNs)
583            .append("collectionFormat", collectionFormat)
584            .append("namespaces", namespaces)
585            .append("addBeanTypes", addBeanTypes)
586         );
587   }
588}