http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/package.html ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/package.html b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/package.html deleted file mode 100755 index 790aa41..0000000 --- a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/package.html +++ /dev/null @@ -1,1410 +0,0 @@ -<!DOCTYPE HTML> -<!-- - Licensed Materials - Property of IBM - (c) Copyright IBM Corporation 2014. All Rights Reserved. - - Note to U.S. Government Users Restricted Rights: - Use, duplication or disclosure restricted by GSA ADP Schedule - Contract with IBM Corp. - --> -<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>URL encoding 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'>URL encoding support overview</a></p> - <ol> - <li><p><a class='doclink' href='#OverviewExample'>Example</a></p> - </ol> - <li><p><a class='doclink' href='#UrlEncodingSerializer'>UrlEncodingSerializer and UonSerializer classes</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='#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='#UrlEncodingParser'>UrlEncodingParser and UonParser classes</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> - <li><p><a class='doclink' href='#RestApiSupport'>REST API support</a></p> - <ol> - <li><p><a class='doclink' href='#RestServerSupport'>REST server support</a></p> - <ol> - <li><p><a class='doclink' href='#RestServletDefault'>Using RestServletDefault</a></p> - <li><p><a class='doclink' href='#RestServlet'>Using RestServlet with annotations</a></p> - <li><p><a class='doclink' href='#DefaultProvider'>Using JAX-RS DefaultProvider</a></p> - <li><p><a class='doclink' href='#BaseProvider'>Using JAX-RS BaseProvider with annotations</a></p> - </ol> - <li><p><a class='doclink' href='#RestClientSupport'>REST client support</a></p> - </ol> -</ol> - -<!-- ======================================================================================================== --> -<a id="Overview"></a> -<h2 class='topic' onclick='toggle(this)'>1 - URL encoding support overview</h2> -<div class='topic'> - <p> - Juno supports converting arbitrary POJOs to and from URL-encoded strings using ultra-efficient serializers and parsers.<br> - The serializer converts POJOs directly to URL-encoded strings without the need for intermediate DOM objects using a highly-efficient state machine.<br> - Likewise, the parser creates POJOs directly from URL-encoded strings without the need for intermediate DOM objects. - </p> - <p> - Juno uses UON (URL-Encoded Object Notation) for representing POJOs. - The UON specification can be found <a href='doc-files/rfc_uon.txt'>here</a>. - </p> - <p> - Juno can serialize and parse instances of any of the following POJO types: - </p> - <ul> - <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>PojoFilters</code> that convert them to serializable forms. - </ul> - <p> - Refer to <a href='../package-summary.html#PojoCategories' class='doclink'>POJO Categories</a> for a complete definition of supported POJOs. - </p> - <h6 class='topic'>Prerequisites</h6> - <p> - The Juno URL-encoding 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 - URL-encoding support overview - example</h3> - <div class='topic'> - <p> - The example shown here is from the Address Book resource located in the <code>com.ibm.juno.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/people/1</code>, the POJO is rendered as HTML: - </p> - <img class='bordered' src="doc-files/Example_HTML.png"> - <p> - By appending <code>?Accept=application/x-www-form-urlencoded&plainText=true</code> to the URL, you can view the data as a URL-encoded string: - </p> - <img class='bordered' src="doc-files/Example_UrlEncoding.png"> - - <p> - Juno supports two kinds of serialization: - </p> - <ul> - <li>Construction of full URL query parameter strings (e.g. <code>&key=value</code> pairs) from beans and maps. - <li>Construction of URL query parameter value strings (e.g. just the <code>value</code> portion of <code>&key=value</code> pairs) from any POJO. - </ul> - <p> - Top-level beans and maps can serialized as key/value pairs as shown below: - </p> - <h6 class='figure'>Example: A bean with 2 string properties, 'foo' and 'baz', serialized to a query string</h6> - <p class='bcode'> http://localhost/sample?<xa>foo</xa>=<xs>bar</xs>&<xa>baz</xa>=<xs>bing</xs></p> - <p> - Lower-level beans and maps are also serialized as key/value pairs, but are surrounded with a <js>"$o(...)"</js> construct to denote an object mapping, - and uses a comma as the parameter delimiter instead of <js>"&"</js>.<br> - </p> - <h6 class='figure'>Example: A bean serialized as a query parameter value.</h6> - <p class='bcode'> http://localhost/sample?<xa>a1</xa>=$o(<xa>foo</xa>=<xs>bar</xs>,<xa>baz</xa>=<xs>bing</xs>)</p> - <p> - The UON specification defines two separate modes: - </p> - <ul> - <li>Strict mode - Serialized model is fully equivalent to JSON and can be losslessly converted back and forth into a JSON model without additional information. - <li>Lax mode - A shortened form that excludes data type information. Ideal if the data types of values are fixed and already known by the parser. - </ul> - <table class='styled' style='border-collapse: collapse;'> - <tr><th>Java type</th><th>JSON equivalent</th><th>Strict syntax</th><th>Lax syntax</th></tr> - <tr> - <td>Maps/beans</td> - <td>OBJECT</td> - <td class='code'><xa>a1</xa>=$o(<xa>b1</xa>=<xs>x1</xs>,<xa>b2</xa>=<xs>x2</xs>)<br><xa>a1</xa>=$o(<xa>b1</xa>=$o(<xa>c1</xa>=<xs>x1</xs>,<xa>c2</xa>=<xs>x2</xs>))</td> - <td class='code'><xa>a1</xa>=(<xa>b1</xa>=<xs>x1</xs>,<xa>b2</xa>=<xs>x2</xs>)<br><xa>a1</xa>=(<xa>b1</xa>=(<xa>c1</xa>=<xs>x1</xs>,<xa>c2</xa>=<xs>x2</xs>))</td> - </tr> - <tr> - <td>Collections/arrays</td> - <td>ARRAY</td> - <td class='code'><xa>a1</xa>=$a(<xs>x1</xs>,<xs>x2</xs>)<br><xa>a1</xa>=$a($a(<xs>x1</xs>,<xs>x2</xs>),$a(<xs>x3</xs>,<xs>x4</xs>))<br><xa>a1</xa>=$a($o(<xa>b1</xa>=<xs>x1</xs>,<xa>b2</xa>=<xs>x2</xs>),$o(<xa>c1</xa>=<xs>x1</xs>,<xa>c2</xa>=<xs>x2</xs>))</td> - <td class='code'><xa>a1</xa>=(<xs>x1</xs>,<xs>x2</xs>)<br><xa>a1</xa>=((<xs>x1</xs>,<xs>x2</xs>),(<xs>x3</xs>,<xs>x4</xs>))<br><xa>a1</xa>=((<xa>b1</xa>=<xs>x1</xs>,<xa>b2</xa>=<xs>x2</xs>),(<xa>c1</xa>=<xs>x1</xs>,<xa>c2</xa>=<xs>x2</xs>))</td> - </tr> - <tr> - <td>Booleans</td> - <td>BOOLEAN</td> - <td class='code'><xa>a1</xa>=$b(<xs>true</xs>)&<xa>a2</xa>=$b(<xs>false</xs>)</td> - <td class='code'><xa>a1</xa>=<xs>true</xs>&<xa>a2</xa>=<xs>false</xs></td> - </tr> - <tr> - <td>int/float/double/...</td> - <td>NUMBER</td> - <td class='code'><xa>a1</xa>=$n(<xs>123</xs>)&<xa>a2</xa>=$n(<xs>1.23e1</xs>)</td> - <td class='code'><xa>a1</xa>=<xs>123</xs>&<xa>a2</xa>=<xs>1.23e1</xs></td> - </tr> - <tr> - <td>null</td> - <td>NULL</td> - <td class='code'><xa>a1</xa>=<xs>%00</xs></td> - <td class='code'><xa>a1</xa>=<xs>%00</xs></td> - </tr> - <tr> - <td>String</td> - <td>STRING</td> - <td class='code'><xa>a1</xa>=<xs>foobar</xs></td> - <td class='code'><xa>a1</xa>=<xs>foobar</xs></td> - </tr> - </table> - <p> - Refer to the <a href='doc-files/rfc_uon.txt'>UON specification</a> for a complete set of syntax rules. - <p> - Filters 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 filters can be associated at various levels: - </p> - <ul> - <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> - <h6 class='figure'>Example: A serialized Calendar object using <code>CalendarFilter.RFC2822DTZ</code> filter.</h6> - <p class='bcode'> http://localhost/sample?<xa>a1=<js>Sun~,+03+Mar+1901+09:05:06+GMT</js></p> - <p> - For more information about filters, refer to {@link com.ibm.juno.core.filter}. - </p> - </div> - -</div> - -<!-- ======================================================================================================== --> -<a id="UrlEncodingSerializer"></a> -<h2 class='topic' onclick='toggle(this)'>2 - UrlEncodingSerializer and UonSerializer classes</h2> -<div class='topic'> - <p> - {@link com.ibm.juno.core.urlencoding.UrlEncodingSerializer} and {@link com.ibm.juno.core.urlencoding.UonSerializer} classes are used to convert POJOs to URL-encoded strings.<br> - The <code>UonSerializer</code> class converts parameter values to UON notation. - The <code>UrlEncodingSerializer</code> class converts a POJO to key/value URL-Encoded pairs using <code>UonSerializer</code> to serialize the values. - If you're trying to construct complete URL-Encoded entities, use <code>UrlEncodingSerializer</code>. - If you're constructing your own key/value pairs, use <code>UonSerializer</code>. - </p> - <p> - The serializers include several configurable settings.<br> - Static reusable instances of serializers are provided with commonly-used settings: - </p> - <ul> - <li>{@link com.ibm.juno.core.urlencoding.UrlEncodingSerializer#DEFAULT} - All default settings, strict mode. - <li>{@link com.ibm.juno.core.urlencoding.UrlEncodingSerializer#DEFAULT_SIMPLE} - All default settings, lax mode. - <li>{@link com.ibm.juno.core.urlencoding.UrlEncodingSerializer#DEFAULT_READABLE} - Use whitespace and indentation for readability. - <li>{@link com.ibm.juno.core.urlencoding.UonSerializer#DEFAULT} - All default settings, strict mode. - <li>{@link com.ibm.juno.core.urlencoding.UonSerializer#DEFAULT_SIMPLE} - All default settings, lax mode. - <li>{@link com.ibm.juno.core.urlencoding.UonSerializer#DEFAULT_READABLE} - Use whitespace and indentation for readability. - <li>{@link com.ibm.juno.core.urlencoding.UonSerializer#DEFAULT_ENCODING} - Same as DEFAULT, but use URL-Encoding on special characters. - <li>{@link com.ibm.juno.core.urlencoding.UonSerializer#DEFAULT_SIMPLE_ENCODING} - Same as DEFAULT_SIMPLE, but use URL-Encoding on special characters. - </ul> - <p> - The general guidelines on which serializer to use is: - </p> - <ul> - <li>Use strict mode serializers if the data types of the value are not known on the parsing side, and this - information needs to be preserved during transmission. - <li>Use lax mode serializers if the data types of the value are known on the parsing side. - For example, if you're serializing/parsing beans, lax mode is usually sufficient since the data types - can be inferred from the bean properties. - <li>Use encoding serializers when you're using the results to construct a URI yourself, and therefore - need invalid URI characters to be encoded. - <li>Use unencoding serializers when you're creating parameter values and passing them off to some other - utility class that will itself encode invalid URI characters. - <li>Use the readable serializer for debugging purposes. - </ul> - - <h6 class='topic'>Notes about examples</h6> - <p> - The examples shown in this document will use default strict 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 a URL-encoded value: - </p> - <p class='bcode'> - <jc>// Use serializer with readable output, simple mode.</jc> - UonSerializer s = UonSerializer.<jsf>DEFAULT</jsf>; - - <jc>// Create our bean.</jc> - Person p = <jk>new</jk> Person(1, <js>"John Smith"</js>); - - <jc>// Serialize the bean to URL-encoded parameter value.</jc> - String urlencoded = s.serialize(p); - </p> - <p> - The code above produces the following output: - </p> - <p class='bcode'> - $o(<xa>id</xa>=$n(<xs>1</xs>),<xa>name</xa>=<xs>John+Smith</xs>) - </p> - <p> - The {@link com.ibm.juno.core.urlencoding.UrlEncodingSerializer} class converts - maps and beans into top-level query parameter strings. - </p> - <p class='bcode'> - <jc>// Use serializer with readable output, simple mode.</jc> - UrlEncodingSerializer s = UrlEncodingSerializer.<jsf>DEFAULT</jsf>; - - <jc>// Serialize the bean to URL-encoded query string.</jc> - String urlencoded = s.serialize(p); - </p> - <p> - The code above produces the following output: - </p> - <p class='bcode'> - <xa>id</xa>=$n(<xs>1</xs>)&<xa>name</xa>=<xs>John+Smith</xs> - </p> - <p> - The general method guidelines are as follows: - </p> - <ul> - <li>Use <code>UonSerializer</code> to create individual query parameter values. - <li>Use <code>UrlEncodingSerializer</code> to create complete URL-encoded query strings. - </ul> - <p> - By default, the <code>UrlEncodingSerializer</code> class will URL-Encode special characters, and the <code>UonSerializer</code> will NOT URL-encode special characters. - </p> - - - <!-- ======================================================================================================== --> - <a id="BeanAnnotations"></a> - <h3 class='topic' onclick='toggle(this)'>2.1 - @Bean and @BeanProperty annotations</h3> - <div class='topic'> - <p> - The {@link com.ibm.juno.core.annotation.Bean @Bean} and {@link com.ibm.juno.core.annotation.BeanProperty @BeanProperty} annotations - are used to customize the behavior of beans across the entire framework.<br> - They have various uses: - </p> - <ul> - <li>Hiding bean properties. - <li>Specifying the ordering of bean properties. - <li>Overriding the names of bean properties. - <li>Associating filters 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 filter 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 filters, 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>(filter=CalendarFilter.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'> - $o(<xa>id</xa>=$n(<xs>1</xs>),<xa>name</xa>=<xs>John+Smith</xs>,<xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>,<xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>,<xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>) - </p> - <p> - Using <code>UrlEncodingSerializer</code> instead would create the following: - </p> - <p class='bcode'> - <xa>id</xa>=$n(<xs>1</xs>)&<xa>name</xa>=<xs>John+Smith</xs>&<xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>&<xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>&<xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs> - </p> - <p> - Another useful feature is the {@link com.ibm.juno.core.annotation.Bean#propertyNamer()} annotation that allows you to plug in your own - logic for determining bean property names.<br> - The {@link com.ibm.juno.core.PropertyNamerDashedLC} is an example of an alternate property namer. - It converts bean property names to lowercase-dashed format. - </p> - <h6 class='figure'>Example</h6> - <p class='bcode'> - <ja>@Bean</ja>(propertyNamer=PropertyNamerDashedLC.<jk>class</jk>) - <jk>public class</jk> Person { - ... - </p> - <h6 class='figure'>Results</h6> - <p class='bcode'> - $o(<xa>id</xa>=$n(<xs>1</xs>),<xa>name</xa>=<xs>John+Smith</xs>,<xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>,<xa>address-book-uri</xa>=<xs>http://sample/addressBook</xs>,<xa>birth-date</xa>=<xs>1946-08-12T00:00:00Z</xs>) - </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> - UonSerializer s = UonSerializer.<jsf>DEFAULT_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 (in readable format): - </p> - <p class='bcode'> - $o( - <xa>id</xa>=$n(<xs>1</xs>), - <xa>name</xa>=<xs>John+Smith</xs>, - <xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>, - <xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>, - <xa>addresses</xa>=$a( - $o( - <xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>, - <xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>id</xa>=$n(<xs>1</xs>), - <xa>street</xa>=<xs>100+Main+Street</xs>, - <xa>city</xa>=<xs>Anywhereville</xs>, - <xa>state</xa>=<xs>NY</xs>, - <xa>zip</xa>=$n(<xs>12345</xs>), - <xa>isCurrent</xa>=$b(<xs>true</xs>) - ) - ) - ) - </p> - <p> - If we were to use lax mode instead, we would get the following: - </p> - <p class='bcode'> - ( - <xa>id</xa>=<xs>1</xs>, - <xa>name</xa>=<xs>John+Smith</xs>, - <xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>, - <xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>, - <xa>addresses</xa>=( - ( - <xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>, - <xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>id</xa>=<xs>1</xs>, - <xa>street</xa>=<xs>100+Main+Street</xs>, - <xa>city</xa>=<xs>Anywhereville</xs>, - <xa>state</xa>=<xs>NY</xs>, - <xa>zip</xa>=<xs>12345</xs>, - <xa>isCurrent</xa>=<xs>true</xs> - ) - ) - ) - </p> - <p> - Note how the data type information is removed, so it's not possible to distinguish between numbers/booleans/strings, and between objects/arrays. - However, this is fine if we're parsing back into the same beans, since we can inver the data types from the bean property metadata. - </p> - <p> - If we were to use <code>UrlEncodingSerializer</code> instead, we would get the following: - </p> - <p class='bcode'> - <xa>id</xa>=$n(<xs>1</xs>)& - <xa>name</xa>=<xs>John+Smith</xs>& - <xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>& - <xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>& - <xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>& - <xa>addresses</xa>=$a( - $o( - <xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>, - <xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>id</xa>=$n(<xs>1</xs>), - <xa>street</xa>=<xs>100+Main+Street</xs>, - <xa>city</xa>=<xs>Anywhereville</xs>, - <xa>state</xa>=<xs>NY</xs>, - <xa>zip</xa>=$n(<xs>12345</xs>), - <xa>isCurrent</xa>=$b(<xs>true</xs>) - ) - ) - </p> - </div> - <p> - Note how the top level <code>Person</code> bean is serialized using the standard <js>'&'</js> delimiter, whereas the lower-level <code>Address</code> - bean is serialized using the <js>','</js> character to prevent the <code>addresses</code> field from being incompletely parsed. - </p> - - - - - <!-- ======================================================================================================== --> - <a id="Recursion"></a> - <h3 class='topic' onclick='toggle(this)'>2.3 - Non-tree models and recursion detection</h3> - <div class='topic'> - <p> - The URL-encoding 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 com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_maxDepth} is not reached first). - </p> - <p> - If you still want to use the URL-encoding serializer on such models, Juno provides the - {@link com.ibm.juno.core.serializer.SerializerProperties#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> - UrlEncodingSerializer s = UrlEncodingSerializer.<jsf>DEFAULT_READABLE</jsf>.clone().setProperty(SerializerProperties.<jsf>SERIALIZER_detectRecursions</jsf>, <jk>true</jk>); - - <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.</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'> - $o( - <xa>b</xa>=$o( - <xa>c</xa>=$o() - ) - ) - </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.4 - Configurable properties</h3> - <div class='topic'> - <p> - The full list of configurable settings applicable to the <code>UrlEncodingSerializer</code> class is shown below: - </p> - <table class='styled' style='border-collapse: collapse;'> - <tr><th>Property</th><th>Short Description</th></tr> - <tr> - <td>{@link com.ibm.juno.core.urlencoding.UonSerializerProperties#UON_simpleMode}</td> - <td>Use UON lax mode instead of strict mode</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.urlencoding.UonSerializerProperties#UON_useWhitespace}</td> - <td>Use whitespace in output</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.urlencoding.UonSerializerProperties#UON_encodeChars}</td> - <td>Encode invalid URI characters</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_maxDepth}</td> - <td>Maximum serialization depth</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_detectRecursions}</td> - <td>Automatically detect POJO recursions</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_useIndentation}</td> - <td>Use indentation in output</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_trimNullProperties}</td> - <td>Trim null bean property values from output</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_trimEmptyLists}</td> - <td>Trim empty lists and arrays from output</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_trimEmptyMaps}</td> - <td>Trim empty maps from output</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_relativeUriBase}</td> - <td>URI context root for relative URIs</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.serializer.SerializerProperties#SERIALIZER_absolutePathUriBase}</td> - <td>URI authority for absolute path relative URIs</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_beansRequireDefaultConstructor}</td> - <td>Beans require no-arg constructors</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_beansRequireSerializable}</td> - <td>Beans require <code>Serializable</code> interface</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_beansRequireSettersForGetters}</td> - <td>Beans require setters for getters</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_beansRequireSomeProperties}</td> - <td>Beans require some properties</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_beanConstructorVisibility}</td> - <td>Look for bean constructors with the specified minimum visibility</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_beanClassVisibility}</td> - <td>Look for bean classes with the specified minimum visibility</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_beanFieldVisibility}</td> - <td>Look for bean fields with the specified minimum visibility</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_methodVisibility}</td> - <td>Look for bean methods with the specified minimum visibility</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_useInterfaceProxies}</td> - <td>Use interface proxies</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_ignoreUnknownBeanProperties}</td> - <td>Ignore unknown properties</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_ignoreUnknownNullBeanProperties}</td> - <td>Ignore unknown properties with null values</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_ignorePropertiesWithoutSetters}</td> - <td>Ignore properties without setters</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_ignoreInvocationExceptionsOnGetters}</td> - <td>Ignore invocation errors when calling getters</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_ignoreInvocationExceptionsOnSetters}</td> - <td>Ignore invocation errors when calling setters</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_addNotBeanPackages}</td> - <td>Add to the list of packages whose classes should not be considered beans</td> - </tr> - <tr> - <td>{@link com.ibm.juno.core.BeanContextProperties#BEAN_removeNotBeanPackages}</td> - <td>Remove from the list of packages whose classes should not be considered beans</td> - </tr> - </table> - </div> - - - <!-- ======================================================================================================== --> - <a id="SerializerOtherNotes"></a> - <h3 class='topic' onclick='toggle(this)'>2.5 - Other notes</h3> - <div class='topic'> - <ul> - <li>Like all other Juno serializers, the URL-encoding serializers are thread safe and maintain 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="UrlEncodingParser"></a> -<h2 class='topic' onclick='toggle(this)'>3 - UrlEncodingParser and UonParser classes</h2> -<div class='topic'> - <p> - {@link com.ibm.juno.core.urlencoding.UrlEncodingParser} and {@link com.ibm.juno.core.urlencoding.UonParser} classes are used to convert URL-encoded strings back into POJOs.<br> - The <code>UonParser</code> class converts UON-encoded parameter values to POJOs. - The <code>UrlEncodingParser</code> class converts entire URL-Encoded strings to POJOs using <code>UonSerializer</code> to serialize indivisual values. - If you're trying to parse an entire URL-Encoded string, use <code>UrlEncodingParser</code>. - If you're trying to parse an individual value (such as that returned by <code>RestServlet.getParameter(name)</code>), use <code>UonParser</code>. - </p> - <p> - The following static reusable instances of <code>UrlEncodingParser</code> are provided for convenience: - </p> - <ul> - <li>{@link com.ibm.juno.core.urlencoding.UrlEncodingParser#DEFAULT} - Default parser for entire URL-encoded strings, decode <code>%xx</code> sequences. - <li>{@link com.ibm.juno.core.urlencoding.UonParser#DEFAULT} - Default parser for URL-encoded parameter values, don't decode <code>%xx</code> sequences. - <li>{@link com.ibm.juno.core.urlencoding.UonParser#DEFAULT_DECODING} - Default parser for URL-encoded parameter values, decode <code>%xx</code> sequences. - </ul> - <p> - The general guildlines on which parser to use is: - </p> - <ul> - <li>Use the <code>DEFAULT</code> parser for parameter values that have already had <code>%xx</code> sequences decoded, - such as when using <code>HttpServletRequest.getParameter(name)</code>. - <li>Use the <code>DEFAULT_ENCODED</code> parser if the input has not already had <code>%xx</code> sequences decoded. - </ul> - <p> - Let's build upon the previous example and parse the generated URL-encoded string back into the original bean.<br> - We start with the URL-encoded string that was generated. - </p> - <p class='bcode'> - <jc>// Use serializer with readable output.</jc> - UonSerializer s = UonSerializer.<jsf>DEFAULT_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.</jc> - String urlencoded = s.serialize(p); - </p> - <p> - This code produced the following: - </p> - <p class='bcode'> - $o( - <xa>id</xa>=$n(<xs>1</xs>), - <xa>name</xa>=<xs>John+Smith</xs>, - <xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>, - <xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>, - <xa>addresses</xa>=$a( - $o( - <xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>, - <xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>id</xa>=$n(<xs>1</xs>), - <xa>street</xa>=<xs>100+Main+Street</xs>, - <xa>city</xa>=<xs>Anywhereville</xs>, - <xa>state</xa>=<xs>NY</xs>, - <xa>zip</xa>=$n(<xs>12345</xs>), - <xa>isCurrent</xa>=$b(<xs>true</xs>) - ) - ) - ) - </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 = UonParser.<jsf>DEFAULT</jsf>.parse(urlencoded, Person.<jk>class</jk>); - - <jc>// Render it back as JSON.</jc> - json = JsonSerializer.<jsf>DEFAULT_SIMPLE_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 URL-encoding 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 com.ibm.juno.core.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 com.ibm.juno.core.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 URL-encoded string: - </p> - <p class='bcode'> - $o( - <xa>id</xa>=$n(<xs>1</xs>), - <xa>name</xa>=<xs>John+Smith</xs>, - <xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>, - <xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>, - <xa>addresses</xa>=$a( - $o( - <xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>, - <xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>, - <xa>id</xa>=$n(<xs>1</xs>), - <xa>street</xa>=<xs>100+Main+Street</xs>, - <xa>city</xa>=<xs>Anywhereville</xs>, - <xa>state</xa>=<xs>NY</xs>, - <xa>zip</xa>=$n(<xs>12345</xs>), - <xa>isCurrent</xa>=$b(<xs>true</xs>) - ) - ) - ) - </p> - <p> - We can parse this into a generic <code>ObjectMap</code>: - </p> - <p class='bcode'> - <jc>// Parse URL-encoded string into a generic POJO model.</jc> - ObjectMap m = UonParser.<jsf>DEFAULT</jsf>.parse(urlencoded, ObjectMap.<jk>class</jk>); - - <jc>// Convert it back to JSON.</jc> - String json = JsonSerializer.<jsf>DEFAULT_SIMPLE_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 URL-encoded string into a generic POJO model.</jc> - ObjectMap m = UonParser.<jsf>DEFAULT</jsf>.parse(urlencoded, 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 filter.</jc> - CalendarFilter filter = <jk>new</jk> CalendarFilter.ISO8601DTZ(); - Calendar birthDate = m.get(filter, <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> - The full list of configurable settings applicable to the <code>UrlEncodingParser</code> class is shown below: - </p> - <table class='styled' style='border-collapse: collapse;'> - <tr><th>Property</th><th>Short Description</th></tr> - <tr> - <td>{@link com.ibm.juno.core.urlencoding.UonParserProperties#UON_decodeChars}</td> - <td>Decode <js>"%xx"</js> sequences</td> - </tr> - </table> - </div> - - - <!-- ======================================================================================================== --> - <a id="ParserOtherNotes"></a> - <h3 class='topic' onclick='toggle(this)'>3.3 - Other notes</h3> - <div class='topic'> - <ul> - <li>Like all other Juno parsers, the URL-encoding parsers are thread safe and maintain 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> - - -<!-- ======================================================================================================== --> -<a id="RestApiSupport"></a> -<h2 class='topic' onclick='toggle(this)'>4 - REST API support</h2> -<div class='topic'> - <p> - Juno provides fully-integrated support for URL-encoding serialization/parsing in the REST server and client APIs.<br> - The next two sections describe these in detail. - </p> - - <!-- ======================================================================================================== --> - <a id="RestServerSupport"></a> - <h3 class='topic' onclick='toggle(this)'>4.1 - REST server support</h3> - <div class='topic'> - <p> - There are four general ways of defining REST interfaces with support for JSON. - Two using the built-in Juno Server API, and two using the JAX-RS integration component. - </p> - <ul> - <li>Create a servlet that subclasses from {@link com.ibm.juno.server.RestServletDefault}.<br> - This includes URL-encoding serialization/parsing support by default, in addition to several other media types.<br><br> - <li>Create a servlet that subclasses from {@link com.ibm.juno.server.RestServlet} and specify the - URL-encoding serializer and/or parser using the {@link com.ibm.juno.server.annotation.RestResource#serializers()} and - {@link com.ibm.juno.server.annotation.RestResource#parsers()} on the entire servlet class, or - the {@link com.ibm.juno.server.annotation.RestMethod#serializers()} and {@link com.ibm.juno.server.annotation.RestMethod#parsers()} - annotations on individual methods within the class.<br><br> - <li>Register {@link com.ibm.juno.server.jaxrs.DefaultProvider} with JAX-RS.<br> - This includes URL-encoding serialization/parsing support by default, in addition to several other media types.<br><br> - <li>Create and register a subclass of {@link com.ibm.juno.server.jaxrs.BaseProvider} and specify the serializers and parsers to use on JAX-RS resources. - </ul> - <p> - In general, the Juno REST server API is much more configurable and easier to use than JAX-RS, but beware that the author may be slightly biased in this statement. - </p> - - <!-- ======================================================================================================== --> - <a id="RestServletDefault"></a> - <h4 class='topic' onclick='toggle(this)'>4.1.1 - Using RestServletDefault</h4> - <div class='topic'> - <p> - The quickest way to implement a REST resource with URL-encoding support is to create a subclass of {@link com.ibm.juno.server.RestServletDefault}.<br> - This class provides support for JSON, XML, HTML, URL-Encoding, and others. - </p> - <p> - The <code>AddressBookResource</code> example shown in the first chapter uses the <code>RestServletJenaDefault</code> class - which is a subclass of <code>RestServletDefault</code> with additional support for RDF languages.<br> - The start of the class definition is shown below: - </p> - <p class='bcode'> - <jc>// Proof-of-concept resource that shows off the capabilities of working with POJO resources. - // Consists of an in-memory address book repository.</jc> - <ja>@RestResource</ja>( - messages=<js>"nls/AddressBookResource"</js>, - properties={ - <ja>@Property</ja>(name=UonSerializerProperties.<jsf>UON_simpleMode</jsf>, value=<js>"true"</js>), - <ja>@Property</ja>(name=HtmlDocSerializerProperties.<jsf>HTMLDOC_title</jsf>, value=<js>"$L{title}"</js>), - <ja>@Property</ja>(name=HtmlDocSerializerProperties.<jsf>HTMLDOC_description</jsf>, value=<js>"$L{description}"</js>), - <ja>@Property</ja>(name=HtmlDocSerializerProperties.<jsf>HTMLDOC_links</jsf>, value=<js>"{options:'?method=OPTIONS',doc:'doc'}"</js>) - }, - encoders=GzipEncoder.<jk>class</jk> - ) - <jk>public class</jk> AddressBookResource <jk>extends</jk> RestServletJenaDefault { - </p> - <p> - Notice how serializer and parser properties can be specified using the <code>@RestResource.properties()</code> annotation.<br> - In this case, we're overriding the <jsf>UON_simpleMode</jsf> property to produce lax UON notation. - The remaining properties are specific to the HTML serializer. - </p> - <p> - The <code>$L{...}</code> variable represent localized strings pulled from the resource bundle identified by the <code>messages</code> annotation. - These variables are replaced at runtime based on the HTTP request locale. - Several built-in runtime variable types are defined, and the API can be extended to include user-defined variables. - See {@link com.ibm.juno.server.RestServlet#getVarResolver()} for more information. - </p> - <p> - This document won't go into all the details of the Juno <code>RestServlet</code> class.<br> - Refer to the {@link com.ibm.juno.server} documentation for more information on the REST servlet class in general. - </p> - <p> - The rest of the code in the resource class consists of REST methods that simply accept and return POJOs.<br> - The framework takes care of all content negotiation, serialization/parsing, and error handling.<br> - Below are 3 of those methods to give you a general idea of the concept: - </p> - <p class='bcode'> - <jc>// GET person request handler</jc> - <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/people/{id}/*"</js>, rc={200,404}) - <jk>public</jk> Person getPerson(RestRequest req, <ja>@Attr</ja> <jk>int</jk> id) throws Exception { - properties.put(HtmlDocSerializerProperties.<jsf>HTMLDOC_title</jsf>, req.getPathInfo()); - <jk>return</jk> findPerson(id); - } - - <jc>// POST person handler</jc> - <ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/people"</js>, guards=AdminGuard.<jk>class</jk>, rc={307,404}) - <jk>public void</jk> createPerson(RestResponse res, <ja>@Content</ja> CreatePerson cp) <jk>throws</jk> Exception { - Person p = addressBook.createPerson(cp); - res.sendRedirect(p.<jf>uri</jf>); - } - - <jc>// DELETE person handler</jc> - <ja>@RestMethod</ja>(name=<js>"DELETE"</js>, path=<js>"/people/{id}"</js>, guards=AdminGuard.<jk>class</jk>, rc={200,404}) - <jk>public</jk> String deletePerson(RestResponse res, <ja>@Attr</ja> <jk>int</jk> id) <jk>throws</jk> Exception { - Person p = findPerson(id); - addressBook.remove(p); - <jk>return</jk> <js>"DELETE successful"</js>; - } - </p> - <p> - The resource class can be registered with the web application like any other servlet, or can be - defined as a child of another resource through the {@link com.ibm.juno.server.annotation.RestResource#children()} annotation. - </div> - - <!-- ======================================================================================================== --> - <a id="RestServlet"></a> - <h4 class='topic' onclick='toggle(this)'>4.1.2 - Using RestServlet with annotations</h4> - <div class='topic'> - <p> - For fine-tuned control of media types, the {@link com.ibm.juno.server.RestServlet} class - can be subclassed directly.<br> - The serializers/parsers can be specified through annotations at the class and/or method levels. - </p> - <p> - An equivalent <code>AddressBookResource</code> class could be defined to only support URL-encoding using - the following definition: - </p> - <p class='bcode'> - <ja>@RestResource</ja>( - serializers={UrlEncodingSerializer.<jk>class</jk>}, - parsers={UrlEncodingParser.<jk>class</jk>}, - properties={ - <ja>@Property</ja>(name=UonSerializerProperties.<jsf>UON_simpleMode</jsf>, value=<js>"true"</js>) - } - ) - <jk>public class</jk> AddressBookResource <jk>extends</jk> RestServlet { - </p> - <p> - Likewise, serializers and parsers can be specified/augmented/overridden at the method level like so: - </p> - <p class='bcode'> - <jc>// GET person request handler</jc> - <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/people/{id}/*"</js>, rc={200,404}, - serializers={UrlEncodingSerializer.<jk>class</jk>}, - parsers={UrlEncodingParser.<jk>class</jk>}, - properties={ - <ja>@Property</ja>(name=UonSerializerProperties.<jsf>UON_simpleMode</jsf>, value=<js>"true"</js>) - } - ) - <jk>public</jk> Person getPerson(RestRequest req, <ja>@Attr</ja> <jk>int</jk> id) throws Exception { - properties.put(HtmlDocSerializerProperties.<jsf>HTMLDOC_title</jsf>, req.getPathInfo()); - <jk>return</jk> findPerson(id); - } - </p> - <p> - The {@link com.ibm.juno.server.annotation.RestMethod#serializersInherit()} and - {@link com.ibm.juno.server.annotation.RestMethod#parsersInherit()} control how various artifacts - are inherited from the parent class.<br> - Refer to {@link com.ibm.juno.server} for additional information on using these annotations. - </p> - </div> - - <!-- ======================================================================================================== --> - <a id="DefaultProvider"></a> - <h4 class='topic' onclick='toggle(this)'>4.1.3 - Using JAX-RS DefaultProvider</h4> - <div class='topic'> - <p> - URL-encoding media type support in JAX-RS can be achieved by using the {@link com.ibm.juno.server.jaxrs.DefaultProvider} class.<br> - It implements the JAX-RS <code>MessageBodyReader</code> and <code>MessageBodyWriter</code> interfaces for all Juno supported media types. - </p> - <p> - The <code>DefaultProvider</code> class definition is shown below: - </p> - <p class='bcode'> - <ja>@Provider</ja> - <ja>@Produces</ja>({ - <js>"application/json"</js>, <js>"text/json"</js>, <jc>// JsonSerializer</jc> - <js>"application/json+simple"</js>,<js>"text/json+simple"</js>, <jc>// JsonSerializer.Simple</jc> - <js>"application/json+schema"</js>,<js>"text/json+schema"</js>, <jc>// JsonSchemaSerializer</jc> - <js>"text/xml"</js>, <jc>// XmlDocSerializer</jc> - <js>"text/xml+simple"</js>, <jc>// XmlDocSerializer.Simple</jc> - <js>"text/xml+schema"</js>, <jc>// XmlSchemaDocSerializer</jc> - <js>"text/html"</js>, <jc>// HtmlDocSerializer</jc> - <js>"text/uon"</js>, <jc>// UonSerializer</jc> - <js>"application/x-www-form-urlencoded"</js>, <jc>// UrlEncodingSerializer</jc> - <js>"text/xml+soap"</js>, <jc>// SoapXmlSerializer</jc> - <js>"application/x-java-serialized-object"</js> <jc>// JavaSerializedObjectSerializer</jc> - }) - <ja>@Consumes</ja>({ - <js>"application/json"</js>, <js>"text/json"</js>, <jc>// JsonParser</jc> - <js>"text/xml"</js>, <jc>// XmlParser</jc> - <js>"text/html"</js>, <jc>// HtmlParser</jc> - <js>"text/uon"</js>, <jc>// UonParser</jc> - <js>"application/x-www-form-urlencoded"</js>, <jc>// UrlEncodingParser</jc> - <js>"application/x-java-serialized-object"</js> <jc>// JavaSerializedObjectParser</jc> - }) - <ja>@JunoProvider</ja>( - serializers={ - JsonSerializer.<jk>class</jk>, - JsonSerializer.Simple.<jk>class</jk>, - JsonSchemaSerializer.<jk>class</jk>, - XmlDocSerializer.<jk>class</jk>, - XmlDocSerializer.Simple.<jk>class</jk>, - XmlSchemaDocSerializer.<jk>class</jk>, - HtmlDocSerializer.<jk>class</jk>, - UonSerializer.<jk>class</jk>, - UrlEncodingSerializer.<jk>class</jk>, - SoapXmlSerializer.<jk>class</jk>, - JavaSerializedObjectSerializer.<jk>class</jk> - }, - parsers={ - JsonParser.<jk>class</jk>, - XmlParser.<jk>class</jk>, - HtmlParser.<jk>class</jk>, - UonParser.<jk>class</jk>, - UrlEncodingParser.<jk>class</jk>, - JavaSerializedObjectParser.<jk>class</jk>, - } - ) - <jk>public final class</jk> DefaultProvider <jk>extends</jk> BaseProvider {} - </p> - <p> - That's the entire class. It consists of only annotations to hook up media types to Juno serializers and parsers. - The <ja>@Provider</ja>, <ja>@Produces</ja>, and <ja>@Consumes</ja> annotations are standard JAX-RS annotations, and the <ja>@JunoProvider</ja> annotation is from Juno. - </p> - <p> - To enable the provider, you need to make the JAX-RS environment aware of it. - In Wink, this is accomplished by adding an entry to a config file. - </p> - <p class='bcode'> - <xt><web-app</xt> <xa>version</xa>=<xs>"2.3"</xs><xt>></xt> - <xt><servlet></xt> - <xt><servlet-name></xt>WinkService<xt></servlet-name></xt> - <xt><servlet-class></xt>org.apache.wink.server.internal.servlet.RestServlet<xt></servlet-class></xt> - <xt><init-param></xt> - <xt><param-name></xt>applicationConfigLocation<xt></param-name></xt> - <xt><param-value></xt>/WEB-INF/wink.cfg<xt></param-value></xt> - <xt></init-param></xt> - <xt></servlet></xt> - </p> - <p> - Simply include a reference to the provider in the configuration file. - <p class='bcode'> - com.ibm.juno.server.jaxrs.DefaultProvider - </p> - <p> - Properties can be specified on providers through the {@link com.ibm.juno.server.jaxrs.JunoProvider#properties()} annotation.<br> - Properties can also be specified at the method level by using the {@link com.ibm.juno.server.annotation.RestMethod#properties} annotation, like so: - </p> - <p class='bcode'> - <ja>@GET</ja> - <ja>@Produces</ja>(<js>"*/*"</js>) - <ja>@RestMethod</ja>( <jc>/* Override some properties */</jc> - properties={ - <ja>@Property</ja>(name=UonSerializerProperties.<jsf>UON_simpleMode</jsf>, value=<js>"true"</js>) - } - ) - <jk>public</jk> Message getMessage() { - <jk>return</jk> message; - } - </p> - <h6 class='topic'>Limitations</h6> - <p> - In general, the Juno REST API is considerably more flexible than the JAX-RS API, since you can specify and override - serializers, parsers, properties, filters, converters, guards, etc... at both the class and method levels.<br> - Therefore, the JAX-RS API has the following limitations that the Juno Server API does not: - </p> - <ul> - <li>The ability to specify different media type providers at the class and method levels.<br> - For example, you may want to use <code>JsonSerializer</code> with one set of properties on - one class, and another instance with different properties on another class.<br> - There is currently no way to define this at the class level.<br> - You can override properties at the method level, but this can be cumbersome since it would have to be - done for all methods in the resource.<br><br> - <li>The Juno Server API allows you to manipulate properties programatically through the {@link com.ibm.juno.server.RestResponse#setProperty(String,Object)} - method, and through the {@link com.ibm.juno.server.annotation.Properties} annotation.<br> - There is no equivalent in JAX-RS. - </ul> - </div> - - <!-- ======================================================================================================== --> - <a id="BaseProvider"></a> - <h4 class='topic' onclick='toggle(this)'>4.1.4 - Using JAX-RS BaseProvider with annotations</h4> - <div class='topic'> - <p> - To provide support for only JSON media types, you can define your own provider class, like so: - </p> - <p class='bcode'> - <ja>@Provider</ja> - <ja>@Produces</ja>({ - <js>"application/x-www-form-urlencoded"</js>, <jc>// UrlEncodingSerializer</jc> - }) - <ja>@Consumes</ja>({ - <js>"application/x-www-form-urlencoded"</js> <jc>// UrlEncodingParser</jc> - }) - <ja>@JunoProvider</ja>( - serializers={ - UrlEncodingSerializer.<jk>class</jk> - }, - parsers={ - UrlEncodingParser.<jk>class</jk>, - } - properties={ - <ja>@Property</ja>(name=UonSerializerProperties.<jsf>UON_simpleMode</jsf>, value=<js>"true"</js>) - } - ) - <jk>public final class</jk> MyUrlEncodingProvider <jk>extends</jk> BaseProvider {} - </p> - <p> - Then register it with Wink the same way as <code>DefaultProvider</code>. - </p> - </div> - - </div> - - <!-- ======================================================================================================== --> - <a id="RestClientSupport"></a> - <h3 class='topic' onclick='toggle(this)'>4.2 - REST client support</h3> - <div class='topic'> - <p> - The {@link com.ibm.juno.client.RestClient} class provides an easy-to-use REST client interface with - pluggable media type handling using any of the Juno serializers and parsers.<br> - Defining a client to support the URL-encoding media type on HTTP requests and responses can be done in one line of code: - </p> - <p class='bcode'> - <jc>// Create a client to handle URL-encoded requests and responses.</jc> - RestClient client = <jk>new</jk> RestClient(UrlEncodingSerializer.<jk>class</jk>, UrlEncodingParser.<jk>class</jk>); - </p> - <p> - The client handles all content negotiation based on the registered serializers and parsers. - </p> - <p> - The following code is pulled from the main method of the <code>ClientTest</code> class in the sample web application, and - is run against the <code>AddressBookResource</code> class running within the sample app.<br> - It shows how the client can be used to interact with the REST API while completely hiding the negotiated content type and working with nothing more than beans. - </p> - <h6 class='figure'>Example</h6> - <p class='bcode'> - String root = <js>"http://localhost:9080/sample/addressBook"</js>; - - <jc>// Get the current contents of the address book</jc> - AddressBook ab = client.doGet(root).getResponse(AddressBook.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"Number of entries = "</js> + ab.size()); - - <jc>// Delete the existing entries</jc> - <jk>for</jk> (Person p : ab) { - String r = client.doDelete(p.<jf>uri</jf>).getResponse(String.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"Deleted person "</js> + p.<jf>name</jf> + <js>", response = "</js> + r); - } - - <jc>// Make sure they're gone</jc> - ab = client.doGet(root).getResponse(AddressBook.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"Number of entries = "</js> + ab.size()); - - <jc>// Add 1st person again</jc> - CreatePerson cp = <jk>new</jk> CreatePerson( - <js>"Barack Obama"</js>, - <jsm>toCalendar</jsm>(<js>"Aug 4, 1961"</js>), - <jk>new</jk> CreateAddress(<js>"1600 Pennsylvania Ave"</js>, <js>"Washington"</js>, <js>"DC"</js>, 20500, <jk>true</jk>), - <jk>new</jk> CreateAddress(<js>"5046 S Greenwood Ave"</js>, <js>"Chicago"</js>, <js>"IL"</js>, 60615, <jk>false</jk>) - ); - Person p = client.doPost(root + <js>"/people"</js>, cp).getResponse(Person.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"Created person "</js> + p.<jf>name</jf> + <js>", uri = "</js> + p.<jf>uri</jf>); - - <jc>// Add 2nd person again, but add addresses separately</jc> - cp = <jk>new</jk> CreatePerson( - <js>"George Walker Bush"</js>, - toCalendar(<js>"Jul 6, 1946"</js>) - ); - p = client.doPost(root + <js>"/people"</js>, cp).getResponse(Person.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"Created person "</js> + p.<jf>name</jf> + <js>", uri = "</js> + p.<jf>uri</jf>); - - <jc>// Add addresses to 2nd person</jc> - CreateAddress ca = <jk>new</jk> CreateAddress(<js>"43 Prairie Chapel Rd"</js>, <js>"Crawford"</js>, <js>"TX"</js>, 76638, <jk>true</jk>); - Address a = client.doPost(p.<jf>uri</jf> + <js>"/addresses"</js>, ca).getResponse(Address.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"Created address "</js> + a.<jf>uri</jf>); - - ca = <jk>new</jk> CreateAddress(<js>"1600 Pennsylvania Ave"</js>, <js>"Washington"</js>, <js>"DC"</js>, 20500, <jk>false</jk>); - a = client.doPost(p.<jf>uri</jf> + "/addresses"</js>, ca).getResponse(Address.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"Created address "</js> + a.<jf>uri</jf>); - - <jc>// Find 1st person, and change name</jc> - Person[] pp = client.doGet(root + <js>"?q={name:\"'Barack+Obama'\"}"</js>).getResponse(Person[].<jk>class</jk>); - String r = client.doPut(pp[0].<jf>uri</jf> + <js>"/name"</js>, <js>"Barack Hussein Obama"</js>).getResponse(String.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"Changed name, response = "</js> + r); - p = client.doGet(pp[0].<jf>uri</jf>).getResponse(Person.<jk>class</jk>); - System.<jsm>out</jsm>.println(<js>"New name = "</js> + p.<jf>name</jf>); - </p> - <h6 class='figure'>Results</h6> - <p class='bcode'> - Number of entries = 2 - Deleted person Barack Obama, response = DELETE successful - Deleted person George Walker Bush, response = DELETE successful - Number of entries = 0 - Created person Barack Obama, uri = http://localhost:9080/sample/addressBook/people/3 - Created person George Walker Bush, uri = http://localhost:9080/sample/addressBook/people/4 - Created address http://localhost:9080/sample/addressBook/addresses/7 - Created address http://localhost:9080/sample/addressBook/addresses/8 - Changed name, response = PUT successful - New name = Barack Hussein Obama - </p> - </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/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/Args.class ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/Args.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/Args.class deleted file mode 100755 index f781f70..0000000 Binary files a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/Args.class and /dev/null differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/Args.java ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/Args.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/Args.java deleted file mode 100755 index 9d64bb1..0000000 --- a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/Args.java +++ /dev/null @@ -1,240 +0,0 @@ -/******************************************************************************* - * Licensed Materials - Property of IBM - * © Copyright IBM Corporation 2014, 2015. All Rights Reserved. - * - * The source code for this program is not published or otherwise - * divested of its trade secrets, irrespective of what has been - * deposited with the U.S. Copyright Office. - *******************************************************************************/ -package com.ibm.juno.core.utils; - -import java.util.*; - -import com.ibm.juno.core.*; - -/** - * Utility class to make it easier to work with command-line arguments pass in through a <code>main(String[] args)</code> method. - * <p> - * Used to parse command-line arguments of the form <js>"[zero or more main arguments] [zero or more optional arguments]"</js>. - * <p> - * The format of a main argument is a token that does not start with <js>'-'</js>. - * <p> - * The format of an optional argument is <js>"-argName [zero or more tokens]"</js>. - * <p> - * <h6 class='topic'>Command-line examples</h6> - * <ul> - * <li><code>java com.sample.MyClass mainArg1</code> - * <li><code>java com.sample.MyClass mainArg1 mainArg2</code> - * <li><code>java com.sample.MyClass mainArg1 -optArg1</code> - * <li><code>java com.sample.MyClass -optArg1</code> - * <li><code>java com.sample.MyClass mainArg1 -optArg1 optArg1Val</code> - * <li><code>java com.sample.MyClass mainArg1 -optArg1 optArg1Val1 optArg1Val2</code> - * <li><code>java com.sample.MyClass mainArg1 -optArg1 optArg1Val1 -optArg1 optArg1Val2</code> - * </ul> - * - * <h6 class='topic'>Code examples</h6> - * <p class='bcode'> - * - * <jc>// Main method with arguments</jc> - * <jk>public static void</jk> <jsm>main</jsm>(String[] args) { - * - * <jc>// Wrap in Args</jc> - * Args a = new Args(args); - * - * <jc>// One main argument</jc> - * <jc>// a1</jc> - * String a1 = a.getArg(0); <jc>// "a1"</jc> - * String a2 = a.getArg(1); <jc>// null</jc> - * - * <jc>// Two main arguments</jc> - * <jc>// a1 a2</jc> - * String a1 = a.getArg(0); <jc>// "a1"</jc> - * String a2 = a.getArg(1); <jc>// "a2"</jc> - * - * <jc>// One main argument and one optional argument with no value</jc> - * <jc>// a1 -a2</jc> - * String a1 = a.getArg(0); - * <jk>boolean</jk> hasA2 = a.hasArg(<js>"a2"</js>); <jc>// true</jc> - * <jk>boolean</jk> hasA3 = a.hasArg(<js>"a3"</js>); <jc>// false</jc> - * - * <jc>// One main argument and one optional argument with one value</jc> - * <jc>// a1 -a2 v2</jc> - * String a1 = a.getArg(0); - * String a2 = a.getArg(<js>"a2"</js>); <jc>// "v2"</jc> - * String a3 = a.getArg(<js>"a3"</js>); <jc>// null</jc> - * - * <jc>// One main argument and one optional argument with two values</jc> - * <jc>// a1 -a2 v2a v2b</jc> - * String a1 = a.getArg(0); - * List<String> a2 = a.getArgs(<js>"a2"</js>); <jc>// Contains ["v2a","v2b"]</jc> - * List<String> a3 = a.getArgs(<js>"a3"</js>); <jc>// Empty list</jc> - * - * <jc>// Same as previous, except specify optional argument name multiple times</jc> - * <jc>// a1 -a2 v2a -a2 v2b</jc> - * String a1 = a.getArg(0); - * List<String> a2 = a.getArgs(<js>"a2"</js>); <jc>// Contains ["v2a","v2b"]</jc> - * } - * </p> - * <p> - * Main arguments are available through numeric string keys (e.g. <js>"0"</js>, <js>"1"</js>, ...). - * So you could use the {@link ObjectMap} API to convert main arguments directly to POJOs, such as an <code>Enum</code> - * <p class='bcode'> - * <jc>// Get 1st main argument as an Enum</jc> - * MyEnum e = a.get(MyEnum.<jk>class</jk>, <js>"0"</js>); - * - * <jc>// Get 1st main argument as an integer</jc> - * int i = a.get(<jk>int</jk>.<jk>class</jk>, <js>"0"</js>); - * </p> - * <p> - * Equivalent operations are available on optional arguments through the {@link #getArg(Class, String)} method. - * - * @author jbognar - */ -public final class Args extends ObjectMap { - - private static final long serialVersionUID = 1L; - - /** - * Constructor. - * - * @param args Arguments passed in through a <code>main(String[] args)</code> method. - */ - public Args(String[] args) { - List<String> argList = new LinkedList<String>(Arrays.asList(args)); - - // Capture the main arguments. - Integer i = 0; - while (! argList.isEmpty()) { - String s = argList.get(0); - if (StringUtils.startsWith(s,'-')) - break; - put(i.toString(), argList.remove(0)); - i++; - } - - // Capture the mapped arguments. - String key = null; - while (! argList.isEmpty()) { - String s = argList.remove(0); - if (StringUtils.startsWith(s, '-')) { - key = s.substring(1); - if (key.matches("\\d*")) - throw new RuntimeException("Invalid optional key name '"+key+"'"); - if (! containsKey(key)) - put(key, new ObjectList()); - } else { - ((ObjectList)get(key)).add(s); - } - } - } - - /** - * Returns main argument at the specified index, or <jk>null</jk> if the index is out of range. - * <p> - * Can be used in conjuction with {@link #hasArg(int)} to check for existence of arg. - * <p class='bcode'> - * <jc>// Check for no arguments</jc> - * <jk>if</jk> (! args.hasArg(0)) - * printUsageAndExit(); - * - * <jc>// Get the first argument</jc> - * String firstArg = args.getArg(0); - * </p> - * <p> - * Since main arguments are stored as numeric keys, this method is essentially equivalent to... - * <p class='bcode'> - * <jc>// Check for no arguments</jc> - * <jk>if</jk> (! args.containsKey(<js>"0"</js>)) - * printUsageAndExit(); - * - * <jc>// Get the first argument</jc> - * String firstArg = args.getString("0"); - * </p> - * - * @param i The index position of the main argument (zero-indexed). - * @return The main argument value, or <js>""</js> if argument doesn't exist at that position. - */ - public String getArg(int i) { - return getString(Integer.toString(i)); - } - - /** - * Returns <jk>true</jk> if argument exists at specified index. - * - * @param i The zero-indexed position of the argument. - * @return <jk>true</jk> if argument exists at specified index. - */ - public boolean hasArg(int i) { - return containsKey(Integer.toString(i)); - } - - /** - * Returns the optional argument value, or blank if the optional argument was not specified. - * <p> - * If the optional arg has multiple values, returns values as a comma-delimited list. - * - * @param name The optional argument name. - * @return The optional argument value, or blank if the optional argument was not specified. - */ - public String getArg(String name) { - ObjectList l = (ObjectList)get(name); - if (l == null || l.size() == 0) - return null; - if (l.size() == 1) - return l.get(0).toString(); - return Arrays.toString(l.toArray()).replaceAll("[\\[\\]]", ""); - } - - /** - * Returns the optional argument value converted to the specified object type. - * <p> - * If the optional arg has multiple values, returns only the first converted value. - * - * <dl> - * <dt>Example:</dt> - * <dd> - * <p class='bcode'> - * <jc>// Command: java com.sample.MyClass -verbose true -debug 5</jc> - * <jk>boolean</jk> b = args.getArg(<jk>boolean</jk>.<jk>class</jk>, <js>"verbose"</js>); - * <jk>int</jk> i = args.getArg(<jk>int</jk>.<jk>class</jk>, <js>"debug"</js>); - * </p> - * </dd> - * </dl> - * - * @param c The class type to convert the value to. - * @param <T> The class type to convert the value to. - * @param name The optional argument name. - * @return The optional argument value, or blank if the optional argument was not specified. - */ - public <T> T getArg(Class<T> c, String name) { - ObjectList l = (ObjectList)get(name); - if (l == null || l.size() == 0) - return null; - return l.get(c, 0); - } - - /** - * Returns the optional argument values as a list of strings. - * - * <dl> - * <dt>Example:</dt> - * <dd> - * <p class='bcode'> - * <jc>// Command: java com.sample.MyClass -extraArgs foo bar baz</jc> - * List<String> l1 = args.getArgs(<js>"extraArgs"</js>); <jc>// ['foo','bar','baz']</jc> - * List<String> l2 = args.getArgs(<js>"nonExistentArgs"</js>); <jc>// An empty list</jc> - * </p> - * </dd> - * </dl> - * - * @param name The optional argument name. - * @return The optional argument values, or an empty list if the optional argument was not specified. - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - public List<String> getArgs(String name) { - List l = (ObjectList)get(name); - if (l == null) - return Collections.emptyList(); - return l; - } -} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$1$1.class ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$1$1.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$1$1.class deleted file mode 100755 index 157067c..0000000 Binary files a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$1$1.class and /dev/null differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$1.class ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$1.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$1.class deleted file mode 100755 index 3b7e54a..0000000 Binary files a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$1.class and /dev/null differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$2.class ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$2.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$2.class deleted file mode 100755 index 7ab64ff..0000000 Binary files a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils$2.class and /dev/null differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils.class ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils.class deleted file mode 100755 index 64841df..0000000 Binary files a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils.class and /dev/null differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils.java ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils.java deleted file mode 100755 index 22923df..0000000 --- a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ArrayUtils.java +++ /dev/null @@ -1,273 +0,0 @@ -/******************************************************************************* - * Licensed Materials - Property of IBM - * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved. - * - * The source code for this program is not published or otherwise - * divested of its trade secrets, irrespective of what has been - * deposited with the U.S. Copyright Office. - *******************************************************************************/ -package com.ibm.juno.core.utils; - -import static com.ibm.juno.core.utils.ThrowableUtils.*; - -import java.lang.reflect.*; -import java.util.*; - -/** - * Quick and dirty utilities for working with arrays. - * - * @author James Bognar ([email protected]) - */ -public final class ArrayUtils { - - /** - * Appends one or more elements to an array. - * - * @param <T> The element type. - * @param array The array to append to. - * @param newElements The new elements to append to the array. - * @return A new array with the specified elements appended. - */ - @SuppressWarnings("unchecked") - public static <T> T[] append(T[] array, T...newElements) { - assertNotNull(array, "Array cannot be null."); - if (newElements.length == 0) - return array; - T[] a = (T[])Array.newInstance(array.getClass().getComponentType(), array.length + newElements.length); - for (int i = 0; i < array.length; i++) - a[i] = array[i]; - for (int i = 0; i < newElements.length; i++) - a[i+array.length] = newElements[i]; - return a; - } - - /** - * Appends one or more elements to an array. - * - * @param <T> The element type. - * @param array The array to append to. - * @param newElements The new elements to append to the array. - * @return A new array with the specified elements appended. - */ - @SuppressWarnings("unchecked") - public static <T> T[] append(T[] array, Collection<T> newElements) { - assertFieldNotNull(array, "array"); - if (newElements.size() == 0) - return array; - T[] a = (T[])Array.newInstance(array.getClass().getComponentType(), array.length + newElements.size()); - for (int i = 0; i < array.length; i++) - a[i] = array[i]; - int l = array.length; - for (T t : newElements) - a[l++] = t; - return a; - } - - /** - * Combine an arbitrary number of arrays into a single array. - * - * @param arrays Collection of arrays to combine. - * @return A new combined array, or <jk>null</jk> if all arrays are <jk>null</jk>. - */ - @SuppressWarnings("unchecked") - public static <T> T[] combine(T[]...arrays) { - assertFieldNotNull(arrays, "arrays"); - int l = 0; - T[] a1 = null; - for (T[] a : arrays) { - if (a1 == null && a != null) - a1 = a; - l += (a == null ? 0 : a.length); - } - if (a1 == null) - return null; - T[] a = (T[])Array.newInstance(a1.getClass().getComponentType(), l); - int i = 0; - for (T[] aa : arrays) - if (aa != null) - for (T t : aa) - a[i++] = t; - return a; - } - - /** - * Creates a new array with reversed entries. - * - * @param <T> The class type of the array. - * @param array The array to reverse. - * @return A new array with reversed entries, or <jk>null</jk> if the array was <jk>null</jk>. - */ - @SuppressWarnings("unchecked") - public static <T> T[] reverse(T[] array) { - assertFieldNotNull(array, "array"); - Class<T> c = (Class<T>)array.getClass().getComponentType(); - T[] a2 = (T[])Array.newInstance(c, array.length); - for (int i = 0; i < array.length; i++) - a2[a2.length-i-1] = array[i]; - return a2; - } - - /** - * Converts the specified array to a <code>Set</code>. - * <p> - * The order of the entries in the set are the same as the array. - * - * @param <T> The entry type of the array. - * @param array The array being wrapped in a <code>Set</code> interface. - * @return The new set. - */ - public static <T> Set<T> asSet(final T[] array) { - assertFieldNotNull(array, "array"); - return new AbstractSet<T>() { - - @Override /* Set */ - public Iterator<T> iterator() { - return new Iterator<T>() { - int i = 0; - - @Override /* Iterator */ - public boolean hasNext() { - return i < array.length; - } - - @Override /* Iterator */ - public T next() { - if (i >= array.length) - throw new NoSuchElementException(); - T t = array[i]; - i++; - return t; - } - - @Override /* Iterator */ - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - @Override /* Set */ - public int size() { - return array.length; - } - }; - } - - /** - * Returns an iterator against an array. - * This works with any array type (e.g. <code>String[]</code>, <code>Object[]</code>, <code><jk>int</jk>[]</code>, etc...). - * - * @param array The array to create an iterator over. - * @return An iterator over the specified array. - */ - public static Iterator<Object> iterator(final Object array) { - return new Iterator<Object>() { - int i = 0; - int length = array == null ? 0 : Array.getLength(array); - - @Override /* Iterator */ - public boolean hasNext() { - return i < length; - } - - @Override /* Iterator */ - public Object next() { - if (i >= length) - throw new NoSuchElementException(); - return Array.get(array, i++); - } - - @Override /* Iterator */ - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - /** - * Converts the specified collection to an array. - * Works on both object and primitive arrays. - * - * @param c The collection to convert to an array. - * @param componentType The component type of the collection. - * @return A new array. - */ - public static <T> Object toArray(Collection<T> c, Class<T> componentType) { - Object a = Array.newInstance(componentType, c.size()); - Iterator<T> it = c.iterator(); - int i = 0; - while (it.hasNext()) - Array.set(a, i++, it.next()); - return a; - } - - /** - * Copies the specified array into the specified list. - * Works on both object and primitive arrays. - * - * @param array The array to copy into a list. - * @param list The list to copy the values into. - */ - @SuppressWarnings({"unchecked","rawtypes"}) - public static void copyToList(Object array, List list) { - if (array != null) { - int length = Array.getLength(array); - for (int i = 0; i < length; i++) - list.add(Array.get(array, i)); - } - } - - /** - * Returns <jk>true</jk> if the specified array contains the specified element - * using the {@link Object#equals(Object)} method. - * - * @param element The element to check for. - * @param array The array to check. - * @return <jk>true</jk> if the specified array contains the specified element, - * <jk>false</jk> if the array or element is <jk>null</jk>. - */ - public static <T> boolean contains(T element, T[] array) { - return indexOf(element, array) != -1; - } - - /** - * Returns the index position of the element in the specified array - * using the {@link Object#equals(Object)} method. - * - * @param element The element to check for. - * @param array The array to check. - * @return The index position of the element in the specified array, or - * <code>-1</code> if the array doesn't contain the element, or the array or element is <jk>null</jk>. - */ - public static <T> int indexOf(T element, T[] array) { - if (element == null) - return -1; - if (array == null) - return -1; - for (int i = 0; i < array.length; i++) - if (element.equals(array[i])) - return i; - return -1; - } - - /** - * Converts a primitive wrapper array (e.g. <code>Integer[]</code>) to a primitive array (e.g. <code><jk>int</jk>[]</code>). - * - * @param o The array to convert. Must be a primitive wrapper array. - * @return A new array. - * @throws IllegalArgumentException If object is not a wrapper object array. - */ - public static Object toPrimitiveArray(Object o) { - Class<?> c = o.getClass(); - if (! c.isArray()) - throw new IllegalArgumentException("Cannot pass non-array objects to toPrimitiveArray()"); - int l = Array.getLength(o); - Class<?> tc = ClassUtils.getPrimitiveForWrapper(c.getComponentType()); - if (tc == null) - throw new IllegalArgumentException("Array type is not a primitive wrapper array."); - Object a = Array.newInstance(tc, l); - for (int i = 0; i < l; i++) - Array.set(a, i, Array.get(o, i)); - return a; - } -} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/30947fd7/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/AsciiSet.class ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/AsciiSet.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/AsciiSet.class deleted file mode 100755 index b6b5b3a..0000000 Binary files a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/AsciiSet.class and /dev/null differ
