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