http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/Rdf.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/Rdf.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/Rdf.java new file mode 100644 index 0000000..2812d71 --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/Rdf.java @@ -0,0 +1,77 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import org.apache.juneau.jena.*; + +/** + * Annotation for specifying options for RDF serializers. + * + * <p> + * Can be applied to Java packages, types, fields, and methods. + * + * <p> + * Can be used for the following: + * <ul> + * <li>Override the default behavior of how collections and arrays are serialized. + * </ul> + */ +@Documented +@Target({PACKAGE,TYPE,FIELD,METHOD}) +@Retention(RUNTIME) +@Inherited +public @interface Rdf { + + /** + * Sets the XML prefix of this property or class. + * + * <p> + * Must either be matched to a {@link #namespace()} annotation on the same object, parent object, or a {@link RdfNs} + * with the same name through the {@link RdfSchema#rdfNs()} annotation on the package. + */ + String prefix() default ""; + + /** + * Sets the namespace URI of this property or class. + * + * <p> + * Must be matched with a {@link #prefix()} annotation on this object, a parent object, or a {@link RdfNs} with the + * same name through the {@link RdfSchema#rdfNs()} annotation on the package. + */ + String namespace() default ""; + + /** + * The format for how collections (e.g. lists and arrays) are serialized in RDF. + * + * @see RdfCollectionFormat + */ + RdfCollectionFormat collectionFormat() default RdfCollectionFormat.DEFAULT; + + /** + * Marks a bean property as a resource URI identifier for the bean. + * + * <p> + * Has the following effects on the following serializers: + * <ul class='spaced-list'> + * <li> + * {@link RdfSerializer} - Will be rendered as the value of the <js>"rdf:about"</js> attribute + * for the bean. + * </ul> + */ + boolean beanUri() default false; +}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfNs.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfNs.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfNs.java new file mode 100644 index 0000000..d8d9aff --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfNs.java @@ -0,0 +1,40 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena.annotation; + +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Namespace name/URL mapping pair. + * + * <p> + * Used to identify a namespace/URI pair on a {@link RdfSchema#rdfNs()} annotation. + */ +@Documented +@Target({}) +@Retention(RUNTIME) +@Inherited +public @interface RdfNs { + + /** + * RDF namespace prefix. + */ + String prefix(); + + /** + * RDF namespace URL. + */ + String namespaceURI(); +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfSchema.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfSchema.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfSchema.java new file mode 100644 index 0000000..c840dcd --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfSchema.java @@ -0,0 +1,93 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Identifies the default RDF namespaces at the package level. + */ +@Documented +@Target(PACKAGE) +@Retention(RUNTIME) +@Inherited +public @interface RdfSchema { + + /** + * Sets the default RDF prefix for all classes in this and child packages. + * + * <p> + * Must either be matched with a {@link #namespace()} annotation, or an {@link #rdfNs()} mapping with the same + * {@link RdfNs#prefix} value. + */ + public String prefix() default ""; + + /** + * Sets the default RDF namespace URL for all classes in this and child packages. + * + * <p> + * Must either be matched with a {@link #prefix()} annotation, or an {@link #rdfNs()} mapping with the same + * {@link RdfNs#namespaceURI} value. + */ + public String namespace() default ""; + + /** + * Lists all namespace mappings to be used on all classes within this package. + * + * <p> + * The purpose of this annotation is to allow namespace mappings to be defined in a single location and referred to + * by name through just the {@link Rdf#prefix()} annotation. + * + * <p> + * Inherited by child packages. + * + * <h5 class='section'>Example:</h5> + * + * Contents of <code>package-info.java</code>... + * <p class='bcode'> + * <jc>// XML namespaces used within this package.</jc> + * <ja>@RdfSchema</ja>(prefix=<js>"ab"</js>, + * namespaces={ + * <ja>@RdfNs</ja>(prefix=<js>"ab"</js>, namespaceURI=<js>"http://www.apache.org/addressBook/"</js>), + * <ja>@RdfNs</ja>(prefix=<js>"per"</js>, namespaceURI=<js>"http://www.apache.org/person/"</js>), + * <ja>@RdfNs</ja>(prefix=<js>"addr"</js>, namespaceURI=<js>"http://www.apache.org/address/"</js>), + * <ja>@RdfNs</ja>(prefix=<js>"mail"</js>, namespaceURI="<js>http://www.apache.org/mail/"</js>) + * } + * ) + * <jk>package</jk> org.apache.juneau.examples.addressbook; + * <jk>import</jk> org.apache.juneau.rdf.annotation.*; + * </p> + * + * <p> + * Class in package using defined namespaces... + * <p class='bcode'> + * <jk>package</jk> org.apache.juneau.examples.addressbook; + * + * <jc>// Bean class, override "ab" namespace on package.</jc> + * <ja>@Rdf</ja>(prefix=<js>"addr"</js>) + * <jk>public class</jk> Address { + * + * <jc>// Bean property, use "addr" namespace on class.</jc> + * <jk>public int</jk> <jf>id</jf>; + * + * <jc>// Bean property, override with "mail" namespace.</jc> + * <ja>@Rdf</ja>(prefix=<js>"mail"</js>) + * <jk>public</jk> String <jf>street</jf>, <jf>city</jf>, <jf>state</jf>; + * } + * </p> + */ + public RdfNs[] rdfNs() default {}; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/package.html ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/package.html b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/package.html new file mode 100644 index 0000000..c72c12e --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/annotation/package.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<!-- +/*************************************************************************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + ***************************************************************************************************************************/ + --> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <style type="text/css"> + /* For viewing in Page Designer */ + @IMPORT url("../../../../../../../javadoc.css"); + + /* For viewing in REST interface */ + @IMPORT url("../htdocs/javadoc.css"); + body { + margin: 20px; + } + </style> + <script> + /* Replace all @code and @link tags. */ + window.onload = function() { + document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>'); + document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>'); + } + </script> +</head> +<body> +<p>RDF annotations</p> +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_HTML.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_HTML.png b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_HTML.png new file mode 100644 index 0000000..b4a3576 Binary files /dev/null and b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_HTML.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_N3.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_N3.png b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_N3.png new file mode 100644 index 0000000..16613a4 Binary files /dev/null and b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_N3.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_NTriple.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_NTriple.png b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_NTriple.png new file mode 100644 index 0000000..9da3ffa Binary files /dev/null and b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_NTriple.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_RDFXML.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_RDFXML.png b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_RDFXML.png new file mode 100644 index 0000000..13f2b43 Binary files /dev/null and b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_RDFXML.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_RDFXMLABBREV.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_RDFXMLABBREV.png b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_RDFXMLABBREV.png new file mode 100644 index 0000000..e1ffa09 Binary files /dev/null and b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_RDFXMLABBREV.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_Turtle.png ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_Turtle.png b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_Turtle.png new file mode 100644 index 0000000..0fd2b36 Binary files /dev/null and b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/doc-files/Example_Turtle.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/package.html ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/package.html b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/package.html new file mode 100644 index 0000000..34ef9e7 --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/package.html @@ -0,0 +1,1055 @@ +<!DOCTYPE HTML> +<!-- +/*************************************************************************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + ***************************************************************************************************************************/ + --> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <style type="text/css"> + /* For viewing in Page Designer */ + @IMPORT url("../../../../../../javadoc.css"); + + /* For viewing in REST interface */ + @IMPORT url("../htdocs/javadoc.css"); + body { + margin: 20px; + } + </style> + <script> + /* Replace all @code and @link tags. */ + window.onload = function() { + document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>'); + document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>'); + } + </script> +</head> +<body> +<p>Jena-based RDF serialization and parsing support</p> +<script> + function toggle(x) { + var div = x.nextSibling; + while (div != null && div.nodeType != 1) + div = div.nextSibling; + if (div != null) { + var d = div.style.display; + if (d == 'block' || d == '') { + div.style.display = 'none'; + x.className += " closed"; + } else { + div.style.display = 'block'; + x.className = x.className.replace(/(?:^|\s)closed(?!\S)/g , '' ); + } + } + } +</script> + +<a id='TOC'></a><h5 class='toc'>Table of Contents</h5> +<ol class='toc'> + <li><p><a class='doclink' href='#RdfOverview'>RDF support overview</a></p> + <ol> + <li><p><a class='doclink' href='#RdfOverviewExample'>Example</a></p> + </ol> + <li><p><a class='doclink' href='#RdfSerializer'>RdfSerializer class</a></p> + <ol> + <li><p><a class='doclink' href='#Namespaces'>Namespaces</a></p> + <li><p><a class='doclink' href='#UriProperties'>URI properties</a></p> + <li><p><a class='doclink' href='#BeanAnnotations'>@Bean and @BeanProperty annotations</a></p> + <li><p><a class='doclink' href='#Collections'>Collections</a></p> + <li><p><a class='doclink' href='#RootProperty'>Root property</a></p> + <li><p><a class='doclink' href='#TypedLiterals'>Typed literals</a></p> + <li><p><a class='doclink' href='#Recursion'>Non-tree models and recursion detection</a></p> + <li><p><a class='doclink' href='#SerializerConfigurableProperties'>Configurable properties</a></p> + <li><p><a class='doclink' href='#SerializerOtherNotes'>Other notes</a></p> + </ol> + <li><p><a class='doclink' href='#RdfParser'>RdfParser class</a></p> + <ol> + <li><p><a class='doclink' href='#GenericParsing'>Parsing into generic POJO models</a></p> + <li><p><a class='doclink' href='#ParserConfigurableProperties'>Configurable properties</a></p> + <li><p><a class='doclink' href='#ParserOtherNotes'>Other notes</a></p> + </ol> +</ol> + + +<!-- ======================================================================================================== --> +<a id="RdfOverview"></a> +<h2 class='topic' onclick='toggle(this)'>1 - RDF support overview</h2> +<div class='topic'> + <p> + Juneau supports serializing and parsing arbitrary POJOs to and from the following RDF formats: + </p> + <ul> + <li>RDF/XML + <li>Abbreviated RDF/XML + <li>N-Triple + <li>Turtle + <li>N3 + </ul> + <p> + Juneau can serialize and parse instances of any of the following POJO types: + </p> + <ul class='spaced-list'> + <li> + Java primitive objects (e.g. <code>String</code>, <code>Integer</code>, <code>Boolean</code>, + <code>Float</code>). + <li> + Java collections framework objects (e.g. <code>HashSet</code>, <code>TreeMap</code>) containing anything on + this list. + <li> + Multi-dimensional arrays of any type on this list. + <li> + Java Beans with properties of any type on this list. + <li> + Classes with standard transformations to and from <code>Strings</code> (e.g. classes containing + <code>toString()</code>, <code>fromString()</code>, <code>valueOf()</code>, <code>constructor(String)</code>). + </ul> + <p> + In addition to the types shown above, Juneau includes the ability to define 'swaps' to transform non-standard + object and property types to serializable forms (e.g. to transform <code>Calendars</code> to and from + <code>ISO8601</code> strings, or <code>byte[]</code> arrays to and from base-64 encoded strings). + <br>These can be associated with serializers/parsers, or can be associated with classes or bean properties through + type and method annotations. + </p> + <p> + Refer to <a href='../../../../overview-summary.html#Core.PojoCategories' class='doclink'>POJO Categories</a> + for a complete definition of supported POJOs. + </p> + + <h6 class='topic'>Prerequisites</h6> + <p> + Juneau uses the Jena library for these formats. + <br>The predefined serializers and parsers convert POJOs to and from RDF models and then uses Jena to convert + them to and from the various RDF languages. + </p> + <p> + Jena libraries must be provided on the classpath separately if you plan on making use of the RDF support. + </p> + <p> + The minimum list of required jars are: + </p> + <ul> + <li><code>jena-core-2.7.1.jar</code> + <li><code>jena-iri-0.9.2.jar</code> + <li><code>log4j-1.2.16.jar</code> + <li><code>slf4j-api-1.6.4.jar</code> + <li><code>slf4j-log4j12-1.6.4.jar</code> + </ul> + + <!-- ======================================================================================================== --> + <a id="RdfOverviewExample"></a> + <h3 class='topic' onclick='toggle(this)'>1.1 - RDF support overview - example</h3> + <div class='topic'> + <p> + The example shown here is from the Address Book resource located in the + <code>org.apache.juneau.sample.war</code> application. + </p> + <p> + The POJO model consists of a <code>List</code> of <code>Person</code> beans, with each <code>Person</code> + containing zero or more <code>Address</code> beans. + </p> + <p> + When you point a browser at <code>/sample/addressBook</code>, the POJO is rendered as HTML: + </p> + <img class='bordered' src="doc-files/Example_HTML.png"> + <p> + By appending <code>?Accept=<i>mediaType</i>&plainText=true</code> to the URL, you can view the data + in the various RDF supported formats. + </p> + + <h6 class='figure'>RDF/XML</h6> + <img class='bordered' src="doc-files/Example_RDFXML.png"> + + <h6 class='figure'>Abbreviated RDF/XML</h6> + <img class='bordered' src="doc-files/Example_RDFXMLABBREV.png"> + + <h6 class='figure'>N-Triple</h6> + <img class='bordered' src="doc-files/Example_NTriple.png"> + + <h6 class='figure'>Turtle</h6> + <img class='bordered' src="doc-files/Example_Turtle.png"> + + <h6 class='figure'>N3</h6> + <img class='bordered' src="doc-files/Example_N3.png"> + </div> +</div> + +<!-- ======================================================================================================== --> +<a id="RdfSerializer"></a> +<h2 class='topic' onclick='toggle(this)'>2 - RdfSerializer class</h2> +<div class='topic'> + <p> + The {@link org.apache.juneau.jena.RdfSerializer} class is the top-level class for all Jena-based serializers. + <br>Language-specific serializers are defined as inner subclasses of the <code>RdfSerializer</code> class: + </p> + <ul> + <li>{@link org.apache.juneau.jena.RdfSerializer.Xml} + <li>{@link org.apache.juneau.jena.RdfSerializer.XmlAbbrev} + <li>{@link org.apache.juneau.jena.RdfSerializer.NTriple} + <li>{@link org.apache.juneau.jena.RdfSerializer.Turtle} + <li>{@link org.apache.juneau.jena.RdfSerializer.N3} + </ul> + <p> + Static reusable instances of serializers are also provided with default settings: + </p> + <ul> + <li>{@link org.apache.juneau.jena.RdfSerializer#DEFAULT_XML} + <li>{@link org.apache.juneau.jena.RdfSerializer#DEFAULT_XMLABBREV} + <li>{@link org.apache.juneau.jena.RdfSerializer#DEFAULT_TURTLE} + <li>{@link org.apache.juneau.jena.RdfSerializer#DEFAULT_NTRIPLE} + <li>{@link org.apache.juneau.jena.RdfSerializer#DEFAULT_N3} + </ul> + <p> + Abbreviated RDF/XML is currently the most widely accepted and readable RDF syntax, so the examples shown here + will use that format. + </p> + <p> + For brevity, the examples will use public fields instead of getters/setters to reduce the size of the examples. + <br>In the real world, you'll typically want to use standard bean getters and setters. + </p> + <p> + To start off simple, we'll begin with the following simplified bean and build it up. + </p> + <p class='bcode'> + <jk>public class</jk> Person { + <jc>// Bean properties</jc> + <jk>public int</jk> <jf>id</jf>; + <jk>public</jk> String <jf>name</jf>; + + <jc>// Bean constructor (needed by parser)</jc> + <jk>public</jk> Person() {} + + <jc>// Normal constructor</jc> + <jk>public</jk> Person(<jk>int</jk> id, String name) { + <jk>this</jk>.<jf>id</jf> = id; + <jk>this</jk>.<jf>name</jf> = name; + } + } + </p> + <p> + The following code shows how to convert this to abbreviated RDF/XML: + </p> + <p class='bcode'> + <jc>// Create a new serializer with readable output.</jc> + RdfSerializer s = <jk>new</jk> RdfSerializerBuilder().xmlabbrev() + .property(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3).build(); + + <jc>// Create our bean.</jc> + Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>); + + <jc>// Serialize the bean to RDF/XML.</jc> + String rdfXml = s.serialize(p); + </p> + <p> + It should be noted that serializers can also be created by cloning existing serializers: + </p> + <p class='bcode'> + <jc>// Create a new serializer with readable output by cloning an existing serializer.</jc> + RdfSerializer s = RdfSerializer.<jsf>DEFAULT_XMLABBREV</jsf>.builder() + .property(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3).build(); + </p> + <p> + This code produces the following output: + </p> + <p class='bcode'> + <xt><rdf:RDF</xt> + <xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs> + <xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs> + <xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs><xt>></xt> + <xt><rdf:Description></xt> + <xt><jp:id></xt>1<xt></jp:id></xt> + <xt><jp:name></xt>John Smith<xt></jp:name></xt> + <xt></rdf:Description></xt> + <xt></rdf:RDF></xt> + </p> + <p> + Notice that we've taken an arbitrary POJO and converted it to RDF. + <br>The Juneau serializers and parsers are designed to work with arbitrary POJOs without requiring any annotations. + <br>That being said, several annotations are provided to customize how POJOs are handled to produce usable RDF. + </p> + + <!-- ======================================================================================================== --> + <a id="Namespaces"></a> + <h3 class='topic' onclick='toggle(this)'>2.1 - Namespaces</h3> + <div class='topic'> + <p> + You'll notice in the previous example that Juneau namespaces are used to represent bean property names. + <br>These are used by default when namespaces are not explicitly specified. + </p> + <p> + The <code>juneau</code> namespace is used for generic names for objects that don't have namespaces + associated with them. + </p> + <p> + The <code>juneaubp</code> namespace is used on bean properties that don't have namespaces associated with + them. + </p> + <p> + The easiest way to specify namespaces is through annotations. + <br>In this example, we're going to associate the prefix <code>'per'</code> to our bean class and all properties + of this class. + <br>We do this by adding the following annotation to our class: + </p> + <p class='bcode'> + <ja>@Rdf</ja>(prefix=<js>"per"</js>) + <jk>public class</jk> Person { + </p> + <p> + In general, the best approach is to define the namespace URIs at the package level using a + <code>package-info.java</code> class, like so: + </p> + <p class='bcode'> + <jc>// RDF namespaces used in this package</jc> + <ja>@RdfSchema</ja>( + prefix=<js>"ab"</js>, + rdfNs={ + <ja>@RdfNs</ja>(prefix=<js>"ab"</js>, namespaceURI=<js>"http://www.apache.org/addressBook/"</js>), + <ja>@RdfNs</ja>(prefix=<js>"per"</js>, namespaceURI=<js>"http://www.apache.org/person/"</js>), + <ja>@RdfNs</ja>(prefix=<js>"addr"</js>, namespaceURI=<js>"http://www.apache.org/address/"</js>), + <ja>@RdfNs</ja>(prefix=<js>"mail"</js>, namespaceURI=<js>"http://www.apache.org/mail/"</js>) + } + ) + <jk>package</jk> org.apache.juneau.sample.addressbook; + <jk>import</jk> org.apache.juneau.xml.annotation.*; + </p> + <p> + This assigns a default prefix of <js>"ab"</js> for all classes and properties within the project, and + specifies various other prefixes used within this project. + </p> + <p> + Now when we rerun the sample code, we'll get the following: + </p> + <p class='bcode'> + <xt><rdf:RDF</xt> + <xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs> + <xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs> + <xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs> + <xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs><xt>></xt> + <xt><rdf:Description></xt> + <xt><per:id></xt>1<xt></per:id></xt> + <xt><per:name></xt>John Smith<xt></per:name></xt> + <xt></rdf:Description></xt> + <xt></rdf:RDF></xt> + </p> + <p> + Namespace auto-detection ({@link org.apache.juneau.xml.XmlSerializerContext#XML_autoDetectNamespaces}) is + enabled on serializers by default. + <br>This causes the serializer to make a first-pass over the data structure to look for namespaces. + <br>In high-performance environments, you may want to consider disabling auto-detection and providing an + explicit list of namespaces to the serializer to avoid this scanning step. + </p> + <p class='bcode'> + <jc>// Create a new serializer, but manually specify the namespaces.</jc> + RdfSerializer s = <jk>new</jk> RdfSerializerBuilder() + .xmlabbrev() + .property(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3) + .autoDetectNamespaces(<jk>false</jk>) + .namespaces(<js>"{per:'http://www.apache.org/person/'}"</js>) + .build(); + </p> + <p> + This code change will produce the same output as before, but will perform slightly better since it doesn't + have to crawl the POJO tree before serializing the result. + </p> + </div> + + <!-- ======================================================================================================== --> + <a id="UriProperties"></a> + <h3 class='topic' onclick='toggle(this)'>2.2 - URI properties</h3> + <div class='topic'> + <p> + Bean properties of type <code>java.net.URI</code> or <code>java.net.URL</code> have special meaning to the + RDF serializer. + <br>They are interpreted as resource identifiers. + </p> + <p> + In the following code, we're adding 2 new properties. + <br>The first property is annotated with <ja>@BeanProperty</ja> to identify that this property is the resource + identifier for this bean. + <br>The second un-annotated property is interpreted as a reference to another resource. + </p> + <p class='bcode'> + <jk>public class</jk> Person { + + <jc>// Bean properties</jc> + <ja>@Rdf</ja>(beanUri=<jk>true</jk>) + <jk>public</jk> URI <jf>uri</jf>; + + <jk>public</jk> URI <jf>addressBookUri</jf>; + + ... + + <jc>// Normal constructor</jc> + <jk>public</jk> Person(<jk>int</jk> id, String name, String uri, String addressBookUri) <jk>throws</jk> URISyntaxException { + <jk>this</jk>.<jf>id</jf> = id; + <jk>this</jk>.<jf>name</jf> = name; + <jk>this</jk>.<jf>uri</jf> = <jk>new</jk> URI(uri); + <jk>this</jk>.<jf>addressBookUri</jf> = <jk>new</jk> URI(addressBookUri); + } + } + </p> + <p> + We alter our code to pass in values for these new properties. + </p> + <p class='bcode'> + <jc>// Create our bean.</jc> + Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>, <js>"http://sample/addressBook/person/1"</js>, + <js>"http://sample/addressBook"</js>); + </p> + <p> + Now when we run the sample code, we get the following: + </p> + <p class='bcode'> + <xt><rdf:RDF</xt> + <xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs> + <xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs> + <xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs> + <xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs><xt>></xt> + <xt><rdf:Description <b><xa>rdf:about</xa>=<xs>"http://sample/addressBook/person/1"</xs></b>></xt> + <xt><per:addressBookUri</xt> <xa>rdf:resource</xa>=<xs>"http://sample/addressBook"</xs><xt>/></xt> + <xt><per:id></xt>1<xt></per:id></xt> + <xt><per:name></xt>John Smith<xt></per:name></xt> + <xt></rdf:Description></xt> + <xt></rdf:RDF></xt> + </p> + <p> + The {@link org.apache.juneau.annotation.URI} annotation can also be used on classes and properties + to identify them as URLs when they're not instances of <code>java.net.URI</code> or <code>java.net.URL</code> + (not needed if <code><ja>@Rdf</ja>(beanUri=<jk>true</jk>)</code> is already specified). + </p> + <p> + The following properties would have produced the same output as before. + Note that the <ja>@URI</ja> annotation is only needed on the second property. + </p> + <p class='bcode'> + <jk>public class</jk> Person { + + <jc>// Bean properties</jc> + <ja>@Rdf</ja>(beanUri=<jk>true</jk>) <jk>public</jk> String <jf>uri</jf>; + + <ja>@URI</ja> <jk>public</jk> String <jf>addressBookUri</jf>; + </p> + <p> + Also take note of the {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_uriResolution}, + {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_uriRelativity}, and + and {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_uriContext} + settings that can be specified on the serializer to resolve relative and context-root-relative URIs to + fully-qualified URIs. + </p> + <p> + This can be useful if you want to keep the URI authority and context root information out of the bean logic + layer. + </p> + <p> + The following code produces the same output as before, but the URIs on the beans are relative. + </p> + <p class='bcode'> + <jc>// Create a new serializer with readable output.</jc> + RdfSerializer s = <jk>new</jk> RdfSerializerBuilder() + .xmlabbrev() + .property(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3); + .relativeUriBase(<js>"http://myhost/sample"</js>); + .absolutePathUriBase(<js>"http://myhost"</js>) + .build(); + + <jc>// Create our bean.</jc> + Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>, <js>"person/1"</js>, <js>"/"</js>); + + <jc>// Serialize the bean to RDF/XML.</jc> + String rdfXml = s.serialize(p); + </p> + </div> + + <!-- ======================================================================================================== --> + <a id="BeanAnnotations"></a> + <h3 class='topic' onclick='toggle(this)'>2.3 - @Bean and @BeanProperty annotations</h3> + <div class='topic'> + <p> + The {@link org.apache.juneau.annotation.Bean} and {@link org.apache.juneau.annotation.BeanProperty} + annotations are used to customize the behavior of beans across the entire framework. + <br>In addition to using them to identify the resource URI for the bean shown above, they have various other + uses: + </p> + <ul class='spaced-list'> + <li> + Hiding bean properties. + <li> + Specifying the ordering of bean properties. + <li> + Overriding the names of bean properties. + <li> + Associating transforms at both the class and property level (to convert non-serializable POJOs to + serializable forms). + </ul> + <p> + For example, we now add a <code>birthDate</code> property, and associate a swap with it to transform + it to an ISO8601 date-time string in GMT time. + <br>By default, <code>Calendars</code> are treated as beans by the framework, which is usually not how you want + them serialized. + <br>Using swaps, we can convert them to standardized string forms. + </p> + <p class='bcode'> + <jk>public class</jk> Person { + + <jc>// Bean properties</jc> + <ja>@BeanProperty</ja>(swap=CalendarSwap.ISO8601DTZ.<jk>class</jk>) <jk>public</jk> Calendar birthDate; + ... + + <jc>// Normal constructor</jc> + <jk>public</jk> Person(<jk>int</jk> id, String name, String uri, String addressBookUri, String birthDate) + <jk>throws</jk> Exception { + ... + <jk>this</jk>.<jf>birthDate</jf> = <jk>new</jk> GregorianCalendar(); + <jk>this</jk>.<jf>birthDate</jf>.setTime( + DateFormat.<jsm>getDateInstance</jsm>(DateFormat.<jsf>MEDIUM</jsf>).parse(birthDate)); + } + } + </p> + <p> + And we alter our code to pass in the birthdate. + </p> + <p class='bcode'> + <jc>// Create our bean.</jc> + Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>, <js>"http://sample/addressBook/person/1"</js>, + <js>"http://sample/addressBook"</js>, <js>"Aug 12, 1946"</js>); + </p> + <p> + Now when we rerun the sample code, we'll get the following: + </p> + <p class='bcode'> + <xt><rdf:RDF</xt> + <xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs> + <xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs> + <xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs> + <xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs><xt>></xt> + <xt><rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/person/1"</xs>></xt> + <xt><per:addressBookUri</xt> <xa>rdf:resource</xa>=<xs>"http://sample/addressBook"</xs><xt>/></xt> + <xt><per:id></xt>1<xt></per:id></xt> + <xt><per:name></xt>John Smith<xt></per:name></xt> + <xt><per:birthDate></xt>1946-08-12T00:00:00Z<xt></per:birthDate></xt> + <xt></rdf:Description></xt> + <xt></rdf:RDF></xt> + </p> + </div> + + + <!-- ======================================================================================================== --> + <a id="Collections"></a> + <h3 class='topic' onclick='toggle(this)'>2.4 - Collections</h3> + <div class='topic'> + <p> + Collections and arrays are converted to RDF sequences. + <br>In our example, let's add a list-of-beans property to our sample class: + </p> + <p class='bcode'> + <jk>public class</jk> Person { + + <jc>// Bean properties</jc> + <jk>public</jk> LinkedList<Address> <jf>addresses</jf> = <jk>new</jk> LinkedList<Address>(); + ... + } + </p> + <p> + The <code>Address</code> class has the following properties defined: + </p> + <p class='bcode'> + <ja>@Rdf</ja>(prefix=<js>"addr"</js>) + <jk>public class</jk> Address { + + <jc>// Bean properties</jc> + <ja>@Rdf</ja>(beanUri=<jk>true</jk>) <jk>public</jk> URI <jf>uri</jf>; + <jk>public</jk> URI <jf>personUri</jf>; + + <jk>public int</jk> <jf>id</jf>; + + <ja>@Rdf</ja>(prefix=<js>"mail"</js>) + <jk>public</jk> String <jf>street</jf>, <jf>city</jf>, <jf>state</jf>; + + <ja>@Rdf</ja>(prefix=<js>"mail"</js>) + <jk>public int</jk> <jf>zip</jf>; + + <jk>public boolean</jk> <jf>isCurrent</jf>; + } + </p> + <p> + Next, add some quick-and-dirty code to add an address to our person bean: + </p> + <p class='bcode'> + <jc>// Create a new serializer (revert back to namespace autodetection).</jc> + RdfSerializer s = <jk>new</jk> RdfSerializerBuilder().xmlabbrev().property(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3).build(); + + <jc>// Create our bean.</jc> + Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>, <js>"http://sample/addressBook/person/1"</js>, + <js>"http://sample/addressBook"</js>, <js>"Aug 12, 1946"</js>); + Address a = <jk>new</jk> Address(); + a.<jf>uri</jf> = <jk>new</jk> URI(<js>"http://sample/addressBook/address/1"</js>); + a.<jf>personUri</jf> = <jk>new</jk> URI(<js>"http://sample/addressBook/person/1"</js>); + a.<jf>id</jf> = 1; + a.<jf>street</jf> = <js>"100 Main Street"</js>; + a.<jf>city</jf> = <js>"Anywhereville"</js>; + a.<jf>state</jf> = <js>"NY"</js>; + a.<jf>zip</jf> = 12345; + a.<jf>isCurrent</jf> = <jk>true</jk>; + p.<jf>addresses</jf>.add(a); + </p> + <p> + Now when we run the sample code, we get the following: + </p> + <p class='bcode'> + <xt><rdf:RDF</xt> + <xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs> + <xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs> + <xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs> + <xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs> + <b><xa>xmlns:mail</xa>=<xs>"http://www.apache.org/mail/"</xs></b> + <b><xa>xmlns:addr</xa>=<xs>"http://www.apache.org/address/"</xs></b><xt>></xt> + <xt><rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/person/1"</xs>></xt> + <xt><per:addressBookUri</xt> <xa>rdf:resource</xa>=<xs>"http://sample/addressBook"</xs><xt>/></xt> + <xt><per:id></xt>1<xt></per:id></xt> + <xt><per:name></xt>John Smith<xt></per:name></xt> + <b><xt><per:addresses></xt> + <xt><rdf:Seq></xt> + <xt><rdf:li></xt> + <xt><rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/address/1"</xs>></xt> + <xt><addr:personUri <xa>rdf:resource</xa>=<xs>"http://sample/addressBook/person/1"</xs>/></xt> + <xt><addr:id></xt>1<xt></addr:id></xt> + <xt><mail:street></xt>100 Main Street<xt></mail:street></xt> + <xt><mail:city></xt>Anywhereville<xt></mail:city></xt> + <xt><mail:state></xt>NY<xt></mail:state></xt> + <xt><mail:zip></xt>12345<xt></mail:zip></xt> + <xt><addr:isCurrent></xt>true<xt></addr:isCurrent></xt> + <xt></rdf:Description></xt> + <xt></rdf:li></xt> + <xt></rdf:Seq></xt> + <xt></per:addresses></xt></b> + <xt></rdf:Description></xt> + <xt></rdf:RDF></xt> + </p> + </div> + + + <!-- ======================================================================================================== --> + <a id="RootProperty"></a> + <h3 class='topic' onclick='toggle(this)'>2.5 - Root property</h3> + <div class='topic'> + <p> + For all RDF languages, the POJO objects get broken down into simple triplets. + <br>Unfortunately, for tree-structured data like the POJOs shown above, this causes the root node of the tree + to become lost. + <br>There is no easy way to identify that <code>person/1</code> is the root node in our tree once in triplet + form, and in some cases it's impossible. + </p> + <p> + By default, the {@link org.apache.juneau.jena.RdfParser} class handles this by scanning all the nodes and + identifying the nodes without incoming references. + <br>However, this is inefficient, especially for large models. + <br>And in cases where the root node is referenced by another node in the model by URL, it's not possible to + locate the root at all. + </p> + <p> + To resolve this issue, the property {@link org.apache.juneau.jena.RdfSerializerContext#RDF_addRootProperty} + was introduced. + <br>When enabled, this adds a special <code>root</code> attribute to the root node to make it easy to locate + by the parser. + </p> + <p> + To enable, set the <jsf>RDF_addRootProperty</jsf> property to <jk>true</jk> on the serializer: + </p> + <p class='bcode'> + <jc>// Create a new serializer.</jc> + RdfSerializer s = <jk>new</jk> RdfSerializerBuilder() + .xmlabbrev() + .property(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3), + .addRootProperty(<jk>true</jk>) + .build(); + </p> + <p> + Now when we rerun the sample code, we'll see the added <code>root</code> attribute on the root resource. + </p> + <p class='bcode'> + <xt><rdf:RDF</xt> + <xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs> + <xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs> + <xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs> + <xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs> + <xa>xmlns:mail</xa>=<xs>"http://www.apache.org/mail/"</xs> + <xa>xmlns:addr</xa>=<xs>"http://www.apache.org/address/"</xs><xt>></xt> + <xt><rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/person/1"</xs>></xt> + <b><xt><j:root></xt>true<xt></j:root></xt></b> + <xt><per:addressBookUri</xt> <xa>rdf:resource</xa>=<xs>"http://sample/addressBook"</xs><xt>/></xt> + <xt><per:id></xt>1<xt></per:id></xt> + <xt><per:name></xt>John Smith<xt></per:name></xt> + <xt><per:addresses></xt> + <xt><rdf:Seq></xt> + <xt><rdf:li></xt> + <xt><rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/address/1"</xs>></xt> + <xt><addr:personUri <xa>rdf:resource</xa>=<xs>"http://sample/addressBook/person/1"</xs>/></xt> + <xt><addr:id></xt>1<xt></addr:id></xt> + <xt><mail:street></xt>100 Main Street<xt></mail:street></xt> + <xt><mail:city></xt>Anywhereville<xt></mail:city></xt> + <xt><mail:state></xt>NY<xt></mail:state></xt> + <xt><mail:zip></xt>12345<xt></mail:zip></xt> + <xt><addr:isCurrent></xt>true<xt></addr:isCurrent></xt> + <xt></rdf:Description></xt> + <xt></rdf:li></xt> + <xt></rdf:Seq></xt> + <xt></per:addresses></xt> + <xt></rdf:Description></xt> + <xt></rdf:RDF></xt> + </p> + </div> + + + <!-- ======================================================================================================== --> + <a id="TypedLiterals"></a> + <h3 class='topic' onclick='toggle(this)'>2.6 - Typed literals</h3> + <div class='topic'> + <p> + XML-Schema data-types can be added to non-<code>String</code> literals through the + {@link org.apache.juneau.jena.RdfSerializerContext#RDF_addLiteralTypes} setting. + </p> + <p> + To enable, set the <jsf>RDF_addLiteralTypes</jsf> property to <jk>true</jk> on the serializer: + </p> + <p class='bcode'> + <jc>// Create a new serializer (revert back to namespace autodetection).</jc> + RdfSerializer s = <jk>new</jk> RdfSerializerBuilder() + .xmlabbrev() + .property(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3), + .addLiteralTypes(<jk>true</jk>) + .build(); + </p> + <p> + Now when we rerun the sample code, we'll see the added <code>root</code> attribute on the root resource. + </p> + <p class='bcode'> + <xt><rdf:RDF</xt> + <xa>xmlns:rdf</xa>=<xs>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</xs> + <xa>xmlns:j</xa>=<xs>"http://www.apache.org/juneau/"</xs> + <xa>xmlns:jp</xa>=<xs>"http://www.apache.org/juneaubp/"</xs> + <xa>xmlns:per</xa>=<xs>"http://www.apache.org/person/"</xs> + <xa>xmlns:mail</xa>=<xs>"http://www.apache.org/mail/"</xs> + <xa>xmlns:addr</xa>=<xs>"http://www.apache.org/address/"</xs><xt>></xt> + <xt><rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/person/1"</xs>></xt> + <xt><per:addressBookUri</xt> <xa>rdf:resource</xa>=<xs>"http://sample/addressBook"</xs><xt>/></xt> + <xt><per:id</xt> <b><xa>rdf:datatype</xa>=<xs>"http://www.w3.org/2001/XMLSchema#int"</xs></b><xt>></xt>1<xt></per:id></xt> + <xt><per:name></xt>John Smith<xt></per:name></xt> + <xt><per:addresses></xt> + <xt><rdf:Seq></xt> + <xt><rdf:li></xt> + <xt><rdf:Description <xa>rdf:about</xa>=<xs>"http://sample/addressBook/address/1"</xs>></xt> + <xt><addr:personUri <xa>rdf:resource</xa>=<xs>"http://sample/addressBook/person/1"</xs>/></xt> + <xt><addr:id</xt> <b><xa>rdf:datatype</xa>=<xs>"http://www.w3.org/2001/XMLSchema#int"</xs></b>></xt>1<xt></addr:id></xt> + <xt><mail:street></xt>100 Main Street<xt></mail:street></xt> + <xt><mail:city></xt>Anywhereville<xt></mail:city></xt> + <xt><mail:state></xt>NY<xt></mail:state></xt> + <xt><mail:zip</xt> <b><xa>rdf:datatype</xa>=<xs>"http://www.w3.org/2001/XMLSchema#int"</xs></b>></xt>12345<xt></mail:zip></xt> + <xt><addr:isCurrent</xt> <b><xa>rdf:datatype</xa>=<xs>"http://www.w3.org/2001/XMLSchema#boolean"</xs></b>></xt>true<xt></addr:isCurrent></xt> + <xt></rdf:Description></xt> + <xt></rdf:li></xt> + <xt></rdf:Seq></xt> + <xt></per:addresses></xt> + <xt></rdf:Description></xt> + <xt></rdf:RDF></xt> + </p> + </div> + + + <!-- ======================================================================================================== --> + <a id="Recursion"></a> + <h3 class='topic' onclick='toggle(this)'>2.7 - Non-tree models and recursion detection</h3> + <div class='topic'> + <p> + The RDF serializer is designed to be used against tree structures. + <br>It expects that there not be loops in the POJO model (e.g. children with references to parents, etc...). + <br>If you try to serialize models with loops, you will usually cause a <code>StackOverflowError</code> to + be thrown (if {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_maxDepth} is not reached + first). + </p> + <p> + If you still want to use the XML serializer on such models, Juneau provides the + {@link org.apache.juneau.serializer.SerializerContext#SERIALIZER_detectRecursions} setting. + <br>It tells the serializer to look for instances of an object in the current branch of the tree and skip + serialization when a duplicate is encountered. + </p> + <p> + Recursion detection introduces a performance penalty of around 20%. + <br>For this reason the setting is disabled by default. + </p> + </div> + + + <!-- ======================================================================================================== --> + <a id="SerializerConfigurableProperties"></a> + <h3 class='topic' onclick='toggle(this)'>2.8 - Configurable properties</h3> + <div class='topic'> + <p> + See the following classes for all configurable properties that can be used on this serializer: + </p> + <ul class='spaced-list'> + <li> + {@link org.apache.juneau.BeanContext} - Bean context properties. + <li> + {@link org.apache.juneau.jena.RdfSerializerContext} - Serializer context properties. + </ul> + </div> + + + <!-- ======================================================================================================== --> + <a id="SerializerOtherNotes"></a> + <h3 class='topic' onclick='toggle(this)'>2.9 - Other notes</h3> + <div class='topic'> + <ul class='spaced-list'> + <li> + Like all other Juneau serializers, the RDF serializer is thread safe and maintains an internal cache of + bean classes encountered. + For performance reasons, it's recommended that serializers be reused whenever possible instead of always + creating new instances. + </ul> + </div> +</div> + + +<!-- ======================================================================================================== --> +<a id="RdfParser"></a> +<h2 class='topic' onclick='toggle(this)'>3 - RdfParser class</h2> +<div class='topic'> + <p> + The {@link org.apache.juneau.jena.RdfParser} class is the top-level class for all Jena-based parsers. + <br>Language-specific parsers are defined as inner subclasses of the <code>RdfParser</code> class: + </p> + <ul> + <li>{@link org.apache.juneau.jena.RdfParser.Xml} + <li>{@link org.apache.juneau.jena.RdfParser.NTriple} + <li>{@link org.apache.juneau.jena.RdfParser.Turtle} + <li>{@link org.apache.juneau.jena.RdfParser.N3} + </ul> + <p> + The <code>RdfParser.Xml</code> parser handles both regular and abbreviated RDF/XML. + </p> + <p> + Static reusable instances of parsers are also provided with default settings: + </p> + <ul> + <li>{@link org.apache.juneau.jena.RdfParser#DEFAULT_XML} + <li>{@link org.apache.juneau.jena.RdfParser#DEFAULT_TURTLE} + <li>{@link org.apache.juneau.jena.RdfParser#DEFAULT_NTRIPLE} + <li>{@link org.apache.juneau.jena.RdfParser#DEFAULT_N3} + </ul> + <p> + For an example, we will build upon the previous example and parse the generated RDF/XML back into the original + bean. + </p> + <p class='bcode'> + <jc>// Create a new serializer with readable output.</jc> + RdfSerializer s = <jk>new</jk> RdfSerializerBuilder() + .xmlabbrev() + .property(RdfProperties.<jsf>RDF_rdfxml_tab</jsf>, 3) + .addRootProperty(<jk>true</jk>) + .build(); + + <jc>// Create our bean.</jc> + Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>, <js>"http://sample/addressBook/person/1"</js>, + <js>"http://sample/addressBook"</js>, <js>"Aug 12, 1946"</js>); + Address a = <jk>new</jk> Address(); + a.<jf>uri</jf> = <jk>new</jk> URI(<js>"http://sample/addressBook/address/1"</js>); + a.<jf>personUri</jf> = <jk>new</jk> URI(<js>"http://sample/addressBook/person/1"</js>); + a.<jf>id</jf> = 1; + a.<jf>street</jf> = <js>"100 Main Street"</js>; + a.<jf>city</jf> = <js>"Anywhereville"</js>; + a.<jf>state</jf> = <js>"NY"</js>; + a.<jf>zip</jf> = 12345; + a.<jf>isCurrent</jf> = <jk>true</jk>; + p.<jf>addresses</jf>.add(a); + + <jc>// Serialize the bean to RDF/XML.</jc> + String rdfXml = s.serialize(p); + + <jc>// Parse it back into a bean using the reusable XML parser.</jc> + p = RdfParser.<jsf>DEFAULT_XML</jsf>.parse(rdfXml, Person.<jk>class</jk>); + + <jc>// Render it as JSON.</jc> + String json = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>.serialize(p); + System.<jsm>err</jsm>.println(json); + </p> + <p> + We print it out to JSON to show that all the data has been preserved: + </p> + <p class='bcode'> + { + uri: <js>'http://sample/addressBook/person/1'</js>, + addressBookUri: <js>'http://sample/addressBook'</js>, + id: 1, + name: <js>'John Smith'</js>, + birthDate: <js>'1946-08-12T00:00:00Z'</js>, + addresses: [ + { + uri: <js>'http://sample/addressBook/address/1'</js>, + personUri: <js>'http://sample/addressBook/person/1'</js>, + id: 1, + street: <js>'100 Main Street'</js>, + city: <js>'Anywhereville'</js>, + state: <js>'NY'</js>, + zip: 12345, + isCurrent: <jk>true</jk> + } + ] + } + </p> + + + <!-- ======================================================================================================== --> + <a id="GenericParsing"></a> + <h3 class='topic' onclick='toggle(this)'>3.1 - Parsing into generic POJO models</h3> + <div class='topic'> + <p> + The RDF parser is not limited to parsing back into the original bean classes. + <br>If the bean classes are not available on the parsing side, the parser can also be used to parse into a + generic model consisting of <code>Maps</code>, <code>Collections</code>, and primitive objects. + </p> + <p> + You can parse into any <code>Map</code> type (e.g. <code>HashMap</code>, <code>TreeMap</code>), but + using {@link org.apache.juneau.ObjectMap} is recommended since it has many convenience methods + for converting values to various types. + <br>The same is true when parsing collections. You can use any Collection (e.g. <code>HashSet</code>, + <code>LinkedList</code>) or array (e.g. <code>Object[]</code>, <code>String[]</code>, + <code>String[][]</code>), but using {@link org.apache.juneau.ObjectList} is recommended. + </p> + <p> + When the map or list type is not specified, or is the abstract <code>Map</code>, <code>Collection</code>, + or <code>List</code> types, the parser will use <code>ObjectMap</code> and <code>ObjectList</code> by + default. + </p> + <p> + In the following example, we parse into an <code>ObjectMap</code> and use the convenience methods for + performing data conversion on values in the map. + </p> + <p class='bcode'> + <jc>// Parse RDF into a generic POJO model.</jc> + ObjectMap m = RdfParser.<jsf>DEFAULT_XML</jsf>.parse(rdfXml, ObjectMap.<jk>class</jk>); + + <jc>// Get some simple values.</jc> + String name = m.getString(<js>"name"</js>); + <jk>int</jk> id = m.getInt(<js>"id"</js>); + + <jc>// Get a value convertable from a String.</jc> + URI uri = m.get(URI.<jk>class</jk>, <js>"uri"</js>); + + <jc>// Get a value using a swap.</jc> + CalendarSwap swap = <jk>new</jk> CalendarSwap.ISO8601DTZ(); + Calendar birthDate = m.get(swap, <js>"birthDate"</js>); + + <jc>// Get the addresses.</jc> + ObjectList addresses = m.getObjectList(<js>"addresses"</js>); + + <jc>// Get the first address and convert it to a bean.</jc> + Address address = addresses.get(Address.<jk>class</jk>, 0); + </p> + + <p> + However, there are caveats when parsing into generic models due to the nature of RDF. + <br>Watch out for the following: + </p> + <ul class='spaced-list'> + <li> + The ordering of entries are going to be inconsistent. + <li> + Bean URIs are always going to be denoted with the key <js>"uri"</js>. + <br>Therefore, you cannot have a bean with a URI property and a separate property named <js>"uri"</js>. + <br>The latter will overwrite the former. + <br>This isn't a problem when parsing into beans instead of generic POJO models. + <li> + All values are strings. + <br>This normally isn't a problem when using <code>ObjectMap</code> and <code>ObjectList</code> since + various methods are provided for converting to the correct type anyway. + <li> + The results may not be what is expected if there are lots of URL reference loops in the RDF model. + <br>As nodes are processed from the root node down through the child nodes, the parser keeps + track of previously processed parent URIs and handles them accordingly. + <br>If it finds that the URI has previously been processed, it handles it as a normal URI string and doesn't + process further. + <br>However, depending on how complex the reference loops are, the parsed data may end up having the + same data in it, but structured differently from the original POJO. + </ul> + <p> + We can see some of these when we render the <code>ObjectMap</code> back to JSON. + </p> + <p class='bcode'> + System.<jsm>err</jsm>.println(JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>.serialize(m)); + </p> + <p> + This is what's produced: + </p> + <p class='bcode'> + { + uri: <js>'http://sample/addressBook/person/1'</js>, + addresses: [ + { + uri: <js>'http://sample/addressBook/address/1'</js>, + isCurrent: <js>'true'</js>, + zip: <js>'12345'</js>, + state: <js>'NY'</js>, + city: <js>'Anywhereville'</js>, + street: <js>'100 Main Street'</js>, + id: <js>'1'</js>, + personUri: <js>'http://sample/addressBook/person/1'</js> + } + ], + birthDate: <js>'1946-08-12T00:00:00Z'</js>, + addressBookUri: <js>'http://sample/addressBook'</js>, + name: <js>'John Smith'</js>, + id: <js>'1'</js>, + root: <js>'true'</js> + } + </p> + <p> + As a general rule, parsing into beans is often more efficient than parsing into generic models. + <br>And working with beans is often less error prone than working with generic models. + </p> + </div> + + <!-- ======================================================================================================== --> + <a id="ParserConfigurableProperties"></a> + <h3 class='topic' onclick='toggle(this)'>3.2 - Configurable properties</h3> + <!-- TODO --> + <div class='topic'> + <p> + See the following classes for all configurable properties that can be used on this parser: + </p> + <ul class='spaced-list'> + <li> + {@link org.apache.juneau.BeanContext} - Bean context properties. + <li> + {@link org.apache.juneau.jena.RdfParserContext} - Parser context properties. + </ul> + </div> + + <!-- ======================================================================================================== --> + <a id="ParserOtherNotes"></a> + <h3 class='topic' onclick='toggle(this)'>3.3 - Other notes</h3> + <div class='topic'> + <ul class='spaced-list'> + <li> + Like all other Juneau parsers, the RDF parser is thread safe and maintains an internal cache of bean + classes encountered. + For performance reasons, it's recommended that parser be reused whenever possible instead of always + creating new instances. + </ul> + </div> + +</div> + +<p align="center"><i><b>*** fÃn ***</b></i></p> + +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/resources/.gitignore ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/resources/.gitignore b/juneau-core/juneau-marshall-rdf/src/main/resources/.gitignore new file mode 100644 index 0000000..8a0051a --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/resources/.gitignore @@ -0,0 +1,12 @@ + *************************************************************************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations under the License. * + *************************************************************************************************************************** http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall/.classpath ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/.classpath b/juneau-core/juneau-marshall/.classpath new file mode 100644 index 0000000..704b95d --- /dev/null +++ b/juneau-core/juneau-marshall/.classpath @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src/main/javadoc"/> + <classpathentry kind="src" output="target/classes" path="src/main/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/test-classes" path="src/test/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall/.gitignore ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/.gitignore b/juneau-core/juneau-marshall/.gitignore new file mode 100644 index 0000000..9dd6a50 --- /dev/null +++ b/juneau-core/juneau-marshall/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.settings/ +/.DS_Store +/TODO.txt http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall/.project ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/.project b/juneau-core/juneau-marshall/.project new file mode 100644 index 0000000..169c8ef --- /dev/null +++ b/juneau-core/juneau-marshall/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>juneau-marshall</name> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</nature> + </natures> +</projectDescription> http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall/pom.xml ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/pom.xml b/juneau-core/juneau-marshall/pom.xml new file mode 100644 index 0000000..cac41c3 --- /dev/null +++ b/juneau-core/juneau-marshall/pom.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + *************************************************************************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations under the License. * + *************************************************************************************************************************** +--> +<project + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.juneau</groupId> + <artifactId>juneau-core</artifactId> + <version>6.3.2-incubating-SNAPSHOT</version> + </parent> + + <artifactId>juneau-marshall</artifactId> + <name>Apache Juneau Marshall</name> + <description>Base toolkit for serializers, parsers, and bean contexts.</description> + <packaging>bundle</packaging> + + <properties> + <!-- Skip javadoc generation since we generate them in the aggregate pom --> + <maven.javadoc.skip>true</maven.javadoc.skip> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>3.2.0</version> + <extensions>true</extensions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <includes> + <include>**/*Test.class</include> + </includes> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <executions> + <execution> + <id>attach-sources</id> + <phase>verify</phase> + <goals> + <goal>jar-no-fork</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.7.2.201409121644</version> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>default-report</id> + <phase>prepare-package</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project>
