Repository: incubator-juneau Updated Branches: refs/heads/master b89cb9823 -> ab8f0faaa
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/ab8f0faa/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/package.html ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/package.html b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/package.html new file mode 100644 index 0000000..3c3e845 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/package.html @@ -0,0 +1,1005 @@ +<!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>JSON 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='#Overview'>JSON support overview</a></p> + <ol> + <li><p><a class='doclink' href='#OverviewExample'>Example</a></p> + </ol> + <li><p><a class='doclink' href='#JsonSerializer'>JsonSerializer class</a></p> + <ol> + <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='#JsonSchemaSupport'>JSON-Schema support</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='#JsonParser'>JsonParser 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="Overview"></a> +<h2 class='topic' onclick='toggle(this)'>1 -JSON support overview</h2> +<div class='topic'> + <p> + Juneau supports converting arbitrary POJOs to and from JSON using ultra-efficient serializers and parsers. + <br>The JSON serializer converts POJOs directly to JSON without the need for intermediate DOM objects using a + highly-efficient state machine. + <br>Likewise, the JSON parser creates POJOs directly from JSON without the need for intermediate DOM objects. + </p> + <p> + Juneau can serialize and parse instances of any of the following POJO types: + </p> + <ul class='spaced-list'> + <li> + Java primitives and 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>). + <li> + Non-serializable classes and properties with associated <code>PojoSwaps</code> that convert them to + serializable forms. + </ul> + <p> + Refer to <a href='../../../../overview-summary.html#juneau-marshall.PojoCategories' class='doclink'>POJO Categories</a> + for a complete definition of supported POJOs. + </p> + + <h6 class='topic'>Prerequisites</h6> + <p> + The Juneau JSON serialization and parsing support does not require any external prerequisites. + It only requires Java 1.6 or above. + </p> + + <!-- ======================================================================================================== --> + <a id="OverviewExample"></a> + <h3 class='topic' onclick='toggle(this)'>1.1 - JSON 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. + <br>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 supported JSON formats: + </p> + + <h6 class='figure'>Normal JSON</h6> + <img class='bordered' src="doc-files/Example_JSON.png"> + + <h6 class='figure'>Simple JSON</h6> + <img class='bordered' src="doc-files/Example_JSONSimple.png"> + + <p> + In addition to serializing POJOs to JSON, Juneau includes support for serializing POJO metamodels to + JSON Schema. + </p> + + <h6 class='figure'>JSON Schema</h6> + <img class='bordered' src="doc-files/Example_JSONSchema.png"> + + <p> + The JSON data type produced depends on the Java object type being serialized. + </p> + <ul class='spaced-list'> + <li> + Primitives and primitive objects are converted to JSON primitives. + <li> + Beans and Maps are converted to JSON objects. + <li> + Collections and arrays are converted to JSON arrays. + <li> + Anything else is converted to JSON strings. + </ul> + + <h6 class='topic'>Examples:</h6> + <table class='styled'> + <tr> + <th>POJO type</th> + <th>Example</th> + <th>Serialized form</th> + </tr> + <tr> + <td>String</td> + <td><code>serializer.serialize(<js>"foobar"</js>);</code></td> + <td><code><js>'foobar'</js></code> + </tr> + <tr> + <td>Number</td> + <td><code>serializer.serialize(123);</code></td> + <td><code><jk>123</jk></code> + </tr> + <tr> + <td>Boolean</td> + <td><code>serializer.serialize(<jk>true</jk>);</code></td> + <td><code><jk>true</jk></code> + </tr> + <tr> + <td>Null</td> + <td><code>serializer.serialize(<jk>null</jk>);</code></td> + <td><code><jk>null</jk></code> + </tr> + <tr> + <td>Beans with properties of any type on this list</td> + <td><code>serializer.serialize(<jk>new</jk> MyBean());</code></td> + <td><code>{p1:<js>'val1'</js>,p2:<jk>true</jk>}</code> + </tr> + <tr> + <td>Maps with values of any type on this list</td> + <td><code>serializer.serialize(<jk>new</jk> TreeMap());</code></td> + <td><code>{key1:<js>'val1'</js>,key2:<jk>true</jk>}</code> + </tr> + <tr> + <td>Collections and arrays of any type on this list</td> + <td><code>serializer.serialize(<jk>new</jk> Object[]{1,<js>"foo"</js>,<jk>true</jk>});</code></td> + <td><code>[1,'foo',true]</code> + </tr> + </table> + <p> + In addition, swaps can be used to convert non-serializable POJOs into serializable forms, such as converting + <code>Calendar</code> object to ISO8601 strings, or <code><jk>byte</jk>[]</code> arrays to Base-64 + encoded strings. + <br>These swaps can be associated at various levels: + </p> + <ul class='spaced-list'> + <li> + On serializer and parser instances to handle all objects of the class type globally. + <li> + On classes through the <code><ja>@Bean</ja></code> annotation. + <li> + On bean properties through the <code><ja>@BeanProperty</ja></code> annotations. + </ul> + <p> + For more information about transforms, refer to <a class='doclink' + href='../transform/package-summary.html#TOC'>org.apache.juneau.transform</a>. + </p> + </div> +</div> + +<!-- ======================================================================================================== --> +<a id="JsonSerializer"></a> +<h2 class='topic' onclick='toggle(this)'>2 - JsonSerializer class</h2> +<div class='topic'> + <p> + {@link org.apache.juneau.json.JsonSerializer} is the class used to convert POJOs to JSON. + <br>{@link org.apache.juneau.json.JsonSchemaSerializer} is the class used to generate JSON-Schema from POJOs. + </p> + <p> + The JSON serializer includes several configurable settings. + <br>Static reusable instances of Json serializers are provided with commonly-used settings: + </p> + <ul class='spaced-list'> + <li> + {@link org.apache.juneau.json.JsonSerializer#DEFAULT} - All default settings + <li> + {@link org.apache.juneau.json.JsonSerializer#DEFAULT_LAX} - Single quotes, only quote attributes when + necessary. + <li> + {@link org.apache.juneau.json.JsonSerializer#DEFAULT_LAX_READABLE} - Readable output. + </ul> + + <h6 class='topic'>Notes about examples</h6> + <p> + The examples shown in this document will use single-quote, readable settings. + <br>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 upon it. + </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 simple JSON: + </p> + <p class='bcode'> + <jc>// Use serializer with readable output, simple mode.</jc> + JsonSerializer s = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>; + + <jc>// Create our bean.</jc> + Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>); + + <jc>// Serialize the bean to JSON.</jc> + String json = s.serialize(p); + </p> + <p> + We could have also created a new serializer with the same settings using the following code: + </p> + <p class='bcode'> + JsonSerializer s = <jk>new</jk> JsonSerializerBuilder().simple().ws().sq().build(); + </p> + + <p> + The code above produces the following output: + </p> + <p class='bcode'> + { + id: <jk>1</jk>, + name: <js>'John Smith'</js> + } + </p> + + + <!-- ======================================================================================================== --> + <a id="BeanAnnotations"></a> + <h3 class='topic' onclick='toggle(this)'>2.1 - @Bean and @BeanProperty annotations</h3> + <div class='topic'> + <p> + The {@link org.apache.juneau.annotation.Bean @Bean} and + {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotations are used to customize the + behavior of beans across the entire framework. + <br>They have various 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 swaps 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>We'll also add a couple of <code>URI</code> properties. + <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> + <jk>public int</jk> <jf>id</jf>; + <jk>public</jk> String <jf>name</jf>; + <jk>public</jk> URI <jf>uri</jf>; + <jk>public</jk> URI <jf>addressBookUri</jf>; + + <ja>@BeanProperty</ja>(swap=CalendarSwap.ISO8601DTZ.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</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, String uri, String addressBookUri, String birthDate) <jk>throws</jk> Exception { + <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); + <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> + Next, 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'> + { + id: <jk>1</jk>, + name: <js>'John Smith'</js>, + uri: <js>'http://sample/addressBook/person/1'</js>, + addressBookUri: <js>'http://sample/addressBook'</js>, + birthDate: <js>'1946-08-12T00:00:00Z'</js> + } + </p> + <p> + Another useful feature is the {@link org.apache.juneau.annotation.Bean#propertyNamer()} annotation that + allows you to plug in your own logic for determining bean property names. + <br>The {@link org.apache.juneau.PropertyNamerDLC} is an example of an alternate property namer. + It converts bean property names to lowercase-dashed format. + </p> + + <h6 class='topic'>Example:</h6> + <p class='bcode'> + <ja>@Bean</ja>(propertyNamer=PropertyNamerDLC.<jk>class</jk>) + <jk>public class</jk> Person { + ... + </p> + + <h6 class='figure'>Results</h6> + <p class='bcode'> + { + id: <jk>1</jk>, + name: <js>'John Smith'</js>, + uri: <js>'http://sample/addressBook/person/1'</js>, + <js>'address-book-uri'</js>: <js>'http://sample/addressBook'</js>, + <js>'birth-date'</js>: <js>'1946-08-12T00:00:00Z'</js> + } + </p> + </div> + + + <!-- ======================================================================================================== --> + <a id="Collections"></a> + <h3 class='topic' onclick='toggle(this)'>2.2 - Collections</h3> + <div class='topic'> + <p> + 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'> + <jk>public class</jk> Address { + + <jc>// Bean properties</jc> + <jk>public</jk> URI <jf>uri</jf>; + <jk>public</jk> URI <jf>personUri</jf>; + <jk>public int</jk> <jf>id</jf>; + <jk>public</jk> String <jf>street</jf>, <jf>city</jf>, <jf>state</jf>; + <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>// Use serializer with readable output, simple mode.</jc> + JsonSerializer s = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>; + + <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'> + { + id: <jk>1</jk>, + name: <js>'John Smith'</js>, + uri: <js>'http://sample/addressBook/person/1'</js>, + addressBookUri: <js>'http://sample/addressBook'</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: <jk>1</jk>, + street: <js>'100 Main Street'</js>, + city: <js>'Anywhereville'</js>, + state: <js>'NY'</js>, + zip: <jk>12345</jk>, + isCurrent: <jk>true</jk> + } + ] + } + </p> + </div> + + + <!-- ======================================================================================================== --> + <a id="JsonSchemaSupport"></a> + <h3 class='topic' onclick='toggle(this)'>2.3 - JSON-Schema support</h3> + <div class='topic'> + <p> + Juneau provides the {@link org.apache.juneau.json.JsonSchemaSerializer} class for generating JSON-Schema + documents that describe the output generated by the {@link org.apache.juneau.json.JsonSerializer} class. + <br>This class shares the same properties as <code>JsonSerializer</code>. + <br>For convenience the {@link org.apache.juneau.json.JsonSerializer#getSchemaSerializer()} method has been + added for creating instances of schema serializers from the regular serializer instance. + </p> + <p> + <i>Note:</i> As of this writing, JSON-Schema has not been standardized, so the output generated by the + schema serializer may be subject to future modifications. + </p> + <p> + Lets start with the classes from the previous examples: + </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>; + <jk>public</jk> URI <jf>uri</jf>; + <jk>public</jk> URI <jf>addressBookUri</jf>; + <ja>@BeanProperty</ja>(swap=CalendarSwap.ISO8601DTZ.<jk>class</jk>) <jk>public</jk> Calendar <jf>birthDate</jf>; + <jk>public</jk> LinkedList<Address> <jf>addresses</jf> = <jk>new</jk> LinkedList<Address>(); + + <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, String uri, String addressBookUri, String birthDate) <jk>throws</jk> Exception { + <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); + <jk>this</jk>.<jf>birthDate</jf> = <jk>new</jk> GregorianCalendar(); + <jk>this</jk>.<jf>birthDate</jf>.setTime(DateFormat.getDateInstance(DateFormat.<jsf>MEDIUM</jsf>).parse(birthDate)); + } + } + + <jk>public class</jk> Address { + <jc>// Bean properties</jc> + <jk>public</jk> URI <jf>uri</jf>; + <jk>public</jk> URI <jf>personUri</jf>; + <jk>public int</jk> <jf>id</jf>; + <jk>public</jk> String <jf>street</jf>, <jf>city</jf>, <jf>state</jf>; + <jk>public int</jk> <jf>zip</jf>; + <jk>public boolean</jk> <jf>isCurrent</jf>; + } + </p> + <p> + The code for creating our POJO model and generating JSON-Schema is shown below: + </p> + <p class='bcode'> + <jc>// Get the schema serializer for one of the default JSON serializers.</jc> + JsonSchemaSerializer s = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>.getSchemaSerializer(); + + <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>// Get the JSON Schema corresponding to the JSON generated above.</jc> + String jsonSchema = s.serialize(p); + </p> + + <h6 class='figure'>Results</h6> + <p class='bcode'> + { + type: <js>'object'</js>, + description: <js>'org.apache.juneau.sample.Person'</js>, + properties: { + id: { + type: <js>'number'</js>, + description: <js>'int'</js> + }, + name: { + type: <js>'string'</js>, + description: <js>'java.lang.String'</js> + }, + uri: { + type: <js>'any'</js>, + description: <js>'java.net.URI'</js> + }, + addressBookUri: { + type: <js>'any'</js>, + description: <js>'java.net.URI'</js> + }, + birthDate: { + type: <js>'any'</js>, + description: <js>'java.util.Calendar'</js> + }, + addresses: { + type: <js>'array'</js>, + description: <js>'java.util.LinkedList<org.apache.juneau.sample.Address>'</js>, + items: { + type: <js>'object'</js>, + description: <js>'org.apache.juneau.sample.Address'</js>, + properties: { + uri: { + type: <js>'any'</js>, + description: <js>'java.net.URI'</js> + }, + personUri: { + type: <js>'any'</js>, + description: <js>'java.net.URI'</js> + }, + id: { + type: <js>'number'</js>, + description: <js>'int'</js> + }, + street: { + type: <js>'string'</js>, + description: <js>'java.lang.String'</js> + }, + city: { + type: <js>'string'</js>, + description: <js>'java.lang.String'</js> + }, + state: { + type: <js>'string'</js>, + description: <js>'java.lang.String'</js> + }, + zip: { + type: <js>'number'</js>, + description: <js>'int'</js> + }, + isCurrent: { + type: <js>'boolean'</js>, + description: <js>'boolean'</js> + } + } + } + } + } + } + </p> + </div> + + + <!-- ======================================================================================================== --> + <a id="Recursion"></a> + <h3 class='topic' onclick='toggle(this)'>2.4 - Non-tree models and recursion detection</h3> + <div class='topic'> + <p> + The JSON serializer is designed to be used against POJO 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 JSON 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> + For example, let's make a POJO model out of the following classes: + </p> + <p class='bcode'> + <jk>public class</jk> A { + <jk>public</jk> B b; + } + + <jk>public class</jk> B { + <jk>public</jk> C c; + } + + <jk>public class</jk> C { + <jk>public</jk> A a; + } + </p> + <p> + Now we create a model with a loop and serialize the results. + </p> + <p class='bcode'> + <jc>// Clone an existing serializer and set property for detecting recursions.</jc> + JsonSerializer s = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>.builder().detectRecursions(<jk>true</jk>).build(); + + <jc>// Create a recursive loop.</jc> + A a = <jk>new</jk> A(); + a.<jf>b</jf> = <jk>new</jk> B(); + a.<jf>b</jf>.<jf>c</jf> = <jk>new</jk> C(); + a.<jf>b</jf>.<jf>c</jf>.<jf>a</jf> = a; + + <jc>// Serialize to JSON.</jc> + String json = s.serialize(a); + </p> + <p> + What we end up with is the following, which does not serialize the contents of the <code>c</code> field: + </p> + <p class='bcode'> + { + b: { + c: { + } + } + } + </p> + <p> + Without recursion detection enabled, this would cause a stack-overflow error. + </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.5 - 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.json.JsonSerializerContext} - Serializer context properties. + </ul> + </div> + + + <!-- ======================================================================================================== --> + <a id="SerializerOtherNotes"></a> + <h3 class='topic' onclick='toggle(this)'>2.6 - Other notes</h3> + <div class='topic'> + <ul class='spaced-list'> + <li> + Like all other Juneau serializers, the JSON serializer is thread safe and maintains an internal cache + of bean classes encountered. + <br>For performance reasons, it's recommended that serializers be reused whenever possible instead of + always creating new instances. + </ul> + </div> +</div> + + +<!-- ======================================================================================================== --> +<a id="JsonParser"></a> +<h2 class='topic' onclick='toggle(this)'>3 - JsonParser class</h2> +<div class='topic'> + <p> + The {@link org.apache.juneau.json.JsonParser} class is the class used to parse JSON back into POJOs. + </p> + <p> + The JSON parser supports ALL valid JSON, including: + </p> + <ul class='spaced-list'> + <li> + Javascript comments. + <li> + Single or double quoted values. + <li> + Quoted (strict) or unquoted (non-strict) attributes. + <li> + JSON fragments (such as string, numeric, or boolean primitive values). + <li> + Concatenated strings. + </ul> + <p> + A static reusable instance of <code>JsonParser</code> is also provided for convenience: + </p> + <ul> + <li>{@link org.apache.juneau.json.JsonParser#DEFAULT} + </ul> + <p> + Let's build upon the previous example and parse the generated JSON back into the original bean. + <br>We start with the JSON that was generated. + </p> + <p class='bcode'> + <jc>// Use serializer with readable output, simple mode.</jc> + JsonSerializer s = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>; + + <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 JSON.</jc> + String json = s.serialize(p); + </p> + <p> + This code produced the following: + </p> + <p class='bcode'> + { + id: <jk>1</jk>, + name: <js>'John Smith'</js>, + uri: <js>'http://sample/addressBook/person/1'</js>, + addressBookUri: <js>'http://sample/addressBook'</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: <jk>1</jk>, + street: <js>'100 Main Street'</js>, + city: <js>'Anywhereville'</js>, + state: <js>'NY'</js>, + zip: <jk>12345</jk>, + isCurrent: <jk>true</jk> + } + ] + } + </p> + <p> + The code to convert this back into a bean is: + </p> + <p class='bcode'> + <jc>// Parse it back into a bean using the reusable JSON parser.</jc> + Person p = JsonParser.<jsf>DEFAULT</jsf>.parse(json, Person.<jk>class</jk>); + + <jc>// Render it back as JSON.</jc> + json = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>.serialize(p); + </p> + <p> + We print it back out to JSON to show that all the data has been preserved: + </p> + <p class='bcode'> + { + id: <jk>1</jk>, + name: <js>'John Smith'</js>, + uri: <js>'http://sample/addressBook/person/1'</js>, + addressBookUri: <js>'http://sample/addressBook'</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: <jk>1</jk>, + street: <js>'100 Main Street'</js>, + city: <js>'Anywhereville'</js>, + state: <js>'NY'</js>, + zip: <jk>12345</jk>, + 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 JSON 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> + Starting back with our original JSON: + </p> + <p class='bcode'> + { + id: <jk>1</jk>, + name: <js>'John Smith'</js>, + uri: <js>'http://sample/addressBook/person/1'</js>, + addressBookUri: <js>'http://sample/addressBook'</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: <jk>1</jk>, + street: <js>'100 Main Street'</js>, + city: <js>'Anywhereville'</js>, + state: <js>'NY'</js>, + zip: <jk>12345</jk>, + isCurrent: <jk>true</jk> + } + ] + } + </p> + <p> + We can parse this into a generic <code>ObjectMap</code>: + </p> + <p class='bcode'> + <jc>// Parse JSON into a generic POJO model.</jc> + ObjectMap m = JsonParser.<jsf>DEFAULT</jsf>.parse(json, ObjectMap.<jk>class</jk>); + + <jc>// Convert it back to JSON.</jc> + String json = JsonSerializer.<jsf>DEFAULT_LAX_READABLE</jsf>.serialize(m); + </p> + <p> + What we end up with is the exact same output. + <br>Even the numbers and booleans are preserved because they are parsed into <code>Number</code> and + <code>Boolean</code> objects when parsing into generic models. + </p> + <p class='bcode'> + { + id: <jk>1</jk>, + name: <js>'John Smith'</js>, + uri: <js>'http://sample/addressBook/person/1'</js>, + addressBookUri: <js>'http://sample/addressBook'</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: <jk>1</jk>, + street: <js>'100 Main Street'</js>, + city: <js>'Anywhereville'</js>, + state: <js>'NY'</js>, + zip: <jk>12345</jk>, + isCurrent: <jk>true</jk> + } + ] + } + </p> + <p> + Once parsed into a generic model, various convenience methods are provided on the <code>ObjectMap</code> + and <code>ObjectList</code> classes to retrieve values: + </p> + <p class='bcode'> + <jc>// Parse JSON into a generic POJO model.</jc> + ObjectMap m = JsonParser.<jsf>DEFAULT</jsf>.parse(json, 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> + 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> + <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.json.JsonParserContext} - Serializer 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 JSON parser is thread safe and maintains an internal cache of bean + classes encountered. + <br>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
