You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/01/09 03:32:48 UTC
[1/2] juneau git commit: Javadoc updates.
Repository: juneau
Updated Branches:
refs/heads/master cea2a1d74 -> 474a143ce
http://git-wip-us.apache.org/repos/asf/juneau/blob/474a143c/juneau-doc/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index 64797e8..375a2ef 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -92,9 +92,21 @@
<li><p><a class='doclink' href='#juneau-marshall.Transforms'>Transforms</a></p>
<ol>
<li><p><a class='doclink' href='#juneau-marshall.PojoSwaps'>PojoSwaps</a></p>
- <li><p><a class='doclink' href='#juneau-marshall.SwapAnnotation'>@Swap annotation</a></p>
- <li><p><a class='doclink' href='#juneau-marshall.SwapMethods'>Swap methods</a></p>
- <li><p><a class='doclink' href='#juneau-marshall.BeanFilters'>BeanFilters and @Bean annotations</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.PerMediaTypePojoSwaps'>Per-media-type PojoSwaps</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.OneWayPojoSwaps'>One-way PojoSwaps</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SwapAnnotation'>@Swap Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SwapMethods'>Swap Methods</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SurrogateClasses'>Surrogate Classes</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanAnnotation'>@Bean Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanPropertyAnnotation'>@BeanProperty Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanConstructorAnnotation'>@BeanConstructor Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanIgnoreAnnotation'>@BeanIgnore Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.NamePropertyAnnotation'>@NameProperty Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.ParentPropertyAnnotation'>@ParentProperty Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.URIAnnotation'>@URI Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanFilters'>BeanFilters</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.StopClasses'>Stop Classes</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SerializingToObjectMaps'>Serializing to ObjectMaps</a></p>
<li><p><a class='doclink' href='#juneau-marshall.SerializingReadersAndInputStreams'>Serializing Readers and InputStreams</a></p>
</ol>
<li><p><a class='doclink' href='#juneau-marshall.BeanDictionaries'>Bean Name and Dictionaries</a></p>
@@ -971,22 +983,33 @@
<h4 class='topic' onclick='toggle(this)'>2.1.6 - Transforms</h4>
<div class='topic'>
<p>
- By default, the Juneau framework can serialize and parse a wide variety of POJOs out-of-the-box.
- However, two special classes are provided tailor how certain Java objects are handled by the framework.
- These classes are:
+ By default, the Juneau framework can serialize and parse a wide variety of POJOs out-of-the-box.
+ <br>However, two special classes are provided tailor how certain Java objects are handled by the framework.
+ <br>These classes are:
</p>
- <ul class='doctree'>
- <li class='jc'>
- {@link org.apache.juneau.transform.PojoSwap}
- - Tailor how specific non-bean classes are handled by the framework.
- <li class='jc'>
- {@link org.apache.juneau.transform.BeanFilter}
- - Tailor how specific bean classes are handled by the framework.
+ <ul>
+ <li class='jc'>{@link org.apache.juneau.transform.BeanFilter} - Transforms that alter the way beans are handled.
+ <li class='jac'>{@link org.apache.juneau.transform.PojoSwap} - Transforms that swap non-serializable POJOs with
+ serializable POJOs during serialization (and optionally vis-versa during parsing).
+ <ol>
+ <li class='jc'>{@link org.apache.juneau.transform.StringSwap} - Convenience subclass for swaps that convert
+ objects to strings.
+ <li class='jc'>{@link org.apache.juneau.transform.MapSwap} - Convenience subclass for swaps that convert
+ objects to maps.
+ </ol>
+ </li>
</ul>
<p>
- Annotations are also provided that allow you to use transformations directly on class definitions:
+ Transforms are added to serializers and parsers (and REST clients) using the following configuration properties:
+ </p>
+ <ul>
+ <li class='jm'>{@link org.apache.juneau.BeanContext#BEAN_beanFilters}
+ <li class='jm'>{@link org.apache.juneau.BeanContext#BEAN_pojoSwaps}
+ </ul>
+ <p>
+ Annotations are also provided for specifying transforms directly on classes and methods:
</p>
- <ul class='doctree'>
+ <ul>
<li class='ja'>
{@link org.apache.juneau.annotation.Swap @Swap}
- Used to tailor how non-bean POJOs get interpreted by the framework.
@@ -1022,8 +1045,7 @@
They allow the serializers and parsers to handle Java objects that wouldn't normally be serializable.
</p>
<p>
- Swaps are very easy to understand.
- Simply put, they can be thought of as 'object swappers' that swap in serializable objects for
+ Swaps are, simply put, 'object swappers' that swap in serializable objects for
non-serializable ones during serialization, and vis-versa during parsing.
</p>
<p>
@@ -1050,12 +1072,8 @@
<jd>/** Converts an ISO8601 string to a Date object. */</jd>
<ja>@Override</ja>
- <jk>public</jk> Date unswap(BeanSession session, String o, ClassMeta hint) <jk>throws</jk> ParseException {
- <jk>try</jk> {
- <jk>return</jk> <jf>format</jf>.parse(o);
- } <jk>catch</jk> (java.text.ParseException e) {
- <jk>throw new</jk> ParseException(e);
- }
+ <jk>public</jk> Date unswap(BeanSession session, String o, ClassMeta hint) <jk>throws</jk> Exception {
+ <jk>return</jk> <jf>format</jf>.parse(o);
}
}
</p>
@@ -1069,14 +1087,82 @@
}
<jc>// Create a new JSON serializer, associate our date swap with it, and serialize a sample bean.</jc>
- Serializer serializer = JsonSerializer.<jsm>create</jsm>().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
- String json = serializer.serialize(<jk>new</jk> MyBean()); <jc>// == "{date:'2012-03-03T04:05:06-0500'}"</jc>
+ WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
+ String json = s.serialize(<jk>new</jk> MyBean()); <jc>// == "{date:'2012-03-03T04:05:06-0500'}"</jc>
<jc>// Create a JSON parser, associate our date swap with it, and reconstruct our bean (including the date).</jc>
- ReaderParser parser = JsonParser.<jsm>create</jsm>().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
- MyBean bean = parser.parse(json, MyBean.<jk>class</jk>);
+ ReaderParser p = JsonParser.<jsm>create</jsm>().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
+ MyBean bean = p.parse(json, MyBean.<jk>class</jk>);
<jk>int</jk> day = bean.<jf>date</jf>.getDay(); <jc>// == 3</jc>
</p>
+ <p>
+ The {@link org.apache.juneau.BeanMap#get(Object)} and {@link org.apache.juneau.BeanMap#put(String,Object)}
+ methods will automatically convert to swapped values as the following example shows:
+ </p>
+ <p class='bcode'>
+ <jc>// Create a new bean context and add our swap.</jc>
+ BeanContext bc = BeanContext.<jsm>create</jsm>().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
+
+ <jc>// Create a new bean.</jc>
+ MyBean myBean = <jk>new</jk> MyBean();
+
+ <jc>// Wrap it in a bean map.</jc>
+ BeanMap<Bean> beanMap = bc.forBean(myBean);
+
+ <jc>// Use the get() method to get the date field as an ISO8601 string.</jc>
+ String date = (String)beanMap.get(<js>"date"</js>); <jc>// == "2012-03-03T04:05:06-0500"</jc>
+
+ <jc>// Use the put() method to set the date field to an ISO8601 string.</jc>
+ beanMap.put(<js>"date"</js>, <js>"2013-01-01T12:30:00-0500"</js>); <jc>// Set it to a new value.</jc>
+
+ <jc>// Verify that the date changed on the original bean.</jc>
+ <jk>int</jk> year = myBean.<jf>date</jf>.getYear(); <jc>// == 113</jc>
+ </p>
+ <p>
+ Another example of a <code>PojoSwap</code> is one that converts <code><jk>byte</jk>[]</code> arrays to '
+ BASE64-encoded strings:
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> ByteArrayBase64Swap <jk>extends</jk> StringSwap<<jk>byte</jk>[]> {
+
+ <ja>@Override</ja>
+ <jk>public</jk> String swap(<jk>byte</jk>[] b) <jk>throws</jk> Exception {
+ ByteArrayOutputStream baos = <jk>new</jk> ByteArrayOutputStream();
+ OutputStream b64os = MimeUtility.encode(baos, <js>"base64"</js>);
+ b64os.write(b);
+ b64os.close();
+ <jk>return new</jk> String(baos.toByteArray());
+ }
+
+ <ja>@Override</ja>
+ <jk>public byte</jk>[] unswap(String s, ClassMeta<?> hint) <jk>throws</jk> Exception {
+ <jk>byte</jk>[] b = s.getBytes();
+ ByteArrayInputStream bais = <jk>new</jk> ByteArrayInputStream(b);
+ InputStream b64is = MimeUtility.decode(bais, <js>"base64"</js>);
+ <jk>byte</jk>[] tmp = <jk>new byte</jk>[b.length];
+ <jk>int</jk> n = b64is.read(tmp);
+ <jk>byte</jk>[] res = <jk>new byte</jk>[n];
+ System.<jsm>arraycopy</jsm>(tmp, 0, res, 0, n);
+ <jk>return</jk> res;
+ }
+ }
+ </p>
+ <p>
+ The following example shows the BASE64 swap in use:
+ </p>
+ <p class='bcode'>
+ <jc>// Create a JSON serializer and register the BASE64 encoding swap with it.</jc>
+ WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
+ ReaderParser p = JsonParser.<jsm>create</jsm>().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
+
+ <jk>byte</jk>[] bytes = {1,2,3};
+ String json = s.serialize(bytes); <jc>// Produces "'AQID'"</jc>
+ bytes = p.parse(json, <jk>byte</jk>[].<jk>class</jk>); <jc>// Reproduces {1,2,3}</jc>
+
+ <jk>byte</jk>[][] bytes2d = {{1,2,3},{4,5,6},<jk>null</jk>};
+ json = s.serialize(bytes2d); <jc>// Produces "['AQID','BAUG',null]"</jc>
+ bytes2d = p.parse(json, <jk>byte</jk>[][].<jk>class</jk>); <jc>// Reproduces {{1,2,3},{4,5,6},null}</jc>
+ </p>
<p>
Several <code>PojoSwaps</code> are already provided for common Java objects:
</p>
@@ -1106,14 +1192,25 @@
{@link org.apache.juneau.transforms.DateSwap} transforms provide a large number of customized swaps to
ISO, RFC, or localized strings.
</p>
-
+
+ <ul class='doctree'>
+ <li class='info'>
+ The 'swapped' class type must be a serializable type.
+ <br>See the definition for Category 4 objects in <a class='doclink' href='#juneau-marshall.PojoCategories'>POJO Categories</a>.
+ </ul>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.PerMediaTypePojoSwaps"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.2 - Per-media-type PojoSwaps</h4>
+ <div class='topic'>
<p>
Swaps can also be defined per-media-type.
- The {@link org.apache.juneau.transform.PojoSwap#forMediaTypes()} method can be overridden to
+ <br>The {@link org.apache.juneau.transform.PojoSwap#forMediaTypes()} method can be overridden to
provide a set of media types that the swap is invoked on.
- It's also possible to define multiple swaps against the same POJO as long as they're differentiated
+ <br>It's also possible to define multiple swaps against the same POJO as long as they're differentiated
by media type.
- When multiple swaps are defined, the best-match media type is used.
+ <br>When multiple swaps are defined, the best-match media type is used.
</p>
<p>
In the following example, we define 3 swaps against the same POJO.
@@ -1125,33 +1222,33 @@
<jk>public static class</jk> MyPojo {}
<jk>public static class</jk> MyJsonSwap <jk>extends</jk> PojoSwap<MyPojo,String> {
-
+ <ja>@Override</ja>
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"*/json"</js>);
}
-
+ <ja>@Override</ja>
<jk>public</jk> String swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
<jk>return</jk> <js>"It's JSON!"</js>;
}
}
<jk>public static class</jk> MyXmlSwap <jk>extends</jk> PojoSwap<MyPojo,String> {
-
+ <ja>@Override</ja>
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"*/xml"</js>);
}
-
+ <ja>@Override</ja>
<jk>public</jk> String swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
<jk>return</jk> <js>"It's XML!"</js>;
}
}
<jk>public static class</jk> MyOtherSwap <jk>extends</jk> PojoSwap<MyPojo,String> {
-
+ <ja>@Override</ja>
<jk>public</jk> MediaType[] forMediaTypes() {
<jk>return</jk> MediaType.<jsm>forStrings</jsm>(<js>"*/*"</js>);
}
-
+ <ja>@Override</ja>
<jk>public</jk> String swap(BeanSession session, MyPojo o) <jk>throws</jk> Exception {
<jk>return</jk> <js>"It's something else!"</js>;
}
@@ -1179,23 +1276,68 @@
}
}
</p>
-
- <ul class='doctree'>
- <li class='info'>
- The 'swapped' class type must be a serializable type.
- <br>See the definition for Category 4 objects in <a class='doclink'
- href='#juneau-marshall.PojoCategories'>POJO Categories</a>.
- </ul>
</div>
<!-- =================================================================================================== -->
+ <a id="juneau-marshall.OneWayPojoSwaps"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.3 - One-way PojoSwaps</h4>
+ <div class='topic'>
+ <p>
+ In the previous sections, we defined two-way swaps, meaning swaps where the original objects could be
+ reconstructing during parsing.
+ <br>However, there are certain kinds of POJOs that we may want to support for serializing, but that are not
+ possible to reconstruct during parsing.
+ <br>For these, we can use one-way object swaps.
+ </p>
+ <p>
+ A one-way POJO swap is simply an object transform that only implements the {@code swap()} method.
+ <br>The {@code unswap()} method is simply left unimplemented.
+ </p>
+ <p>
+ An example of a one-way swaps would be one that allows {@code Iterators} to be serialized as JSON arrays.
+ <br>It can make sense to be able to render {@code Iterators} as arrays, but in general it's not possible to
+ reconstruct an {@code Iterator} during parsing.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> IteratorSwap <jk>extends</jk> PojoSwap<Iterator,List> {
+ <ja>@Override</ja>
+ <jk>public</jk> List swap(Iterator o) {
+ List l = <jk>new</jk> LinkedList();
+ <jk>while</jk> (o.hasNext())
+ l.add(o.next());
+ <jk>return</jk> l;
+ }
+ }
+ </p>
+ <p>
+ Here is an example of our one-way swap being used.
+ <br>Note that trying to parse the original object will cause a {@link org.apache.juneau.parser.ParseException}
+ to be thrown.
+ </p>
+ <p class='bcode'>
+ <jc>// Create a JSON serializer that can serialize Iterators.</jc>
+ WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(IteratorSwap.<jk>class</jk>).build();
+
+ <jc>// Construct an iterator we want to serialize.</jc>
+ Iterator i = <jk>new</jk> ObjectList(1,2,3).iterator();
+
+ <jc>// Serialize our Iterator</jc>
+ String json = s.serialize(i); <jc>// Produces "[1,2,3]"</jc>
+
+ <jc>// Try to parse it.</jc>
+ ReaderParser p = JsonParser.<jsm>create</jsm>().pojoSwaps(IteratorSwap.<jk>class</jk>).build();
+ i = p.parse(s, Iterator.<jk>class</jk>); <jc>// Throws ParseException!!!</jc>
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
<a id="juneau-marshall.SwapAnnotation"></a>
- <h4 class='topic' onclick='toggle(this)'>2.1.6.2 - @Swap annotation</h4>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.4 - @Swap Annotation</h4>
<div class='topic'>
<p>
{@link org.apache.juneau.annotation.Swap @Swap} can be used to associate a swap class using an
annotation.
- This is often cleaner than using the builder <code>pojoSwaps()</code> method since you can keep
+ <br>This is often cleaner than using the builder <code>pojoSwaps()</code> method since you can keep
your swap class near your POJO class.
</p>
<p class='bcode'>
@@ -1213,7 +1355,6 @@
}
}
</p>
-
<p>
Multiple swaps can be associated with a POJO by using the {@link org.apache.juneau.annotation.Swaps @Swaps} annotation:
</p>
@@ -1243,16 +1384,15 @@
}
}
</p>
-
</div>
<!-- ======================================================================================================= -->
<a id="juneau-marshall.SwapMethods"></a>
- <h4 class='topic' onclick='toggle(this)'>2.1.6.3 - Swap methods</h4>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.5 - Swap Methods</h4>
<div class='topic'>
<p>
Various methods can be defined on a class directly to affect how it gets serialized.
- This can often be simpler than using <code>PojoSwaps</code>.
+ <br>This can often be simpler than using <code>PojoSwaps</code>.
</p>
<p>
Objects serialized as <code>Strings</code> can be parsed back into their original objects by
@@ -1303,7 +1443,7 @@
<p>
The <code>BeanSession</code> parameter allows you access to various information about the current
serialization session.
- For example, you could provide customized results based on the media type being produced
+ <br>For example, you could provide customized results based on the media type being produced
({@link org.apache.juneau.BeanSession#getMediaType()}).
</p>
<p>
@@ -1388,40 +1528,572 @@
}
}
</p>
-
- <h6 class='toc'>Additional Information - org.apache.juneau.transform</h6>
- <ol class='toc'>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#PojoSwaps'>PojoSwap Class</a></p>
- </ol>
-
</div>
- <!-- ======================================================================================================= -->
- <a id="juneau-marshall.BeanFilters"></a>
- <h4 class='topic' onclick='toggle(this)'>2.1.6.4 - BeanFilters and @Bean annotations</h4>
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.SurrogateClasses"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.6 - Surrogate Classes</h4>
<div class='topic'>
<p>
- {@link org.apache.juneau.transform.BeanFilter BeanFilters} are used to control aspects of how beans are
- handled during serialization and parsing.
- They allow you to control various aspects of beans, such as...
+ <p>
+ Surrogate classes are very similar in concept to one-way <code>PojoSwaps</code> except they represent a
+ simpler syntax.
</p>
- <ul>
- <li>Which properties to include or exclude.
- <li>Property order.
- <li>Property naming conventions.
- <li>Overriding reading and writing of properties.
- </ul>
<p>
- In practice, however, it's simpler to use the {@link org.apache.juneau.annotation.Bean @Bean} and
- {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotations on your bean classes.
- The annotations are functionally equivalent to the bean filter class.
+ For example, let's say we want to be able to serialize the following class, but it's not serializable for
+ some reason (for example, there are no properties exposed):
+ <p class='bcode'>
+ <jk>public class</jk> MyNonSerializableClass {
+ <jk>protected</jk> String <jf>foo</jf>;
+ }
+ </p>
+ <p>
+ This could be solved with the following <code>PojoSwap</code>.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> MySerializableSurrogate {
+ <jk>public</jk> String <jf>foo</jf>;
+ }
+
+ <jk>public class</jk> MySwap <jk>extends</jk> PojoSwap<MyNonSerializableClass,MySerializableSurrogate> {
+ <ja>@Override</ja>
+ <jk>public</jk> MySerializableSurrogate swap(MyNonSerializableClass o) {
+
+ <jc>// Create some serializable class and manually copy the data into it.</jc>
+ MySerializableSurrogate s = <jk>new</jk> MySerializableSurrogate();
+ s.<jf>foo</jf> = o.<jf>foo</jf>;
+ <jk>return</jk> s;
+ }
+ }
+ </p>
+ <p>
+ However, the same can be accomplished by using a surrogate class that simply contains a constructor with
+ the non-serializable class as an argument:
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> MySerializableSurrogate {
+ <jk>public</jk> String <jf>foo</jf>;
+
+ <jk>public</jk> MySerializableSurrogate(MyNonSerializableClass c) {
+ <jk>this</jk>.<jf>foo</jf> = c.<jf>foo</jf>;
+ }
+ }
+ </p>
+ <p>
+ The surrogate class is registered in the same way as a <code>PojoSwap</code>:
+ </p>
+ <p class='bcode'>
+ <jc>// Create a JSON serializer that can serialize Iterators.</jc>
+ WriterSerializer s = JsonSerializer.<jsm>create</jsm>().pojoSwaps(MySerializableSurrogate.<jk>class</jk>).build();
+ </p>
+ <p>
+ When the serializer encounters the non-serializable class, it will serialize an instance of the surrogate
+ instead.
+ </p>
+ </div>
+
+ <!-- ======================================================================================================= -->
+ <a id="juneau-marshall.BeanAnnotation"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.7 - @Bean Annotation</h4>
+ <div class='topic'>
+ <p>
+ The {@link org.apache.juneau.annotation.Bean @Bean} annotation is used to tailor how beans are
+ interpreted by the framework.
+ </p>
+ <p>
+ Bean property inclusion and ordering on a bean class can be done using the
+ {@link org.apache.juneau.annotation.Bean#properties() @Bean.properties()} annotation.
</p>
<p class='bcode'>
<jc>// Address class with only street/city/state properties (in that order).</jc>
<jc>// All other properties are ignored.</jc>
<ja>@Bean</ja>(properties=<js>"street,city,state"</js>)
- <jk>public class</jk> Address {
- ...
+ <jk>public class</jk> Address { ... }
+ </p>
+ <p>
+ Bean properties can be excluded using the {@link org.apache.juneau.annotation.Bean#excludeProperties() @Bean.excludeProperties()}
+ annotation.
+ </p>
+ <p class='bcode'>
+ <jc>// Address class with only street/city/state properties (in that order).</jc>
+ <jc>// All other properties are ignored.</jc>
+ <ja>@Bean</ja>(excludeProperties=<js>"city,state"</js>})
+ <jk>public class</jk> Address { ... }
+ </p>
+ <p>
+ Bean properties can be sorted alphabetically using {@link org.apache.juneau.annotation.Bean#sort() @Bean.sort()}
+ </p>
+ <p class='bcode'>
+ <jc>// Address class with only street/city/state properties (in that order).</jc>
+ <jc>// All other properties are ignored.</jc>
+ <ja>@Bean</ja>(sort=<jk>true</jk>)
+ <jk>public class</jk> MyBean { ... }
+ </p>
+ <p>
+ The {@link org.apache.juneau.annotation.Bean#propertyNamer() @Bean.propertyNamer()} annotation
+ is used to provide customized naming of properties.
+ </p>
+ <p>
+ Property namers are used to transform bean property names from standard form to some other form.
+ <br>For example, the {@link org.apache.juneau.PropertyNamerDLC} will convert property names to
+ dashed-lowercase, and these will be used as attribute names in JSON and element names in XML.
+ </p>
+ <p>
+ <p class='bcode'>
+ <jc>// Define a class with dashed-lowercase property names.</jc>
+ <ja>@Bean</ja>(propertyNamer=PropertyNamerDashedLC.<jk>class</jk>)
+ <jk>public class</jk> MyBean { ... }
+ </p>
+ <p>
+ The {@link org.apache.juneau.annotation.Bean#interfaceClass @Bean.interfaceClass()} annotation is used
+ to limit properties on beans to specific interface classes.
+ <br>When specified, only the list of properties defined on the interface class will be used during
+ serialization.
+ <br>Additional properties on subclasses will be ignored.
+ </p>
+ <p class='bcode'>
+ <jc>// Parent class</jc>
+ <ja>@Bean</ja>(interfaceClass=A.<jk>class</jk>)
+ <jk>public abstract class</jk> A {
+ <jk>public</jk> String <jf>f0</jf> = <js>"f0"</js>;
+ }
+
+ <jc>// Sub class</jc>
+ <jk>public class</jk> A1 <jk>extends</jk> A {
+ <jk>public</jk> String <jf>f1</jf> = <js>"f1"</js>;
+ }
+
+ JsonSerializer s = JsonSerializer.<jsf>DEFAULT_LAX</jsf>;
+ A1 a1 = <jk>new</jk> A1();
+ String r = s.serialize(a1);
+ <jsm>assertEquals</jsm>(<js>"{f0:'f0'}"</js>, r); <jc>// Note f1 is not serialized.</jc>
+ </p>
+ <p>
+ Note that this annotation can be used on the parent class so that it filters to all child classes,
+ or can be set individually on the child classes.
+ </p>
+ <p>
+ The {@link org.apache.juneau.annotation.Bean#stopClass @Bean.stopClass()} annotation is another
+ way to limit which properties are serialized.
+ <br>It's identical in purpose to the stop class specified by {@link java.beans.Introspector#getBeanInfo(Class, Class)}.
+ <br>Any properties in the stop class or in its base classes will be ignored during analysis.
+ </p>
+ <p>
+ For example, in the following class hierarchy, instances of <code>C3</code> will include property
+ <code>p3</code>, but not <code>p1</code> or <code>p2</code>.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> C1 {
+ <jk>public int</jk> getP1();
+ }
+
+ <jk>public class</jk> C2 <jk>extends</jk> C1 {
+ <jk>public int</jk> getP2();
+ }
+
+ <ja>@Bean</ja>(stopClass=C2.<jk>class</jk>)
+ <jk>public class</jk> C3 <jk>extends</jk> C2 {
+ <jk>public int</jk> getP3();
+ }
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.BeanPropertyAnnotation"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.8 - @BeanProperty Annotation</h4>
+ <div class='topic'>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotation is used to tailor how
+ individual bean properties are interpreted by the framework.
+ </p>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanProperty#name() @BeanProperty.name()} annotation
+ is used to override the name of the bean property.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> MyBean {
+ <ja>@BeanProperty</ja>(name=<js>"Bar"</js>)
+ <jk>public</jk> String getFoo() {...}
+ }
+ </p>
+ <p>
+ If the {@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility} setting on the bean context excludes this field
+ (e.g. the visibility is set to the default of PUBLIC, but the field is PROTECTED), this annotation
+ can be used to force the field to be identified as a property.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> MyBean {
+ <ja>@BeanProperty</ja>
+ <jk>protected</jk> String getFoo() {...}
+ }
+ </p>
+ <p>
+ The bean property named <js>"*"</js> is the designated "dynamic property" which allows for "extra" bean
+ properties not otherwise defined.
+ <br>This is similar in concept to the Jackson <ja>@JsonGetterAll</ja> and <ja>@JsonSetterAll</ja>
+ annotations, but generalized for all supported marshall languages.
+ <br>The primary purpose is for backwards compatibility in parsing newer streams with addition
+ information into older beans.
+ </p>
+ <p>
+ The following shows various ways of using dynamic bean properties.
+ </p>
+ <p class='bcode'>
+ <jc>// Option #1 - A simple public Map field.</jc>
+ <jc>// The field name can be anything.</jc>
+ <jk>public class</jk> BeanWithDynaField {
+
+ <ja>@BeanProperty</ja>(name=<js>"*"</js>)
+ <jk>public</jk> Map<String,Object> extraStuff = <jk>new</jk> LinkedHashMap<String,Object>();
+ }
+
+ <jc>// Option #2 - Getters and setters.</jc>
+ <jc>// Method names can be anything.</jc>
+ <jc>// Getter must return a Map with String keys.</jc>
+ <jc>// Setter must take in two arguments, a String and Object.</jc>
+ <jk>public class</jk> BeanWithDynaMethods {
+
+ <ja>@BeanProperty</ja>(name=<js>"*"</js>)
+ <jk>public</jk> Map<String,Object> getMyExtraStuff() {
+ ...
+ }
+
+ <ja>@BeanProperty</ja>(name=<js>"*"</js>)
+ <jk>public void</jk> setAnExtraField(String name, Object value) {
+ ...
+ }
+ }
+
+ <jc>// Option #3 - Getter only.</jc>
+ <jc>// Properties will be added through the getter.</jc>
+ <jk>public class</jk> BeanWithDynaGetterOnly {
+
+ <ja>@BeanProperty</ja>(name=<js>"*"</js>)
+ <jk>public</jk> Map<String,Object> getMyExtraStuff() {
+ ...
+ }
+ }
+ </p>
+ <p>
+ Similar rules apply for value types and swaps.
+ <br>The property values optionally can be any serializable type or use swaps.
+ </p>
+ <p class='bcode'>
+ <jc>// A serializable type other than Object.</jc>
+ <jk>public class</jk> BeanWithDynaFieldWithListValues {
+
+ <ja>@BeanProperty</ja>(name=<js>"*"</js>)
+ <jk>public</jk> Map<String,List<String>> getMyExtraStuff() {
+ ...
+ }
+ }
+
+ <jc>// A swapped value.</jc>
+ <jk>public class</jk> BeanWithDynaFieldWithSwappedValues {
+
+ <ja>@BeanProperty</ja>(name=<js>"*"</js>, swap=CalendarSwap.<jsf>ISO8601DTZ</jsf>.<jk>class</jk>)
+ <jk>public</jk> Map<String,Calendar> getMyExtraStuff() {
+ ...
+ }
+ }
+ </p>
+ <ul class='doctree'>
+ <li class='info'>
+ Note that if you're not interested in these additional properties, you can also use the
+ {@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownBeanProperties} setting to ignore values
+ that don't fit into existing properties.
+ </ul>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanProperty#value() @BeanProperty.value()} annotation
+ is a synonym for {@link org.apache.juneau.annotation.BeanProperty#name() @BeanProperty.name()}.
+ <br>Use it in cases where you're only specifying a name so that you can shorten your annotation.
+ </p>
+ <p>
+ The following annotations are equivalent:
+ </p>
+ <p class='bcode'>
+ <ja>@BeanProperty</ja>(name=<js>"foo"</js>)
+
+ <ja>@BeanProperty</ja>(<js>"foo"</js>)
+ </p>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanProperty#type() @BeanProperty.type()} annotation
+ is used to identify a specialized class type for a generalized property.
+ <br>Normally the type is inferred through reflection of the field type or getter return type.
+ <br>However, you'll want to specify this value if you're parsing beans where the bean property class
+ is an interface or abstract class to identify the bean type to instantiate.
+ <br>Otherwise, you may cause an {@link java.lang.InstantiationException} when trying to set these fields.
+ </p>
+ <p>
+ This property must denote a concrete class with a no-arg constructor.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> MyBean {
+
+ <jc>// Identify concrete type as a HashMap.</jc>
+ <ja>@BeanProperty</ja>(type=HashMap.<jk>class</jk>)
+ <jk>public</jk> Map <jf>p1</jf>;
+ </p>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanProperty#params() @BeanProperty.params()} annotation
+ is for bean properties of type map or collection.
+ <br>It's used to identify the class types of the contents of the bean property object when
+ the general parameter types are interfaces or abstract classes.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> MyBean {
+
+ <jc>// Identify concrete map type with String keys and Integer values.</jc>
+ <ja>@BeanProperty</ja>(type=HashMap.<jk>class</jk>, params={String.<jk>class</jk>,Integer.<jk>class</jk>})
+ <jk>public</jk> Map <jf>p1</jf>;
+ }
+ </p>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanProperty#properties() @BeanProperty.properties()}
+ annotation is used to limit which child properties are rendered by the serializers.
+ <br>It can be used on any of the following bean property types:
+ </p>
+ <ul class='spaced-list'>
+ <li>Beans - Only render the specified properties of the bean.
+ <li>Maps - Only render the specified entries in the map.
+ <li>Bean/Map arrays - Same, but applied to each element in the array.
+ <li>Bean/Map collections - Same, but applied to each element in the collection.
+ </ul>
+ <p class='bcode'>
+ <jk>public class</jk> MyClass {
+
+ <jc>// Only render 'f1' when serializing this bean property.</jc>
+ <ja>@BeanProperty</ja>(properties={<js>"f1"</js>})
+ <jk>public</jk> MyChildClass x1 = <jk>new</jk> MyChildClass();
+ }
+
+ <jk>public class</jk> MyChildClass {
+ <jk>public int</jk> f1 = 1;
+ <jk>public int</jk> f2 = 2;
+ }
+
+ <jc>// Renders "{x1:{f1:1}}"</jc>
+ String json = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(<jk>new</jk> MyClass());
+ </p>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanProperty#format() @BeanProperty.format()}
+ annotation specifies a String format for converting a bean property value to a formatted string.
+ </p>
+ <p class='bcode'>
+ <jc>// Serialize a float as a string with 2 decimal places.</jc>
+ <ja>@BeanProperty</ja>(format=<js>"$%.2f"</js>)
+ <jk>public float</jk> <jf>price</jf>;
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.BeanConstructorAnnotation"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.9 - @BeanConstructor Annotation</h4>
+ <div class='topic'>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor} annotation is used to
+ map constructor arguments to property names on bean with read-only properties.
+ <br>Since method parameter names are lost during compilation, this annotation essentially redefines
+ them so that they are available at runtime.
+ </p>
+ <p>
+ The definition of a read-only bean is a bean with properties with only getters, like shown below:
+ </p>
+ <p class='bcode'>
+ <jc>// Our read-only bean.</jc>
+ <jk>public class</jk> Person {
+ <jk>private final</jk> String <jf>name</jf>;
+ <jk>private final int</jk> <jf>age</jf>;
+
+ <ja>@BeanConstructor</ja>(properties=<js>"name,age"</js>})
+ <jk>public</jk> Person(String name, <jk>int</jk> age) {
+ <jk>this</jk>.<jf>name</jf> = name;
+ <jk>this</jk>.<jf>age</jf> = age;
+ }
+
+ <jc>// Read only properties.</jc>
+
+ <jk>public</jk> String getName() {
+ <jk>return</jk> <jf>name</jf>;
+ }
+
+ <jk>public int</jk> getAge() {
+ <jk>return</jk> <jf>age</jf>;
+ }
+ }
+ </p>
+ <p class='bcode'>
+ <jc>// Parsing into a read-only bean.</jc>
+ String json = <js>"{name:'John Smith',age:45}"</js>;
+ Person p = JsonParser.<jsf>DEFAULT</jsf>.parse(json);
+ String name = p.getName(); <jc>// "John Smith"</jc>
+ <jk>int</jk> age = p.getAge(); <jc>// 45</jc>
+ </p>
+ <p>
+ Beans can also be defined with a combination of read-only and read-write properties.
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.BeanIgnoreAnnotation"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.10 - @BeanIgnore Annotation</h4>
+ <div class='topic'>
+ <p>
+ The {@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore} annotation is used to
+ ignore classes, fields, and methods from being interpreted as beans or bean components.
+ </p>
+ <p>
+ When applied to classes, objects will be converted to strings even though they look like beans.
+ </p>
+ <p class='bcode'>
+ <jc>// Not really a bean! Use toString() instead!</jc>
+ <ja>@BeanIgnore</ja>
+ <jk>public class</jk> MyBean {...}
+ </p>
+ <p>
+ When applied to fields and getters/setters, they will be ignored as bean properties.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> MyBean {
+
+ <jc>// Not a bean property!</jc>
+ <ja>@BeanIgnore</ja>
+ <jk>public</jk> String <jf>foo</jf>;
+
+ <jc>// Not a bean property!</jc>
+ <ja>@BeanIgnore</ja>
+ <jk>public</jk> String getBar() {...}
+ }
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.NamePropertyAnnotation"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.11 - @NameProperty Annotation</h4>
+ <div class='topic'>
+ <p>
+ The {@link org.apache.juneau.annotation.NameProperty @NameProperty} annotation is used to
+ identify a setter as a method for setting the name of a POJO as it's known by its parent object.
+ </p>
+ <p>
+ A commonly-used case is when you're parsing a JSON map containing beans where one of the bean
+ properties is the key used in the map.
+ </p>
+ <p class='bcode'>
+ <jc>// JSON</jc>
+ {
+ id1: {name: <js>'John Smith'</js>, sex:<js>'M'</js>},
+ id2: {name: <js>'Jane Doe'</js>, sex:<js>'F'</js>}
+ }
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> Person {
+
+ <ja>@NameProperty</ja>
+ <jk>public</jk> String <jf>id</jf>; <jc>// Value gets assigned from object key</jc>
+
+ <jk>public</jk> String <jf>name</jf>;
+
+ <jk>public char</jk> <jf>sex</jf>;
+ }
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.ParentPropertyAnnotion"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.12 - @ParentProperty Annotation</h4>
+ <div class='topic'>
+ <p>
+ The {@link org.apache.juneau.annotation.ParentProperty @ParentProperty} annotation is used to
+ identify a setter as a method for adding a parent reference to a child object.
+ </p>
+ <p>
+ A commonly-used case is when you're parsing beans and a child bean has a reference to a parent bean.
+ </p>
+ <p class='bcode'>
+ <jk>public class</jk> AddressBook {
+ <jk>public</jk> List<Person> <jf>people</jf>;
+ }
+
+ <jk>public class</jk> Person {
+
+ <ja>@ParentProperty</ja>
+ <jk>public</jk> AddressBook <jf>addressBook</jf>; <jc>// A reference to the containing address book.</jc>
+
+ <jk>public</jk> String <jf>name</jf>;
+
+ <jk>public char</jk> <jf>sex</jf>;
+ }
+ </p>
+ <p>
+ Parsers will automatically set this field for you in the child beans.
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.URIAnnotation"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.13 - @URI Annotation</h4>
+ <div class='topic'>
+ <p>
+ The {@link org.apache.juneau.annotation.URI @URI} annotation is used to identify a class or bean
+ property as a URI.
+ </p>
+ <p>
+ By default, instances of {@link java.net.URL} and {@link java.net.URI} are considered URIs during serialization and
+ are handled differently depending on the serializer (e.g. <code>HtmlSerializer</code> creates a
+ hyperlink, <code>RdfXmlSerializer</code> creates an <code>rdf:resource</code> object, etc...).
+ <br>This annotation allows you to identify other classes that return URIs via <code>toString()</code>
+ as URI objects.
+ </p>
+ <p>
+ URIs are automatically resolved to absolute or root-relative form based on the serializer
+ {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriResolution} and
+ {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriRelativity}
+ configuration settings, and the URI context defined by the {@link org.apache.juneau.UriContext} that's part of the
+ serializer session.
+ <br>Refer to the {@link org.apache.juneau.UriResolver} class for information about the types of URIs that can be
+ resolved during serialization.
+ </p>
+ <p>
+ This annotation can be applied to classes, interfaces, or bean property methods for fields.
+ </p>
+ <p class='bcode'>
+ <jc>// Applied to a class whose toString() method returns a URI.</jc>
+ <ja>@URI</ja>
+ <jk>public class</jk> MyURI {
+ <ja>@Override</ja>
+ <jk>public</jk> String toString() {
+ <jk>return</jk> <js>"http://localhost:9080/foo/bar"</js>;
+ }
+ }
+
+ <jc>// Applied to bean properties</jc>
+ <jk>public class</jk> MyBean {
+
+ <ja>@URI</ja>
+ <jk>public</jk> String <jf>beanUri</jf>;
+
+ <ja>@URI</ja>
+ <jk>public</jk> String getParentUri() {
+ ...
+ }
+ }
+ </p>
+ </div>
+
+ <!-- ======================================================================================================= -->
+ <a id="juneau-marshall.BeanFilters"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.14 - BeanFilter Class</h4>
+ <div class='topic'>
+ <p>
+ The {@link org.apache.juneau.transform.BeanFilter} class is the programmatic equivalent to the
+ {@link org.apache.juneau.annotation.Bean @Bean} annotation.
+ </p>
+ <p>
+ In practice, it's usually simpler to use the {@link org.apache.juneau.annotation.Bean @Bean} and
+ {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotations on your bean classes.
+ <br>However, bean filters make it possible to accomplish the same when you can't add annotations
+ to existing code.
</p>
<p>
Bean filters are defined through {@link org.apache.juneau.transform.BeanFilterBuilder BeanFilterBuilders}.
@@ -1443,7 +2115,7 @@
</p>
<p class='bcode'>
<jc>// Create a new JSON serializer and associate a bean filter with it.</jc>
- Serializer serializer = JsonSerializer.<jsm>create</jsm>().beanFilters(MyAddressBeanFilter.<jk>class</jk>).build();
+ WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyAddressBeanFilter.<jk>class</jk>).build();
</p>
<p>
Note that if you use the annotation, you do NOT need to set anything on the serializers/parsers.
@@ -1470,18 +2142,117 @@
}
<jc>// Create a new JSON serializer that only exposes street,city,state on Address bean.</jc>
- Serializer serializer = JsonSerializer.<jsm>create</jsm>().beanFilters(AddressInterface.<jk>class</jk>).build();
+ WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(AddressInterface.<jk>class</jk>).build();
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.StopClasses"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.15 - Stop Classes</h4>
+ <div class='topic'>
+ <p>
+ Occasionally, you may want to limit bean properties to only those defined on a parent class or interface.
+ <br>There are a couple of ways of doing this.
+ </p>
+ <p>
+ For example, let's define the following parent class and subclass:
+ </p>
+ <p class='bcode'>
+ <jc>// Abstract parent class</jc>
+ <jk>public abstract class</jk> MyClass {
+ <jk>public</jk> String <jf>foo</jf>=<js>"foo"</js>;
+ }
+
+ <jc>// Subclass 1</jc>
+ <jk>public class</jk> MyClassBar <jk>extends</jk> MyClass {
+ <jk>public</jk> String <jf>bar</jf>=<js>"bar"</js>;
+ }
+ </p>
+ <p>
+ Suppose we only want to render the properties defined on <code>MyClass</code>, not those defined on
+ child classes.
+ <br>To do so, we can define the following bean filter:
+ </p>
+ <p class='bcode'>
+ <jc>// Define transform that limits properties to only those defined on MyClass</jc>
+ <jk>public class</jk> MyBeanFilter <jk>extends</jk> BeanFilter<MyClass> {
+ <jk>public</jk> MyBeanFilter() {
+ interfaceClass(MyClass.<jk>class</jk>);
+ }
+ }
+ </p>
+ <p>
+ When serialized, the serialized bean will only include properties defined on the parent class.
+ </p>
+ <p class='bcode'>
+ <jc>// Serialize to JSON</jc>
+ WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().beanFilters(MyBeanFilter.<jk>class</jk>).build();
+ MyClass c = <jk>new</jk> MyClassBar();
+ String json = s.serialize(p); <jc>// Prints "{foo:'foo'}"</jc>
+ </p>
+ <p>
+ The equivalent can be done through an annotation on the parent class, which applies to all child classes:
+ </p>
+ <p class='bcode'>
+ <ja>@Bean</ja>(interfaceClass=MyClass.<jk>class</jk>)
+ <jk>public abstract class</jk> MyClass {
+ <jk>public</jk> String <jf>foo</jf>=<js>"foo"</js>;
+ }
+ </p>
+ <p>
+ The annotation can also be applied on the individual child classes, like so...
+ </p>
+ <p class='bcode'>
+ <ja>@Bean</ja>(interfaceClass=MyClass.<jk>class</jk>)
+ <jk>public class</jk> MyClassBar <jk>extends</jk> MyClass {
+ <jk>public</jk> String <jf>bar</jf>=<js>"bar"</js>;
+ }
+ </p>
+ <p>
+ Also, the <code>beanFilters()</code> methods will automatically interpret any non-<code>BeanFilter</code>
+ classes passed in as meaning interface classes.
+ <br>So in the previous example, the <code>BeanFilter</code> class could have been avoided altogether by just
+ passing in <code>MyClass.<jk>class</jk></code> to the serializer, like so:
+ </p>
+ <p class='bcode'>
+ <jc>// Serialize to JSON</jc>
+ WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyClass.<jk>class</jk>).build();
+ </p>
+ </div>
+
+ <!-- =================================================================================================== -->
+ <a id="juneau-marshall.SerializingToObjectMaps"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.16 - Serializing to ObjectMaps</h4>
+ <div class='topic'>
+ <p>
+ A shortcut method for transforming is provided that can often be simpler than defining transforms.
+ In this case, we add methods to our class to serialize to {@link org.apache.juneau.ObjectMap ObjectMaps}
+ </p>
+ <p>
+ <p class='bcode'>
+ <jk>public class</jk> MyClass {
+ <jk>private</jk> String <jf>f1</jf>;
+
+ <jc>// Constructor that takes in an ObjectMap</jc>
+ <jk>public</jk> MyClass(ObjectMap m) {
+ <jf>f1</jf> = m.getString(<js>"f1"</js>);
+ }
+
+ <jc>// Method that converts object to an ObjectMap</jc>
+ <jk>public</jk> ObjectMap toObjectMap() {
+ <jk>return new</jk> ObjectMap().append(<js>"f1"</js>, <jf>f1</jf>);
+ }
+ </p>
+ <p>
+ The <code>toObjectMap()</code> method will automatically be used during serialization, and
+ the constructor will automatically be used during parsing.
+ This will work for all serializers and parsers.
</p>
-
- <h6 class='toc'>Additional Information - org.apache.juneau.transform</h6>
- <ol class='toc'>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#BeanFilters'>BeanFilter Class</a></p>
- </ol>
</div>
<!-- =================================================================================================== -->
<a id="juneau-marshall.SerializingReadersAndInputStreams"></a>
- <h4 class='topic' onclick='toggle(this)'>2.1.6.5 - Serializing Readers and InputStreams</h4>
+ <h4 class='topic' onclick='toggle(this)'>2.1.6.17 - Serializing Readers and InputStreams</h4>
<div class='topic'>
<p>
Juneau serializers treat instances of <code>Readers</code> and <code>InputStreams</code> special by
@@ -1527,20 +2298,6 @@
access to the underlying stream.
</ul>
</div>
-
-
- <h6 class='toc'>Additional Information - org.apache.juneau.transform</h6>
- <ol class='toc'>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#Transforms'>Transforms</a></p>
- <ol>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#BeanFilters'>BeanFilter Class</a></p>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#PojoSwaps'>PojoSwap Class</a></p>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#PojoSwaps_OneWay'>One-Way PojoSwaps</a></p>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#StopClasses'>Stop Classes</a></p>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#SurrogateClasses'>Surrogate Classes</a></p>
- <li><p><a class='doclink' href='org/apache/juneau/transform/package-summary.html#ToObjectMaps'>Serializing to ObjectMaps</a></p>
- </ol>
- </ol>
</div>
<!-- ======================================================================================================= -->
@@ -8108,6 +8865,38 @@
</ul>
</ul>
+ <h6 class='topic'>Documentation</h6>
+ <ul class='spaced-list'>
+ <li>
+ New and updated sections in overview document:
+ <ul>
+ <li><p><a class='doclink' href='#juneau-marshall.PojoSwaps'>PojoSwaps</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.PerMediaTypePojoSwaps'>Per-media-type PojoSwaps</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.OneWayPojoSwaps'>One-way PojoSwaps</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SwapAnnotation'>@Swap Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SwapMethods'>Swap Methods</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SurrogateClasses'>Surrogate Classes</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanAnnotation'>@Bean Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanPropertyAnnotation'>@BeanProperty Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanConstructorAnnotation'>@BeanConstructor Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanIgnoreAnnotation'>@BeanIgnore Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.NamePropertyAnnotation'>@NameProperty Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.ParentPropertyAnnotation'>@ParentProperty Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.URIAnnotation'>@URI Annotation</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.BeanFilters'>BeanFilters</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.StopClasses'>Stop Classes</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SerializingToObjectMaps'>Serializing to ObjectMaps</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.SerializingReadersAndInputStreams'>Serializing Readers and InputStreams</a></p>
+ </ul>
+ <li>
+ Updated javadocs:
+ <ul>
+ <li>{@link org.apache.juneau.BeanContext}
+ <li>{@link org.apache.juneau.BeanContextBuilder}
+ <li>{@link org.apache.juneau.rest.RestContext}
+ <li>{@link org.apache.juneau.rest.RestContextBuilder}
+ </ul>
+ </ul>
</div>
<!-- =========================================================================================================== -->
@@ -12991,4 +13780,4 @@
</div>
</body>
-
\ No newline at end of file
+
[2/2] juneau git commit: Javadoc updates.
Posted by ja...@apache.org.
Javadoc updates.
Project: http://git-wip-us.apache.org/repos/asf/juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/juneau/commit/474a143c
Tree: http://git-wip-us.apache.org/repos/asf/juneau/tree/474a143c
Diff: http://git-wip-us.apache.org/repos/asf/juneau/diff/474a143c
Branch: refs/heads/master
Commit: 474a143ce44d5243d5af0f3cc3235bf72ee1c30d
Parents: cea2a1d
Author: JamesBognar <ja...@apache.org>
Authored: Mon Jan 8 22:32:44 2018 -0500
Committer: JamesBognar <ja...@apache.org>
Committed: Mon Jan 8 22:32:44 2018 -0500
----------------------------------------------------------------------
.../java/org/apache/juneau/BeanContext.java | 78 +-
.../org/apache/juneau/transform/MapSwap.java | 21 +
.../org/apache/juneau/transform/PojoSwap.java | 55 +-
.../org/apache/juneau/transform/StringSwap.java | 21 +
.../org/apache/juneau/transform/package.html | 675 -------------
juneau-doc/src/main/javadoc/overview.html | 983 +++++++++++++++++--
6 files changed, 1028 insertions(+), 805 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/juneau/blob/474a143c/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index dd681f7..7769f1c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -426,6 +426,10 @@ public class BeanContext extends Context {
* <li><b>Data type:</b> <code>List<Class></code>
* <li><b>Default:</b> empty list
* <li><b>Session-overridable:</b> <jk>false</jk>
+ * <li><b>Annotations:</b>
+ * <ul>
+ * <li class='ja'>{@link Bean}
+ * </ul>
* <li><b>Methods:</b>
* <ul>
* <li class='jm'>{@link BeanContextBuilder#beanFilters(Object...)}
@@ -479,8 +483,9 @@ public class BeanContext extends Context {
*
* <h5 class='section'>Documentation:</h5>
* <ul>
- * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.BeanFilters">Overview > BeanFilters and @Bean annotations</a>
- * <li><a class="doclink" href="transform/package-summary.html#BeanFilters">org.apache.juneau.transform > BeanFilter Class</a>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.BeanAnnotation">Overview > @Bean Annotation</a>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.BeanFilters">Overview > BeanFilters</a>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.StopClasses">Overview > Stop Classes</a>
* </ul>
*/
public static final String BEAN_beanFilters = PREFIX + "beanFilters.lc";
@@ -1056,7 +1061,7 @@ public class BeanContext extends Context {
public static final String BEAN_notBeanPackages_remove = PREFIX + "notBeanPackages.ss/remove";
/**
- * Configuration property: POJO swaps to apply to Java objects.
+ * Configuration property: POJO swaps.
*
* <h5 class='section'>Property:</h5>
* <ul>
@@ -1071,8 +1076,8 @@ public class BeanContext extends Context {
* </ul>
* <li><b>Methods:</b>
* <ul>
- * <li class='jm'>{@link BeanContextBuilder#pojoSwaps(Class...)}
* <li class='jm'>{@link BeanContextBuilder#pojoSwaps(Object...)}
+ * <li class='jm'>{@link BeanContextBuilder#pojoSwaps(Class...)}
* <li class='jm'>{@link BeanContextBuilder#pojoSwaps(boolean, Object...)}
* <li class='jm'>{@link BeanContextBuilder#pojoSwapsRemove(Object...)}
* </ul>
@@ -1080,16 +1085,67 @@ public class BeanContext extends Context {
*
* <h5 class='section'>Description:</h5>
* <p>
- * There are two category of classes that can be passed in through this method:
- * <ul>
- * <li>Subclasses of {@link PojoSwap}.
- * <li>Surrogate classes. A shortcut for defining a {@link SurrogateSwap}.
- * </ul>
- *
+ * POJO swaps are used to "swap out" non-serializable classes with serializable equivalents during serialization,
+ * and "swap in" the non-serializable class during parsing.
+ *
+ * <p>
+ * An example of a POJO swap would be a <code>Calendar</code> object that gets swapped out for an ISO8601 string.
+ *
* <p>
* Multiple POJO swaps can be associated with a single class.
- * When multiple swaps are applicable to the same class, the media type pattern defined by
+ * <br>When multiple swaps are applicable to the same class, the media type pattern defined by
* {@link PojoSwap#forMediaTypes()} or {@link Swap#mediaTypes()} are used to come up with the best match.
+ *
+ * <p>
+ * Values can consist of any of the following types:
+ * <ul>
+ * <li>Any subclass of {@link PojoSwap}.
+ * <li>Any surrogate class. A shortcut for defining a {@link SurrogateSwap}.
+ * <li>Any array or collection of the objects above.
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * <jc>// Sample swap for converting Dates to ISO8601 strings.</jc>
+ * <jk>public class</jk> MyDateSwap <jk>extends</jk> StringSwap<Date> {
+ * <jc>// ISO8601 formatter.</jc>
+ * <jk>private</jk> DateFormat <jf>format</jf> = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>);
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> String swap(BeanSession session, Date o) {
+ * <jk>return</jk> <jf>format</jf>.format(o);
+ * }
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> Date unswap(BeanSession session, String o, ClassMeta hint) <jk>throws</jk> Exception {
+ * <jk>return</jk> <jf>format</jf>.parse(o);
+ * }
+ * }
+ *
+ * <jc>// Sample bean with a Date field.</jc>
+ * <jk>public class</jk> MyBean {
+ * <jk>public</jk> Date <jf>date</jf> = <jk>new</jk> Date(112, 2, 3, 4, 5, 6);
+ * }
+ *
+ * <jc>// Create a new JSON serializer, associate our date swap with it, and serialize a sample bean.</jc>
+ * WriterSerializer s = JsonSerializer.<jsm>create</jsm>().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
+ * String json = s.serialize(<jk>new</jk> MyBean()); <jc>// == "{date:'2012-03-03T04:05:06-0500'}"</jc>
+ *
+ * <jc>// Create a JSON parser, associate our date swap with it, and reconstruct our bean (including the date).</jc>
+ * ReaderParser p = JsonParser.<jsm>create</jsm>().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
+ * MyBean bean = p.parse(json, MyBean.<jk>class</jk>);
+ * <jk>int</jk> day = bean.<jf>date</jf>.getDay(); <jc>// == 3</jc>
+ * </p>
+ *
+ * <h5 class='section'>Documentation:</h5>
+ * <ul>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.PojoSwaps">Overview > PojoSwaps</a>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.PerMediaTypePojoSwaps">Overview > Per-media-type PojoSwaps</a>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.OneWayPojoSwaps">Overview > One-way PojoSwaps</a>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.SwapAnnotation">Overview > @Swap Annotation</a>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.SwapMethods">Overview > Swap Methods</a>
+ * <li><a class="doclink" href="../../../overview-summary.html#juneau-marshall.SurrogateClasses">Overview > Surrogate Classes</a>
+ * </ul>
*/
public static final String BEAN_pojoSwaps = PREFIX + "pojoSwaps.lc";
http://git-wip-us.apache.org/repos/asf/juneau/blob/474a143c/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/MapSwap.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/MapSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/MapSwap.java
index 8f521c0..a2f1904 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/MapSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/MapSwap.java
@@ -17,6 +17,27 @@ import org.apache.juneau.*;
/**
* Abstract subclass for POJO swaps that swap objects for object maps.
*
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * <jc>// A swap that converts beans into generic maps.</jc>
+ * <jk>public class</jk> MyBeanSwap <jk>extends</jk> MapSwap<<jk>byte</jk>[]> {
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> ObjectMap swap(BeanSession session, MyBean myBean) <jk>throws</jk> Exception {
+ * <jk>return new</jk> ObjectMap().append(<js>"foo"</js>, myBean.getFoo());
+ * }
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> MyBean unswap(BeanSession session, ObjectMap m, ClassMeta<?> hint) <jk>throws</jk> Exception {
+ * <jk>return new</jk> MyBean(m.get(<js>"foo"</js>));
+ * }
+ * }
+ *
+ * <jc>// Use it to serialize a byte array.</jc>
+ * WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(MyBeanSwap.<jk>class</jk>).build();
+ * String json = s.serialize(<jk>new</jk> MyBean(<js>"bar"</js>)); <jc>// Produces "{foo:'bar'}"</jc>
+ * </p>
+ *
* @param <T> The normal form of the class.
*/
public abstract class MapSwap<T> extends PojoSwap<T,ObjectMap> {
http://git-wip-us.apache.org/repos/asf/juneau/blob/474a143c/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java
index 3d47fc4..58d9669 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java
@@ -26,8 +26,7 @@ import org.apache.juneau.serializer.*;
* Used to swap out non-serializable objects with serializable replacements during serialization, and vis-versa during
* parsing.
*
- *
- * <h6 class='section'>Description:</h6>
+ * <h5 class='topic'>Description</h5>
*
* <p>
* <code>PojoSwaps</code> are used to extend the functionality of the serializers and parsers to be able to handle
@@ -41,10 +40,15 @@ import org.apache.juneau.serializer.*;
* Swaps MUST declare a public no-arg constructor so that the bean context can instantiate them.
*
* <p>
- * <code>PojoSwaps</code> are associated with instances of {@link BeanContext BeanContexts} by passing the swap
- * class to the {@link SerializerBuilder#pojoSwaps(Class...)} and {@link ParserBuilder#pojoSwaps(Class...)} methods.
- * <br>When associated with a bean context, fields of the specified type will automatically be converted when the
- * {@link BeanMap#get(Object)} or {@link BeanMap#put(String, Object)} methods are called.
+ * <code>PojoSwaps</code> are associated with serializers and parsers through the following:
+ * <ul>
+ * <li class='ja'>{@link Swap}
+ * <li class='ja'>{@link Swaps}
+ * <li class='jm'>{@link BeanContextBuilder#pojoSwaps(Object...)}
+ * <li class='jm'>{@link BeanContextBuilder#pojoSwaps(Class...)}
+ * <li class='jm'>{@link BeanContextBuilder#pojoSwaps(boolean, Object...)}
+ * <li class='jm'>{@link BeanContextBuilder#pojoSwapsRemove(Object...)}
+ * </ul>
*
* <p>
* <code>PojoSwaps</code> have two parameters:
@@ -62,8 +66,8 @@ import org.apache.juneau.serializer.*;
*
* The following abstract subclasses are provided for common swap types:
* <ol>
- * <li>{@link StringSwap} - Objects swapped with strings.
- * <li>{@link MapSwap} - Objects swapped with {@link ObjectMap ObjectMaps}.
+ * <li class='jac'>{@link StringSwap} - Objects swapped with strings.
+ * <li class='jac'>{@link MapSwap} - Objects swapped with {@link ObjectMap ObjectMaps}.
* </ol>
*
*
@@ -96,24 +100,27 @@ import org.apache.juneau.serializer.*;
*
*
* <h6 class='topic'>Overview</h6>
- *
+ *
+ * <p>
* The following is an example of a swap that replaces byte arrays with BASE-64 encoded strings:
- *
+ *
* <p class='bcode'>
- * <jk>public class</jk> ByteArrayBase64Swap <jk>extends</jk> PojoSwap<<jk>byte</jk>[],String> {
- *
- * <jk>public</jk> String swap(BeanSession session, <jk>byte</jk>[] b) <jk>throws</jk> SerializeException {
+ * <jk>public class</jk> ByteArrayBase64Swap <jk>extends</jk> PojoSwap<<jk>byte</jk>[],String> {
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> String swap(BeanSession session, <jk>byte</jk>[] b) <jk>throws</jk> Exception {
* <jk>return</jk> StringUtils.<jsm>base64Encode</jsm>(b);
* }
- *
- * <jk>public byte</jk>[] unswap(BeanSession session, String s, ClassMeta<?> hint) <jk>throws</jk> ParseException {
+ *
+ * <ja>@Override</ja>
+ * <jk>public byte</jk>[] unswap(BeanSession session, String s, ClassMeta<?> hint) <jk>throws</jk> Exception {
* <jk>return</jk> StringUtils.<jsm>base64Decode</jsm>(s);
* }
* }
* </p>
*
* <p class='bcode'>
- * WriterSerializer s = JsonSerializer.<jsf>DEFAULT_LAX</jsf>.builder().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
+ * WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
* String json = s.serialize(<jk>new byte</jk>[] {1,2,3}); <jc>// Produces "'AQID'"</jc>
* </p>
*
@@ -148,11 +155,11 @@ import org.apache.juneau.serializer.*;
* Note that while there is a unified interface for handling swaps during both serialization and parsing,
* in many cases only one of the {@link #swap(BeanSession, Object)} or {@link #unswap(BeanSession, Object, ClassMeta)}
* methods will be defined because the swap is one-way.
- * For example, a swap may be defined to convert an {@code Iterator} to a {@code ObjectList}, but
+ * <br>For example, a swap may be defined to convert an {@code Iterator} to a {@code ObjectList}, but
* it's not possible to unswap an {@code Iterator}.
- * In that case, the {@code swap(Object}} method would be implemented, but the {@code unswap(ObjectMap)} object would
+ * <br>In that case, the {@code swap(Object}} method would be implemented, but the {@code unswap(ObjectMap)} object would
* not, and the swap would be associated on the serializer, but not the parser.
- * Also, you may choose to serialize objects like {@code Dates} to readable {@code Strings}, in which case it's not
+ * <br>Also, you may choose to serialize objects like {@code Dates} to readable {@code Strings}, in which case it's not
* possible to re-parse it back into a {@code Date}, since there is no way for the {@code Parser} to know it's a
* {@code Date} from just the JSON or XML text.
*
@@ -160,7 +167,7 @@ import org.apache.juneau.serializer.*;
* <h6 class='topic'>Per media-type swaps</h6>
* <p>
* The {@link #forMediaTypes()} method can be overridden to provide a set of media types that the swap is invoked on.
- * It's also possible to define multiple swaps against the same POJO as long as they're differentiated by media type.
+ * <br>It's also possible to define multiple swaps against the same POJO as long as they're differentiated by media type.
* When multiple swaps are defined, the best-match media type is used.
*
* <p>
@@ -311,9 +318,13 @@ import org.apache.juneau.serializer.*;
* <code>Time-Zone</code> headers on the request.
*
*
- * <h6 class='section'>Additional information:</h6>
+ * <h6 class='topic'>Documentation</h6>
+ * <ul>
+ * <li><a class="doclink" href="../../../../overview-summary.html#juneau-marshall.PojoSwaps">Overview > PojoSwaps</a>
+ * <li><a class="doclink" href="package-summary.html#PojoSwaps">org.apache.juneau.transform > PojoSwap Class</a>
+ * <li><a class='doclink' href='org/apache/juneau/transform/package-summary.html#PojoSwaps_OneWay'>org.apache.juneau.transform > One-Way PojoSwaps</a>
+ * </ul>
*
- * See <a class='doclink' href='package-summary.html#TOC'>org.apache.juneau.transform</a> for more information.
*
* @param <T> The normal form of the class.
* @param <S> The swapped form of the class.
http://git-wip-us.apache.org/repos/asf/juneau/blob/474a143c/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/StringSwap.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/StringSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/StringSwap.java
index 6002086..4980a00 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/StringSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/StringSwap.java
@@ -17,6 +17,27 @@ import org.apache.juneau.*;
/**
* Abstract subclass for POJO swaps that swap objects for strings.
*
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * <jc>// A swap that converts byte arrays to BASE64-encoded strings.</jc>
+ * <jk>public class</jk> ByteArrayBase64Swap <jk>extends</jk> StringSwap<<jk>byte</jk>[]> {
+ *
+ * <ja>@Override</ja>
+ * <jk>public</jk> String swap(BeanSession session, <jk>byte</jk>[] b) <jk>throws</jk> Exception {
+ * <jk>return</jk> StringUtils.<jsm>base64Encode</jsm>(b);
+ * }
+ *
+ * <ja>@Override</ja>
+ * <jk>public byte</jk>[] unswap(BeanSession session, String s, ClassMeta<?> hint) <jk>throws</jk> Exception {
+ * <jk>return</jk> StringUtils.<jsm>base64Decode</jsm>(s);
+ * }
+ * }
+ *
+ * <jc>// Use it to serialize a byte array.</jc>
+ * WriterSerializer s = JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
+ * String json = s.serialize(<jk>new byte</jk>[] {1,2,3}); <jc>// Produces "'AQID'"</jc>
+ * </p>
+ *
* @param <T> The normal form of the class.
*/
public abstract class StringSwap<T> extends PojoSwap<T,String> {
http://git-wip-us.apache.org/repos/asf/juneau/blob/474a143c/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/package.html
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/package.html b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/package.html
index f351735..faf5634 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/package.html
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/package.html
@@ -56,680 +56,5 @@
}
</script>
-<a id='TOC'></a><h5 class='toc'>Table of Contents</h5>
-<ol class='toc'>
- <li><p><a class='doclink' href='#Transforms'>Transforms</a></p>
- <ol>
- <li><p><a class='doclink' href='#BeanFilters'>BeanFilter Class</a></p>
- <li><p><a class='doclink' href='#PojoSwaps'>PojoSwap Class</a></p>
- <li><p><a class='doclink' href='#PojoSwaps_OneWay'>One-Way PojoSwaps</a></p>
- <li><p><a class='doclink' href='#StopClasses'>Stop Classes</a></p>
- <li><p><a class='doclink' href='#SurrogateClasses'>Surrogate Classes</a></p>
- <li><p><a class='doclink' href='#ToObjectMaps'>Serializing to ObjectMaps</a></p>
- </ol>
-</ol>
-
-<!-- ======================================================================================================== -->
-<a id="Transforms"></a>
-<h2 class='topic' onclick='toggle(this)'>1 - Transforms</h2>
-<div class='topic'>
- <p>
- By default, the Juneau framework can serialize and parse a wide variety of POJOs out-of-the-box.
- However, two special classes are provided tailor how certain Java objects are handled by the framework.
- These classes are:
- </p>
- <ul class='spaced-list'>
- <li class='jc'>{@link org.apache.juneau.transform.BeanFilter} - Transforms that alter the way beans are handled.
- <li class='jac'>{@link org.apache.juneau.transform.PojoSwap} - Transforms that swap non-serializable POJOs with
- serializable POJOs during serialization (and optionally vis-versa during parsing).
- <ol>
- <li class='jc'>{@link org.apache.juneau.transform.StringSwap} - Convenience subclass for swaps that convert
- objects to strings.
- <li class='jc'>{@link org.apache.juneau.transform.MapSwap} - Convenience subclass for swaps that convert
- objects to maps.
- </ol>
- </li>
- </ul>
- <p>
- Transforms are added to serializers and parsers (and REST clients) using the following methods:
- </p>
- <ul class='spaced-list'>
- <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beanFilters(Object[])}
- <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#pojoSwaps(Object[])}
- </ul>
- <p>
- Annotations are also provided for specifying transforms directly on classes:
- </p>
- <ul class='spaced-list'>
- <li class='ja'>{@link org.apache.juneau.annotation.Bean @Bean}
- <li class='ja'>{@link org.apache.juneau.annotation.Swap @Swap}
- </ul>
-
- <!-- ======================================================================================================== -->
- <a id="BeanFilters"></a>
- <h3 class='topic' onclick='toggle(this)'>1.1 - BeanFilter Class</h3>
- <div class='topic'>
- <p>
- Bean filters are used to tailor how Juneau handles bean classes.
- They can be used for the following purposes:
- </p>
- <ul class='spaced-list'>
- <li>
- Include or exclude which properties are exposed in beans, or the order those properties are serialized.
- <li>
- Define property-namers for customizing bean property names.
- <li>
- Define bean subtypes.
- <li>
- Define bean interface classes.
- </ul>
- <p>
- It should be noted that the {@link org.apache.juneau.annotation.Bean @Bean} annotation provides equivalent
- functionality through annotations.
- <br>However, the {@link org.apache.juneau.transform.BeanFilter} and {@link org.apache.juneau.transform.BeanFilterBuilder}
- classes allows you to provide the same features when you do not have access to the source code.
- <p>
-
- <h6 class='topic'>Explicitly specify which properties are visible on a bean class</h6>
- <p class='bcode'>
- <jc>// Define bean filter that orders properties by "age" then "name"</jc>
- <jk>public class</jk> MyBeanFilter <jk>extends</jk> BeanFilterBuilder {
- <jk>public</jk> MyBeanFilter() {
- <jk>super</jk>(Person.<jk>class</jk>);
- properties(<js>"age"</js>,<js>"name"</js>);
- }
- }
-
- WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyBeanFilter.<jk>class</jk>).build();
- Person p = getPerson();
- String json = s.serialize(p); <jc>// Prints "{age:45,name:'John Smith'}"</jc>
- </p>
- <p>
- Note that this is equivalent to specifying the following annotation on the bean class:
- </p>
- <p class='bcode'>
- <ja>@Bean</ja>(properties=<js>"age,name"</js>)
- <jk>public class</jk> Person {
- ...
- }
- </p>
-
- <h6 class='topic'>Exclude which properties are visible on a bean class</h6>
- <p class='bcode'>
- <jc>// Define bean filter that excludes "name"</jc>
- <jk>public class</jk> MyBeanFilter <jk>extends</jk> BeanFilterBuilder {
- <jk>public</jk> MyBeanFilter() {
- <jk>super</jk>(Person.<jk>class</jk>);
- excludeProperties(<js>"name"</js>);
- }
- }
-
- WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyBeanFilter.<jk>class</jk>).build();
- Person p = getPerson();
- String json = s.serialize(p); <jc>// Prints "{age:45}"</jc>
- </p>
- <p>
- Note that this is equivalent to specifying the following annotation on the bean class:
- </p>
- <p class='bcode'>
- <ja>@Bean</ja>(excludeProperties={<js>"name"</js>})
- <jk>public class</jk> Person {
- ...
- }
- </p>
-
- <h6 class='topic'>Define specialized property namers</h6>
- <p class='bcode'>
- <jc>// Define bean filter with our own property namer.</jc>
- <jk>public class</jk> MyBeanFilter <jk>extends</jk> BeanFilterBuilder {
- <jk>public</jk> MyBeanFilter() {
- <jk>super</jk>(Person.<jk>class</jk>);
- propertyNamer(UpperCasePropertyNamer.<jk>class</jk>);
- }
- }
-
- <jc>// Define property namer that upper-cases the property names</jc>
- <jk>public class</jk> UpperCasePropertyNamer <jk>implements</jk> PropertyNamer {
- <ja>@Override</ja>
- <jk>public</jk> String getPropertyName(String name) {
- <jk>return</jk> name.toUpperCase();
- }
- }
-
- <jc>// Serialize to JSON</jc>
- WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyBeanFilter.<jk>class</jk>).build();
- Person person = getPerson();
- String json = s.serialize(p); <jc>// Prints "{AGE:45,NAME:'John Smith'}"</jc>
-
- <jc>// Parse back into bean</jc>
- ReaderParser p = JsonParser.<jsm>create</jsm>().beanFilters(MyBeanFilter.<jk>class</jk>).build();
- person = p.parse(json, Person.class); <jc>// Read back into original object</jc>
- </p>
- <p>
- Note that this is equivalent to specifying the following annotation on the bean class:
- </p>
- <p class='bcode'>
- <ja>@Bean</ja>(propertyNamer=UpperCasePropertyNamer.<jk>class</jk>)
- <jk>public class</jk> Person {
- ...
- }
- </p>
-
- <h6 class='topic'>Limiting bean properties to parent bean classes</h6>
- <p>
- Occasionally, you may want to limit bean properties to some parent interface.
- For example, in the <code>RequestEchoResource</code> class in the sample war file, we serialize instances of
- <code>HttpServletRequest</code> and <code>HttpServletResponse</code>.
- However, we really only want to serialize the properties defined on those specific APIs, not
- vendor-specific methods on the instances of those classes.
- This can be done through the <code>interfaceClass</code> property of a bean filter.
- </p>
- <p>
- For example, let's define the following parent class and subclass:
- </p>
- <p class='bcode'>
- <jc>// Abstract parent class</jc>
- <jk>public abstract class</jk> MyClass {
- <jk>public</jk> String <jf>foo</jf>=<js>"foo"</js>;
- }
-
- <jc>// Subclass 1</jc>
- <jk>public class</jk> MyClassBar <jk>extends</jk> MyClass {
- <jk>public</jk> String <jf>bar</jf>=<js>"bar"</js>;
- }
- </p>
- <p>
- Suppose we only want to render the properties defined on <code>MyClass</code>, not those defined on child
- classes.
- To do so, we can define the following bean filter:
- </p>
- <p class='bcode'>
- <jc>// Define bean filter that limits properties to only those defined on MyClass</jc>
- <jk>public class</jk> MyBeanFilter <jk>extends</jk> BeanFilterBuilder {
- <jk>public</jk> MyBeanFilter() {
- <jk>super</jk>(MyClass.<jk>class</jk>);
- interfaceClass(MyClass.<jk>class</jk>);
- }
- }
- </p>
- <p>
- When serialized, the serialized bean will only include properties defined on the parent class.
- </p>
- <p class='bcode'>
- <jc>// Serialize to JSON</jc>
- WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyBeanFilter.<jk>class</jk>).build();
- MyClass c = <jk>new</jk> MyClassBar();
- String json = s.serialize(p); <jc>// Prints "{foo:'foo'}"</jc>
- </p>
- <p>
- The equivalent can be done through an annotation on the parent class, which applies to all child classes:
- </p>
- <p class='bcode'>
- <ja>@Bean</ja>(interfaceClass=MyClass.<jk>class</jk>)
- <jk>public abstract class</jk> MyClass {
- <jk>public</jk> String <jf>foo</jf>=<js>"foo"</js>;
- }
- </p>
- <p>
- The annotation can also be applied on the individual child classes, like so...
- </p>
- <p class='bcode'>
- <ja>@Bean</ja>(interfaceClass=MyClass.<jk>class</jk>)
- <jk>public class</jk> MyClassBar <jk>extends</jk> MyClass {
- <jk>public</jk> String <jf>bar</jf>=<js>"bar"</js>;
- }
- </p>
- <p>
- Also, the <code>beanFilters(...)</code> methods will automatically interpret any
- non-<code>BeanFilter</code> classes passed in as meaning interface classes.
- <br>So in the previous example, the <code>BeanFilter</code> class could have been avoided altogether by just
- passing in <code>MyClass.<jk>class</jk></code> to the serializer, like so:
- </p>
- <p class='bcode'>
- <jc>// Serialize to JSON</jc>
- WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyClass.<jk>class</jk>).build();
- </p>
- <p>
- In fact, this is the shortcut used in the <code>RequestEchoResource</code> sample class:
- </p>
- <p class='bcode'>
- <ja>@RestResource</ja>(
- beanFilters={
- <jc>// Interpret these as their parent classes, not subclasses</jc>
- HttpServletRequest.<jk>class</jk>, HttpSession.<jk>class</jk>, ServletContext.<jk>class</jk>
- }
- )
- <jk>public class</jk> RequestEchoResource <jk>extends</jk> RestServletDefault {
- </p>
-
- <h6 class='topic'>Allowing non-public bean classes/methods/fields to be used by the framework</h6>
- <p>
- By default, only public classes are interpreted as beans. Non-public classes are treated as 'other' POJOs
- that are typically just serialized to strings using the <code>toString()</code> method.
- Likewise, by default, only public fields/methods are interpreted as bean properties.
- </p>
- <p>
- The following bean context properties can be used to allow non-public classes/methods/fields to be
- used by the framework:
- </p>
- <ul>
- <li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanClassVisibility}
- <li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanConstructorVisibility}
- <li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanMethodVisibility}
- <li class='jf'>{@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility}
- </ul>
- <p>
- Also, specifying a {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotation on non-public
- getters/setters/fields will also allow them to be detected by the framework.
- </p>
- <p class='bcode'>
- <jk>public class</jk> MyBean {
- <jc>// A normal bean property</jc>
- <jk>public int</jk> f1;
-
- <jc>// Not a bean property even though it's public</jc>
- <ja>@BeanIgnore</ja>
- <jk>public int</jk> f2;
-
- <jc>// A bean property even though it's protected</jc>
- <ja>@BeanProperty</ja>
- <jk>protected int</jk> f3;
-
- <jc>// A bean property even though it's private</jc>
- <ja>@BeanProperty</ja>
- <jk>private int</jk> getF3() {...}
- }
- </p>
- </div>
-
- <!-- ======================================================================================================== -->
- <a id="PojoSwaps"></a>
- <h3 class='topic' onclick='toggle(this)'>1.2 - PojoSwap Class</h3>
- <div class='topic'>
- <p>
- {@link org.apache.juneau.transform.PojoSwap PojoSwaps} are a critical component of the Juneau architecture.
- They allow the Juneau serializers and parsers to be extended to handle virtually any kind of Java object.
- </p>
- <p>
- As explained in the overview, Juneau has built-in support for serializing and parsing specific kinds of
- objects, like primitive objects, bean, maps, collections, and arrays.
- Other kinds of POJOs, such as {@code Date} objects, cannot be serialized properly, since they are not true
- beans.
- This is where <code>PojoSwaps</code> come into play.
- </p>
- <p>
- The purpose of an <code>PojoSwap</code> is to convert a non-serializable object to a serializable surrogate
- form during serialization, and to optionally convert that surrogate form back into the original object
- during parsing.
- </p>
- <p>
- For example, the following swap can be used to convert {@link java.util.Date} objects to ISO8601 strings
- during serialization, and {@link java.util.Date} objects from ISO8601 string during parsing:
- </p>
- <p class='bcode'>
- <jc>// Sample swap for converting Dates to ISO8601 strings.</jc>
- <jk>public class</jk> MyDateSwap <jk>extends</jk> StringSwap<Date> {
-
- <jc>// ISO8601 formatter.</jc>
- <jk>private</jk> DateFormat <jf>format</jf> = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>);
-
- <jd>/** Converts a Date object to an ISO8601 string. */</jd>
- <ja>@Override</ja>
- <jk>public</jk> String swap(BeanSession session, Date o) {
- <jk>return</jk> <jf>format</jf>.format(o);
- }
-
- <jd>/** Converts an ISO8601 string to a Date object. */</jd>
- <ja>@Override</ja>
- <jk>public</jk> Date unswap(BeanSession session, String o, ClassMeta hint) <jk>throws</jk> ParseException {
- <jk>try</jk> {
- <jk>return</jk> <jf>format</jf>.parse(o);
- } <jk>catch</jk> (java.text.ParseException e) {
- <jk>throw new</jk> ParseException(e);
- }
- }
- }
- </p>
- <p>
- The swap above can then be associated with serializers and parsers as the following example shows:
- </p>
- <p class='bcode'>
- <jc>// Sample bean with a Date field.</jc>
- <jk>public class</jk> MyBean {
- <jk>public</jk> Date <jf>date</jf> = <jk>new</jk> Date(112, 2, 3, 4, 5, 6);
- }
-
- <jc>// Create a new JSON serializer, associate our date swap with it, and serialize a sample bean.</jc>
- Serializer serializer = JsonSerializer.<jsm>create</jsm>().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
- String json = serializer.serialize(<jk>new</jk> MyBean()); <jc>// == "{date:'2012-03-03T04:05:06-0500'}"</jc>
-
- <jc>// Create a JSON parser, associate our date swap with it, and reconstruct our bean (including the date).</jc>
- ReaderParser parser = JsonParser.<jsm>create</jsm>().pojoSwaps(MyDateSwap.<jk>class</jk>).build();
- MyBean bean = parser.parse(json, MyBean.<jk>class</jk>);
- <jk>int</jk> day = bean.<jf>date</jf>.getDay(); <jc>// == 3</jc>
- </p>
- <p>
- In addition, the {@link org.apache.juneau.BeanMap#get(Object)} and
- {@link org.apache.juneau.BeanMap#put(String,Object)} methods will automatically convert to swapped values
- as the following example shows:
- </p>
- <p class='bcode'>
- <jc>// Create a new bean context and add our swap.</jc>
- BeanContext beanContext = <jk>new</jk> BeanContext().pojoSwaps(MyDateSwap.<jk>class</jk>);
-
- <jc>// Create a new bean.</jc>
- MyBean myBean = <jk>new</jk> MyBean();
-
- <jc>// Wrap it in a bean map.</jc>
- BeanMap<Bean> beanMap = beanContext.forBean(myBean);
-
- <jc>// Use the get() method to get the date field as an ISO8601 string.</jc>
- String date = (String)beanMap.get(<js>"date"</js>); <jc>// == "2012-03-03T04:05:06-0500"</jc>
-
- <jc>// Use the put() method to set the date field to an ISO8601 string.</jc>
- beanMap.put(<js>"date"</js>, <js>"2013-01-01T12:30:00-0500"</js>); <jc>// Set it to a new value.</jc>
-
- <jc>// Verify that the date changed on the original bean.</jc>
- <jk>int</jk> year = myBean.<jf>date</jf>.getYear(); <jc>// == 113</jc>
- </p>
- <p>
- Another example of a <code>PojoSwap</code> is one that converts <code><jk>byte</jk>[]</code> arrays to BASE64-encoded strings:
- </p>
- <p class='bcode'>
- <jk>public class</jk> ByteArrayBase64Swap <jk>extends</jk> StringSwap<<jk>byte</jk>[]> {
-
- <ja>@Override</ja>
- <jk>public</jk> String swap(<jk>byte</jk>[] b) <jk>throws</jk> SerializeException {
- <jk>try</jk> {
- ByteArrayOutputStream baos = <jk>new</jk> ByteArrayOutputStream();
- OutputStream b64os = MimeUtility.encode(baos, <js>"base64"</js>);
- b64os.write(b);
- b64os.close();
- <jk>return new</jk> String(baos.toByteArray());
- } <jk>catch</jk> (Exception e) {
- <jk>throw new</jk> SerializeException(e);
- }
- }
-
- <ja>@Override</ja>
- <jk>public byte</jk>[] unswap(String s, ClassMeta<?> hint) <jk>throws</jk> ParseException {
- <jk>try</jk> {
- <jk>byte</jk>[] b = s.getBytes();
- ByteArrayInputStream bais = <jk>new</jk> ByteArrayInputStream(b);
- InputStream b64is = MimeUtility.decode(bais, <js>"base64"</js>);
- <jk>byte</jk>[] tmp = <jk>new byte</jk>[b.length];
- <jk>int</jk> n = b64is.read(tmp);
- <jk>byte</jk>[] res = <jk>new byte</jk>[n];
- System.<jsm>arraycopy</jsm>(tmp, 0, res, 0, n);
- <jk>return</jk> res;
- } <jk>catch</jk> (Exception e) {
- <jk>throw new</jk> ParseException(e);
- }
- }
- }
- </p>
- <p>
- The following example shows the BASE64 swap in use:
- </p>
- <p class='bcode'>
- <jc>// Create a JSON serializer and register the BASE64 encoding swap with it.</jc>
- Serializer serializer = JsonSerializer.<jsm>create</jsm>().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
- ReaderParser parser = JsonParser.<jsm>create</jsm>().pojoSwaps(ByteArrayBase64Swap.<jk>class</jk>).build();
-
- <jk>byte</jk>[] a1 = {1,2,3};
- String s1 = serializer.serialize(a1); <jc>// Produces "'AQID'"</jc>
- a1 = parser.parse(s1, <jk>byte</jk>[].<jk>class</jk>); <jc>// Reproduces {1,2,3}</jc>
-
- <jk>byte</jk>[][] a2 = {{1,2,3},{4,5,6},<jk>null</jk>};
- String s2 = serializer.serialize(a2); <jc>// Produces "['AQID','BAUG',null]"</jc>
- a2 = parser.parse(s2, <jk>byte</jk>[][].<jk>class</jk>); <jc>// Reproduces {{1,2,3},{4,5,6},null}</jc>
- </p>
- <p>
- It should be noted that the sample swaps shown above have already been implemented in the
- <a class='doclink' href='../transforms/package-summary.html#TOC'>org.apache.juneau.transforms</a> package.
- The following are a list of out-of-the-box swaps:
- </p>
- <ul class='spaced-list'>
- <li>{@link org.apache.juneau.transforms.ByteArrayBase64Swap}
- - Converts byte arrays to BASE64 encoded strings.
- <li>{@link org.apache.juneau.transforms.CalendarSwap}
- - Swaps for converting <code>Calendar</code> objects to various date format strings.
- <li>{@link org.apache.juneau.transforms.DateSwap}
- - Swaps for converting <code>Date</code> objects to various date format strings.
- <li>{@link org.apache.juneau.transforms.EnumerationSwap}
- - Swaps for converting <code>Enumeration</code> objects to arrays.
- <li>{@link org.apache.juneau.transforms.IteratorSwap}
- - Swaps for converting <code>Iterator</code> objects to arrays.
- <li>{@link org.apache.juneau.transforms.ReaderSwap}
- - Swaps for converting <code>Readers</code> to objects before serialization.
- <li>{@link org.apache.juneau.transforms.XMLGregorianCalendarSwap}
- - Swaps for converting <code>XMLGregorianCalendar</code> objects to ISO8601 strings.
- </ul>
-
- <h6 class='topic'>Valid swapped class types</h6>
- <p>
- The swapped class type can be any serializable class type as defined in the
- <a href='../../../../overview-summary.html#juneau-marshall.PojoCategories'>POJO categories</a> table.
- </p>
- </div>
-
-
- <!-- ======================================================================================================== -->
- <a id="PojoSwaps_OneWay"></a>
- <h3 class='topic' onclick='toggle(this)'>1.3 - One-Way PojoSwaps</h3>
- <div class='topic'>
- <p>
- In the previous section, we defined two-way swaps, meaning swaps where the original objects could be
- reconstructing during parsing.
- However, there are certain kinds of POJOs that we may want to support for serializing, but that are not
- possible to reconstruct during parsing.
- For these, we can use one-way object swaps.
- </p>
- <p>
- A one-way POJO swap is simply an object transform that only implements the {@code swap()} method.
- The {@code unswap()} method is simply left unimplemented.
- </p>
- <p>
- An example of a one-way swaps would be one that allows {@code Iterators} to be serialized as JSON arrays.
- It can make sense to be able to render {@code Iterators} as arrays, but in general it's not possible to
- reconstruct an {@code Iterator} during parsing.
- </p>
- <p class='bcode'>
- <jk>public class</jk> IteratorSwap <jk>extends</jk> PojoSwap<Iterator,List> {
-
- <ja>@Override</ja>
- <jk>public</jk> List swap(Iterator o) {
- List l = <jk>new</jk> LinkedList();
- <jk>while</jk> (o.hasNext())
- l.add(o.next());
- <jk>return</jk> l;
- }
- }
- </p>
- <p>
- Here is an example of our one-way swap being used.
- Note that trying to parse the original object will cause a {@link org.apache.juneau.parser.ParseException}
- to be thrown.
- </p>
- <p class='bcode'>
- <jc>// Create a JSON serializer that can serialize Iterators.</jc>
- Serializer serializer = JsonSerializer.<jsm>create</jsm>().pojoSwaps(IteratorSwap.<jk>class</jk>).build();
-
- <jc>// Construct an iterator we want to serialize.</jc>
- Iterator iterator = <jk>new</jk> ObjectList(1,2,3).iterator();
-
- <jc>// Serialize our Iterator</jc>
- String s = serializer.serialize(iterator); <jc>// Produces "[1,2,3]"</jc>
-
- <jc>// Try to parse it.</jc>
- ReaderParser parser = JsonParser.<jsm>create</jsm>().pojoSwaps(IteratorSwap.<jk>class</jk>).build();
- iterator = parser.parse(s, Iterator.<jk>class</jk>); <jc>// Throws ParseException!!!</jc>
- </p>
- </div>
-
- <!-- ======================================================================================================== -->
- <a id="StopClasses"></a>
- <h3 class='topic' onclick='toggle(this)'>1.4 - Stop Classes</h3>
- <div class='topic'>
- <p>
- Occasionally, you may want to limit bean properties to only those defined on a parent class or interface.
- There are a couple of ways of doing this.
- </p>
- <p>
- For example, let's define the following parent class and subclass:
- </p>
- <p class='bcode'>
- <jc>// Abstract parent class</jc>
- <jk>public abstract class</jk> MyClass {
- <jk>public</jk> String <jf>foo</jf>=<js>"foo"</js>;
- }
-
- <jc>// Subclass 1</jc>
- <jk>public class</jk> MyClassBar <jk>extends</jk> MyClass {
- <jk>public</jk> String <jf>bar</jf>=<js>"bar"</js>;
- }
- </p>
- <p>
- Suppose we only want to render the properties defined on <code>MyClass</code>, not those defined on
- child classes.
- To do so, we can define the following bean filter:
- </p>
- <p class='bcode'>
- <jc>// Define transform that limits properties to only those defined on MyClass</jc>
- <jk>public class</jk> MyBeanFilter <jk>extends</jk> BeanFilter<MyClass> {
- <jk>public</jk> MyBeanFilter() {
- setInterfaceClass(MyClass.<jk>class</jk>);
- }
- }
- </p>
- <p>
- When serialized, the serialized bean will only include properties defined on the parent class.
- </p>
- <p class='bcode'>
- <jc>// Serialize to JSON</jc>
- WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyBeanFilter.<jk>class</jk>).build();
- MyClass c = <jk>new</jk> MyClassBar();
- String json = s.serialize(p); <jc>// Prints "{foo:'foo'}"</jc>
- </p>
- <p>
- The equivalent can be done through an annotation on the parent class, which applies to all child classes:
- </p>
- <p class='bcode'>
- <ja>@Bean</ja>(interfaceClass=MyClass.<jk>class</jk>)
- <jk>public abstract class</jk> MyClass {
- <jk>public</jk> String <jf>foo</jf>=<js>"foo"</js>;
- }
- </p>
- <p>
- The annotation can also be applied on the individual child classes, like so...
- </p>
- <p class='bcode'>
- <ja>@Bean</ja>(interfaceClass=MyClass.<jk>class</jk>)
- <jk>public class</jk> MyClassBar <jk>extends</jk> MyClass {
- <jk>public</jk> String <jf>bar</jf>=<js>"bar"</js>;
- }
- </p>
- <p>
- Also, the <code>beanFilters()</code> methods will automatically interpret any non-<code>BeanFilter</code>
- classes passed in as meaning interface classes.
- So in the previous example, the <code>BeanFilter</code> class could have been avoided altogether by just
- passing in <code>MyClass.<jk>class</jk></code> to the serializer, like so:
- </p>
- <p class='bcode'>
- <jc>// Serialize to JSON</jc>
- WriterSerializer s = JsonSerializer.<jsm>create</jsm>().beanFilters(MyClass.<jk>class</jk>).build();
- </p>
- </div>
-
- <!-- ======================================================================================================== -->
- <a id="SurrogateClasses"></a>
- <h3 class='topic' onclick='toggle(this)'>1.5 - Surrogate Classes</h3>
- <div class='topic'>
- <p>
- Surrogate classes are very similar in concept to one-way <code>PojoSwaps</code> except they represent a
- simpler syntax.
- </p>
- <p>
- For example, let's say we want to be able to serialize the following class, but it's not serializable for
- some reason (for example, there are no properties exposed):
- <p class='bcode'>
- <jk>public class</jk> MyNonSerializableClass {
- <jk>protected</jk> String <jf>foo</jf>;
- }
- </p>
- <p>
- This could be solved with the following <code>PojoSwap</code>.
- </p>
- <p class='bcode'>
- <jk>public class</jk> MySerializableSurrogate {
- <jk>public</jk> String <jf>foo</jf>;
- }
-
- <jk>public class</jk> MySwap <jk>extends</jk> PojoSwap<MyNonSerializableClass,MySerializableSurrogate> {
-
- <ja>@Override</ja>
- <jk>public</jk> MySerializableSurrogate swap(MyNonSerializableClass o) {
- MySerializableSurrogate s = <jk>new</jk> MySerializableSurrogate();
- s.<jf>foo</jf> = o.<jf>foo</jf>;
- <jk>return</jk> s;
- }
- }
- </p>
- <p>
- However, the same can be accomplished by using a surrogate class that simply contains a constructor with
- the non-serializable class as an argument:
- </p>
- <p class='bcode'>
- <jk>public class</jk> MySerializableSurrogate {
- <jk>public</jk> String <jf>foo</jf>;
-
- <jk>public</jk> MySerializableSurrogate(MyNonSerializableClass c) {
- <jk>this</jk>.<jf>foo</jf> = c.<jf>foo</jf>;
- }
- }
- </p>
- <p>
- The surrogate class is registered in the same way as a <code>PojoSwap</code>:
- </p>
- <p class='bcode'>
- <jc>// Create a JSON serializer that can serialize Iterators.</jc>
- Serializer serializer = JsonSerializer.<jsm>create</jsm>().pojoSwaps(MySerializableSurrogate.<jk>class</jk>).build();
- </p>
- <p>
- When the serializer encounters the non-serializable class, it will serialize an instance of the surrogate
- instead.
- </p>
- </div>
-
- <!-- ======================================================================================================== -->
- <a id="ToObjectMaps"></a>
- <h3 class='topic' onclick='toggle(this)'>1.6 - Serializing to ObjectMaps</h3>
- <div class='topic'>
- <p>
- A shortcut method for transforming is provided that can often be simpler than defining transforms.
- In this case, we add methods to our class to serialize to {@link org.apache.juneau.ObjectMap ObjectMaps}
- </p>
- <p>
- <p class='bcode'>
- <jk>public class</jk> MyClass {
- <jk>private</jk> String <jf>f1</jf>;
-
- <jc>// Constructor that takes in an ObjectMap</jc>
- <jk>public</jk> MyClass(ObjectMap m) {
- <jf>f1</jf> = m.getString(<js>"f1"</js>);
- }
-
- <jc>// Method that converts object to an ObjectMap</jc>
- <jk>public</jk> ObjectMap toObjectMap() {
- <jk>return new</jk> ObjectMap().append(<js>"f1"</js>, <jf>f1</jf>);
- }
- </p>
- <p>
- The <code>toObjectMap()</code> method will automatically be used during serialization, and
- the constructor will automatically be used during parsing.
- This will work for all serializers and parsers.
- </p>
- </div>
-</div>
</body>
</html>
\ No newline at end of file