From commits-return-5186-archive-asf-public=cust-asf.ponee.io@juneau.apache.org Wed Mar 7 16:54:10 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 5FFBB180656 for ; Wed, 7 Mar 2018 16:54:05 +0100 (CET) Received: (qmail 84262 invoked by uid 500); 7 Mar 2018 15:54:04 -0000 Mailing-List: contact commits-help@juneau.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@juneau.apache.org Delivered-To: mailing list commits@juneau.apache.org Received: (qmail 84253 invoked by uid 99); 7 Mar 2018 15:54:04 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 07 Mar 2018 15:54:04 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id 820078279A; Wed, 7 Mar 2018 15:54:03 +0000 (UTC) Date: Wed, 07 Mar 2018 15:54:03 +0000 To: "commits@juneau.apache.org" Subject: [juneau] branch master updated: Javadoc updates. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <152043804341.11327.7433482590200129895@gitbox.apache.org> From: jamesbognar@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: juneau X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 220e60831f746b3d30b83a1e2a86c72ef8072a39 X-Git-Newrev: 7227412444295b531f03e6967e629b08edf73087 X-Git-Rev: 7227412444295b531f03e6967e629b08edf73087 X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated This is an automated email from the ASF dual-hosted git repository. jamesbognar pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/juneau.git The following commit(s) were added to refs/heads/master by this push: new 7227412 Javadoc updates. 7227412 is described below commit 7227412444295b531f03e6967e629b08edf73087 Author: JamesBognar AuthorDate: Wed Mar 7 10:54:01 2018 -0500 Javadoc updates. --- juneau-doc/src/main/javadoc/overview.html | 2184 +++++++++----------- .../src/main/javadoc/resources/juneau-code.css | 10 + .../examples/rest/htdocs/code-highlighting.css | 136 -- 3 files changed, 1002 insertions(+), 1328 deletions(-) diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html index 9c8ca85..984a9af 100644 --- a/juneau-doc/src/main/javadoc/overview.html +++ b/juneau-doc/src/main/javadoc/overview.html @@ -483,7 +483,7 @@

The library consists of the following artifacts found in the Maven group "org.apache.juneau":

- +
@@ -660,7 +660,7 @@
Maven Dependency
-

+

<dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-marshall</artifactId> @@ -669,12 +669,12 @@

Java Library
-

+

juneau-marshall-7.1.0.jar

OSGi Module
-

+

org.apache.juneau.marshall_7.1.0.jar

@@ -704,7 +704,7 @@

In most cases, you can serialize objects in one line of code by using one of the default serializers:

-

+

// A simple bean public class Person { public String name = "John Smith"; @@ -750,7 +750,7 @@ In addition to the default serializers, customized serializers can be created using various built-in options:

-

+

// Use one of the default serializers to serialize a POJO String json = JsonSerializer.DEFAULT.serialize(someObject); @@ -783,7 +783,7 @@

Like the serializers, you can often parse objects in one line of code by using one of the default parsers:

-

+

// Use one of the predefined parsers. Parser parser = JsonParser.DEFAULT; @@ -820,7 +820,7 @@

The parsers can also be used to populating existing bean and collection objects:

-

+

// Use one of the predefined parsers. Parser parser = JsonParser.DEFAULT; @@ -860,7 +860,7 @@ These classes allow serializers and parsers to be retrieved by W3C-compliant HTTP Accept and Content-Type values...

-

+

// Construct a new serializer group with configuration parameters that get applied to all serializers. SerializerGroup sg = SerializerGroup.create() .append(JsonSerializer.class, UrlEncodingSerializer.class); @@ -944,7 +944,7 @@ (In theory, any valid XML can also be parsed into an unstructured model, although this has not been officially 'tested')

-

+

// Parse an arbitrary JSON document into an unstructered data model // consisting of ObjectMaps, ObjectLists, and java primitive objects. Parser parser = JsonParser.DEFAULT; @@ -966,7 +966,7 @@

The ObjectMap and ObjectList classes have many convenience features:

-

+

// Convert the map to a bean. MyBean m = objectMap.cast(MyBean.class); @@ -1010,7 +1010,7 @@ new instances from scratch or build upon existing instances.
For example, the following code shows how to configure a JSON serializer:

-

+

WriterSerializer s = JsonSerializer .create() // Create a JsonSerializerBuilder .simple() // Simple mode @@ -1022,7 +1022,7 @@ Configurable settings can also be set declaratively.
The following produces the same serializer.

-

+

WriterSerializer s = JsonSerializer .create() .set(JSON_simpleMode, true) @@ -1054,7 +1054,7 @@

These can be used directly, as follows:

-

+

// Serialize a POJO to LAX JSON. String json = JsonSerializer.DEFAULT_LAX.serialize(myPojo);

@@ -1062,7 +1062,7 @@ For performance reasons, serializers and parsers are immutable. However, they can be 'copied' and modified using the builder() method.

-

+

// Clone and customize an existing serializer. WriterSerializer s = JsonSerializer.DEFAULT_LAX .builder() // Create a new builder with copied settings. @@ -1270,7 +1270,7 @@ For example, two serializers of the same type created with the same configuration will always end up being the same serializer:

-

+

// Two serializers created with identical configurations will always be the same copy. WriterSerializer s1 = JsonSerializer.create().pojoSwaps(MySwap.class).simple().build(); WriterSerializer s2 = JsonSerializer.create().set(JSON_simpleMode, true).pojoSwaps(MySwap.class).build(); @@ -1287,7 +1287,7 @@

In the example above, the property store being built looks like the following:

-

+

PropertyStore ps = PropertyStore .create() .set("BeanContext.pojoSwaps.lc", MySwap.class) @@ -1386,7 +1386,7 @@ In the following example, we introduce a PojoSwap that will swap in ISO8601 strings for Date objects:

-

+

// Sample swap for converting Dates to ISO8601 strings. public class MyDateSwap extends PojoSwap<Date,String> { @@ -1409,7 +1409,7 @@

The swap can then be associated with serializers and parsers like so:

-

+

// Sample bean with a Date field. public class MyBean { public Date date = new Date(112, 2, 3, 4, 5, 6); @@ -1428,7 +1428,7 @@ 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:

-

+

// Create a new bean context and add our swap. BeanContext bc = BeanContext.create().pojoSwaps(MyDateSwap.class).build(); @@ -1451,7 +1451,7 @@ Another example of a PojoSwap is one that converts byte[] arrays to BASE64-encoded strings:

-

+

public class ByteArrayBase64Swap extends StringSwap<byte[]> { @Override /* StringSwap */ @@ -1479,7 +1479,7 @@

The following example shows the BASE64 swap in use:

-

+

// Create a JSON serializer and register the BASE64 encoding swap with it. WriterSerializer s = JsonSerializer.create().simple().pojoSwaps(ByteArrayBase64Swap.class).build(); ReaderParser p = JsonParser.create().pojoSwaps(ByteArrayBase64Swap.class).build(); @@ -1555,7 +1555,7 @@ In the following example, we define 3 swaps against the same POJO. One for JSON, one for XML, and one for all other types.

-

+

public class PojoSwapTest { public static class MyPojo {} @@ -1637,7 +1637,7 @@
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.

-

+

public class IteratorSwap extends PojoSwap<Iterator,List> { @Override /* PojoSwap */ public List swap(Iterator o) { @@ -1653,7 +1653,7 @@
Note that trying to parse the original object will cause a {@link org.apache.juneau.parser.ParseException} to be thrown.

-

+

// Create a JSON serializer that can serialize Iterators. WriterSerializer s = JsonSerializer.create().simple().pojoSwaps(IteratorSwap.class).build(); @@ -1679,7 +1679,7 @@
This is often cleaner than using the builder pojoSwaps() method since you can keep your swap class near your POJO class.

-

+

@Swap(MyPojoSwap.class) public class MyPojo { ... @@ -1697,7 +1697,7 @@

Multiple swaps can be associated with a POJO by using the {@link org.apache.juneau.annotation.Swaps @Swaps} annotation:

-

+

@Swaps( { @Swap(MyJsonSwap.class), @@ -1711,7 +1711,7 @@ Readers get serialized directly to the output of a serializer. Therefore it's possible to implement a swap that provides fully-customized output.

-

+

public class MyJsonSwap extends PojoSwap<MyPojo,Reader> { public MediaType[] forMediaTypes() { @@ -1727,7 +1727,7 @@ The @Swap annotation can also be used on getters and setters as well to apply a swap to individual property values

-

+

@BeanProperty(swap=MyPojoSwap.class) public MyPojo getMyPojo();

@@ -1747,14 +1747,14 @@

For example, you could pair a template string like so:

-

+

@Swap(impl=FreeMarkerSwap.class, template="MyPojo.div.ftl") public class MyPojo {}

The implementation of the FreeMarker swap would look something like this:

-

+

// Our templated swap class. public class FreeMarkerSwap extends PojoSwap<Object,Reader> { @@ -1836,7 +1836,7 @@ The following example shows how an HTML5 form template object can be created that gets serialized as a populated HTML5 {@link org.apache.juneau.dto.html5.Form} bean.

-

+

import static org.apache.juneau.dto.html5.HtmlBuilder.*; /** @@ -1877,7 +1877,7 @@ The following shows how our form template class can be modified to allow the parsers to reconstruct our original object:

-

+

import static org.apache.juneau.dto.html5.HtmlBuilder.*; /** @@ -1927,7 +1927,7 @@

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): -

+

// Not serializable because it's not a bean because it has no public properties. public class MyNonSerializableClass { protected String foo; @@ -1936,7 +1936,7 @@

This could be solved with the following PojoSwap.

-

+

// A serializable bean with 1 property. public class MySerializableSurrogate { public String foo; @@ -1958,7 +1958,7 @@ However, the same can be accomplished by using a surrogate class that simply contains a constructor with the non-serializable class as an argument:

-

+

public class MySerializableSurrogate { public String foo; @@ -1971,7 +1971,7 @@

The surrogate class is registered in the same way as a PojoSwap:

-

+

// Create a JSON serializer that can serialize Iterators. WriterSerializer s = JsonSerializer.create().pojoSwaps(MySerializableSurrogate.class).build();

@@ -1998,7 +1998,7 @@ Bean property inclusion and ordering on a bean class can be done using the {@link org.apache.juneau.annotation.Bean#properties() @Bean.properties()} annotation.

-

+

// Address class with only street/city/state properties (in that order). // All other properties are ignored. @Bean(properties="street,city,state") @@ -2008,7 +2008,7 @@ Bean properties can be excluded using the {@link org.apache.juneau.annotation.Bean#excludeProperties() @Bean.excludeProperties()} annotation.

-

+

// Address class with only street/city/state properties (in that order). // All other properties are ignored. @Bean(excludeProperties="city,state"}) @@ -2017,7 +2017,7 @@

Bean properties can be sorted alphabetically using {@link org.apache.juneau.annotation.Bean#sort() @Bean.sort()}

-

+

// Address class with only street/city/state properties (in that order). // All other properties are ignored. @Bean(sort=true) @@ -2033,7 +2033,7 @@ dashed-lowercase, and these will be used as attribute names in JSON and element names in XML.

-

+

// Define a class with dashed-lowercase property names. @Bean(propertyNamer=PropertyNamerDashedLC.class) public class MyBean { ... } @@ -2045,7 +2045,7 @@ serialization.
Additional properties on subclasses will be ignored.

-

+

// Parent class @Bean(interfaceClass=A.class) public abstract class A { @@ -2076,7 +2076,7 @@ For example, in the following class hierarchy, instances of C3 will include property p3, but not p1 or p2.

-

+

public class C1 { public int getP1(); } @@ -2095,7 +2095,7 @@ and {@link org.apache.juneau.transform.PropertyFilter} class can be used to perform interception and inline handling of bean getter and setter calls.

-

+

// Register filter on bean class. @Bean(propertyFilter=AddressPropertyFilter.class) public class Address { @@ -2136,7 +2136,7 @@ The {@link org.apache.juneau.annotation.BeanProperty#name() @BeanProperty.name()} annotation is used to override the name of the bean property.

-

+

public class MyBean { @BeanProperty(name="Bar") public String getFoo() {...} @@ -2147,7 +2147,7 @@ (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.

-

+

public class MyBean { @BeanProperty protected String getFoo() {...} @@ -2164,7 +2164,7 @@

The following shows various ways of using dynamic bean properties.

-

+

// Option #1 - A simple public Map field. // The field name can be anything. public class BeanWithDynaField { @@ -2204,7 +2204,7 @@ Similar rules apply for value types and swaps.
The property values optionally can be any serializable type or use swaps.

-

+

// A serializable type other than Object. public class BeanWithDynaFieldWithListValues { @@ -2237,7 +2237,7 @@

The following annotations are equivalent:

-

+

@BeanProperty(name="foo") @BeanProperty("foo") @@ -2253,7 +2253,7 @@

This property must denote a concrete class with a no-arg constructor.

-

+

public class MyBean { // Identify concrete type as a HashMap. @@ -2266,7 +2266,7 @@
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.

-

+

public class MyBean { // This is a HashMap<String,Integer>. @@ -2285,7 +2285,7 @@

  • Bean/Map arrays - Same, but applied to each element in the array.
  • Bean/Map collections - Same, but applied to each element in the collection. -

    +

    public class MyClass { // Only render 'f1' when serializing this bean property. @@ -2305,7 +2305,7 @@ 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.

    -

    +

    // Serialize a float as a string with 2 decimal places. @BeanProperty(format="$%.2f") public float price; @@ -2325,7 +2325,7 @@

    The definition of a read-only bean is a bean with properties with only getters, like shown below:

    -

    +

    // Our read-only bean. public class Person { private final String name; @@ -2349,7 +2349,7 @@ } }

    -

    +

    // Parsing into a read-only bean. String json = "{name:'John Smith',age:45}"; Person p = JsonParser.DEFAULT.parse(json); @@ -2372,7 +2372,7 @@

    When applied to classes, objects will be converted to strings even though they look like beans.

    -

    +

    // Not really a bean! Use toString() instead! @BeanIgnore public class MyBean {...} @@ -2380,7 +2380,7 @@

    When applied to fields and getters/setters, they will be ignored as bean properties.

    -

    +

    public class MyBean { // Not a bean property! @@ -2406,14 +2406,14 @@ 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.

    -

    +

    // JSON { id1: {name: 'John Smith', sex:'M'}, id2: {name: 'Jane Doe', sex:'F'} }

    -

    +

    public class Person { @NameProperty @@ -2437,7 +2437,7 @@

    A commonly-used case is when you're parsing beans and a child bean has a reference to a parent bean.

    -

    +

    public class AddressBook { public List<Person> people; } @@ -2470,13 +2470,13 @@

    A typical builder usage is shown below:

    -

    +

    MyBean b = MyBean.create().foo("foo").bar(123).build();

    The code for such a builder is shown below:

    -

    +

    public class MyBean { // Read-only properties. @@ -2537,17 +2537,17 @@

    • A static create() method on the POJO class that returns a builder instance. -

      +

      public static MyBuilder create() {...}

    • A public constructor on the POJO class that takes in a single parameter that implements the {@link org.apache.juneau.transform.Builder} interface.
      The builder class must have a public no-arg constructor. -

      +

      public MyPojo(MyBuilder b) {...}

    • A {@link org.apache.juneau.annotation.Builder @Builder} annotation on the POJO class.
      The builder class must have a public no-arg constructor. -

      +

      @Builder(MyBuilder.class) public class MyPojo {...}

      @@ -2557,11 +2557,11 @@

      • The existence of a build() method on the builder class. -

        +

        public MyPojo build() {...}

      • The existence of a public constructor on the POJO class that takes in the builder instance. -

        +

        public MyPojo(MyBuilder b) {...}

      @@ -2582,7 +2582,7 @@

      The following example shows a bean containing URIs of various forms and how they end up serialized.

      -

      +

      // Our bean with properties containing various kinds of URIs. public class TestURIs { public URI @@ -2677,7 +2677,7 @@ properties and class types so that they also get interpreted as URIs.
      For example:

      -

      +

      // Applied to a class whose toString() method returns a URI. @URI public class MyURI { @@ -2721,14 +2721,14 @@

      In the previous examples, we defined this bean annotation:

      -

      +

      @Bean(properties="street,city,state") public class Address { ... }

      The programmatic equivalent would be:

      -

      +

      public class AddressFilter extends BeanFilterBuilder<Address> { // Must provide a no-arg constructor! @@ -2747,7 +2747,7 @@

      For example:

      -

      +

      // Create a new JSON serializer and associate a bean filter with it. WriterSerializer s = JsonSerializer .create() @@ -2765,7 +2765,7 @@
      These cause bean implementations of those interfaces to only expose the properties defined on the interface.

      -

      +

      // An interface with the 3 properties we want serialized. public interface AddressInterface { public String getStreet(); @@ -2809,7 +2809,7 @@

      For example, let's define the following interface and implementation:

      -

      +

      // Interface public class MyInterface { public String getFoo(); @@ -2825,7 +2825,7 @@ Suppose we only want to render the properties defined on our interface, not the implementation.
      To do so, we can define the following bean filter:

      -

      +

      // Define transform that limits properties to only those defined on MyClass public class MyInterfaceFilter extends BeanFilter<MyInterface> { public MyInterfaceFilter() { @@ -2836,7 +2836,7 @@

      When serialized, the serialized bean will only include properties defined on the interface.

      -

      +

      WriterSerializer s = JsonSerializer .create() .simple() @@ -2855,7 +2855,7 @@
      So in the previous example, the BeanFilter class could have been avoided altogether by just passing in MyInterface.class to the serializer, like so:

      -

      +

      WriterSerializer s = JsonSerializer .create() .beanFilters(MyInterface.class) Shortcut! @@ -2864,7 +2864,7 @@

      The annotation equivalent is {@link org.apache.juneau.annotation.Bean#interfaceClass() Bean#interfaceClass()}.

      -

      +

      @Bean(interfaceClass=MyInterface.class) public class MyInterfaceImpl implements MyInterface { public String getFoo() {...} @@ -2877,7 +2877,7 @@

      Using the annotation on an interface will be inherited by all children.

      -

      +

      @Bean(interfaceClass=MyInterface.class) public class MyInterface { public String getFoo(); @@ -2886,7 +2886,7 @@

      The annotation can be used on parent classes as well.
      Child beans will only serialize properties defined on the parent class. -

      +

      @Bean(interfaceClass=MyAbstractClass.class) public abstract class MyAbstractClass { public String getFoo() {...}; @@ -2917,7 +2917,7 @@ For example, in the following class hierarchy, instances of C3 will include property p3, but not p1 or p2.

      -

      +

      public class C1 { public int getP1(); } @@ -2945,7 +2945,7 @@ simply serializing their contents directly to the output stream or writer.
      This allows you to embed fully customized serializer output.

      -

      +

      public class MyBean { // A bean property that produces raw JSON. public Reader f1 = new StringReader("{'foo':'bar'}"); @@ -2964,7 +2964,7 @@
      In the following example, we're customizing the JSON output for a particular bean type, but leaving all other renditions as-is:

      -

      +

      @Swap(MyBeanSwapSometimes.class) public class MyBean {...} @@ -3017,7 +3017,7 @@ For example, if a bean property is of type Object, then the serializer will add "_type" attributes so that the class can be determined during parsing.

      -

      +

      @Bean(typeName="foo") public class Foo { // A bean property where the object types cannot be inferred since it's an Object[]. @@ -3035,7 +3035,7 @@ When serialized as JSON, "_type" attributes would be added when needed to infer the type during parsing:

      -

      +

      { x: [ {_type:'bar'}, @@ -3052,7 +3052,7 @@

      When serialized as XML, the bean is rendered as:

      -

      +

      <foo> <x> <bar/> @@ -3082,7 +3082,7 @@

    • Any subclass of {@link org.apache.juneau.BeanDictionaryMap} containing a mapping of type names to classes without type name annotations.
    • Any array or collection of the objects above.
    -

    +

    // Create a parser and tell it which classes to try to resolve. ReaderParser p = JsonParser .create() @@ -3117,7 +3117,7 @@ When using the annotation, you'll typically want to define it on an interface class so that it can be inherited by all subclasses.

    -

    +

    @Bean(typePropertyName="mytype", beanDictionary={MyClass1.class,MyClass2.class}) public interface MyInterface {...} @@ -3164,7 +3164,7 @@

    In the following example, the abstract class has two subclasses:

    -

    +

    // Abstract superclass @Bean( beanDictionary={A1.class, A2.class} @@ -3188,7 +3188,7 @@

    When serialized, the subtype is serialized as a virtual "_type" property:

    -

    +

    JsonSerializer s = JsonSerializer.DEFAULT_LAX; A1 a1 = new A1(); a1.f1 = "f1"; @@ -3198,7 +3198,7 @@

    The following shows what happens when parsing back into the original object.

    -

    +

    JsonParser p = JsonParser.DEFAULT; A a = p.parse(r, A.class); assertTrue(a instanceof A1); @@ -3217,7 +3217,7 @@

    For example, the following code creates an instance of the specified unimplemented interface:

    -

    +

    // Our unimplemented interface public interface Address { @@ -3254,7 +3254,7 @@

    Virtual beans can also be created programmatically using the BeanContext class:

    -

    +

    Address address = BeanContext.DEFAULT.createSession().newBean(Address.class);

  • @@ -3279,7 +3279,7 @@

    For example, let's make a POJO model out of the following classes:

    -

    +

    public class A { public B b; } @@ -3295,7 +3295,7 @@

    Now we create a model with a loop and serialize the results.

    -

    +

    // Clone an existing serializer and set property for detecting recursions. JsonSerializer s = JsonSerializer.DEFAULT_LAX_READABLE.builder().detectRecursions(true).build(); @@ -3311,7 +3311,7 @@

    What we end up with is the following, which does not serialize the contents of the c field:

    -

    +

    { b: { c: { @@ -3354,7 +3354,7 @@

    For example, given the following JSON:

    -

    +

    { id: 1, name: 'John Smith', @@ -3378,7 +3378,7 @@

    We can parse this into a generic ObjectMap:

    -

    +

    // Parse JSON into a generic POJO model. ObjectMap m = JsonParser.DEFAULT.parse(json, ObjectMap.class); @@ -3390,7 +3390,7 @@
    Even the numbers and booleans are preserved because they are parsed into Number and Boolean objects when parsing into generic models.

    -

    +

    { id: 1, name: 'John Smith', @@ -3415,7 +3415,7 @@ Once parsed into a generic model, various convenience methods are provided on the ObjectMap and ObjectList classes to retrieve values:

    -

    +

    // Parse JSON into a generic POJO model. ObjectMap m = JsonParser.DEFAULT.parse(json, ObjectMap.class); @@ -3463,7 +3463,7 @@ parsed POJO.

    Examples:
    -

    +

    // If you're calling parse on the same input multiple times, use a session instead of the parser directly. ReaderParserSession p = JsonParser.create().unbuffered().build().createSession(); Object x; @@ -3509,7 +3509,7 @@

    Annotations
    -
    CategoryMaven ArtifactsDescriptionPrerequisites
    +
    JacksonJuneau
    @@ -3615,7 +3615,7 @@

    The following chart shows POJOs categorized into groups and whether they can be serialized or parsed:

    - +
    @@ -3888,7 +3888,7 @@ The following example shows JSON for a typical bean:

    Sample Beans
    -

    +

    public class Person { // Bean properties @@ -3911,7 +3911,7 @@ }

    Sample Code
    -

    +

    Person p = new Person() .name("John Smith") .birthDate("1946-08-12T00:00:00Z") @@ -3925,7 +3925,7 @@ );

    Normal JSON
    -

    +

    { "name": "John Smith", "birthDate": "1946-08-12T00:00:00Z", @@ -3941,7 +3941,7 @@ }

    Lax JSON
    -

    +

    { name: 'John Smith', birthDate: '1946-08-12T00:00:00Z', @@ -3976,7 +3976,7 @@

    Data type conversions:
    -
    GroupDescriptionExamplesCan
    serialize?
    Can
    parse?
    1
    +
    @@ -4125,7 +4125,7 @@ The annotation can be applied to beans as well as other objects serialized to other types (e.g. strings).

    Example:
    -

    +

    @Json(wrapperAttr="personBean") public class Person { public String name = "John Smith"; @@ -4134,7 +4134,7 @@

    The following shows the JSON representation with and without the annotation present:

    -
    POJO type JSON type
    +
    @@ -4172,7 +4172,7 @@ schema serializer may be subject to future modifications.

    Sample Beans
    -

    +

    public class Person { // Bean properties @@ -4197,7 +4197,7 @@

    The code for creating our POJO model and generating JSON-Schema is shown below:

    -

    +

    // Get the schema serializer for one of the default JSON serializers. JsonSchemaSerializer s = JsonSerializer.DEFAULT_LAX_READABLE.getSchemaSerializer(); @@ -4206,7 +4206,7 @@

    JSON Schema
    -

    +

    { type: 'object', description: 'org.apache.juneau.sample.Person', @@ -4273,7 +4273,7 @@ The following example shows XML for a typical bean:

    Sample Beans
    -

    +

    @Bean(typeName="person") public class Person { @@ -4298,7 +4298,7 @@ }

    Sample Code
    -

    +

    Person p = new Person() .name("John Smith") .birthDate("1946-08-12T00:00:00Z") @@ -4312,7 +4312,7 @@ );

    Normal XML:
    -

    +

    <person> <name>John Smith</name> <birthDate>1946-08-12T04:00:00Z</birthDate> @@ -4347,7 +4347,7 @@

    The representation of loose (not a direct bean property value) simple types are shown below:

    -
    Without annotation With annotation
    +
    @@ -4388,7 +4388,7 @@ _type attributes are added to bean properties or map entries if the type cannot be inferred through reflection (e.g. an Object or superclass/interface value type).

    -
    Data type JSON example
    +
    @@ -4459,7 +4459,7 @@

    Loose collections and arrays use the element <array> for encapsulation.

    -
    Data type JSON example
    +
    @@ -4636,7 +4636,7 @@
    Data type JSON example
    Beans
    - +
    @@ -4691,7 +4691,7 @@
    Data type JSON example
    Beans with Map properties
    - +
    @@ -4836,7 +4836,7 @@
    Example
    -
    Data type JSON example
    +
    @@ -4881,7 +4881,7 @@

    Example
    -
    Data type JSON example
    +
    @@ -4943,7 +4943,7 @@

    Examples
    -
    Java Without annotation
    +
    @@ -5056,7 +5056,7 @@ Bean type names are also used for resolution when abstract fields are used.
    The following examples show how they are used in a variety of circumstances.

    -
    Java XML
    +
    @@ -5262,7 +5262,7 @@ '\b' and '\f' cannot be encoded in XML 1.0 at all without inventing our own notation.
    Whitespace characters in element names are encoded as well as whitespace end characters in text.

    -
    Java XML
    +
    @@ -5315,7 +5315,7 @@

    Example
    -
    Java XML
    +
    @@ -5411,7 +5411,7 @@

    Example
    -
    Data type JSON example
    +
    @@ -5446,7 +5446,7 @@

    Example
    -
    Data type JSON example
    +
    @@ -5485,7 +5485,7 @@

    Example
    -
    Data type JSON example
    +
    @@ -5529,7 +5529,7 @@

    Example
    -
    Data type JSON example
    +
    @@ -5576,7 +5576,7 @@ to differentiate which collection the values came from if you plan on parsing the output back into beans.
    Note that child names must not conflict with other property names.

    -
    Data type JSON example
    +
    @@ -5626,7 +5626,7 @@
    It allows free-form child elements to be formed.
    All other properties on the bean MUST be serialized as attributes.

    -
    Data type JSON example
    +
    @@ -5689,7 +5689,7 @@ The {@link org.apache.juneau.xml.annotation.XmlFormat#MIXED} format is similar to {@link org.apache.juneau.xml.annotation.XmlFormat#ELEMENTS} except elements names on primitive types (string/number/boolean/null) are stripped from the output. - This format particularly useful when combined with bean dictionaries to produce mixed content. +
    This format particularly useful when combined with bean dictionaries to produce mixed content.
    The bean dictionary isn't used during serialization, but it is needed during parsing to resolve bean types.

    @@ -5698,7 +5698,7 @@ {@link org.apache.juneau.xml.annotation.XmlFormat#MIXED} except whitespace characters are preserved in the output.

    -
    Data type JSON example
    +
    @@ -5758,26 +5758,26 @@
    Data type JSON example

    Whitespace (tabs and newlines) are not added to MIXED child nodes in readable-output mode. - This helps ensures strings in the serialized output can be losslessly parsed back into their original +
    This helps ensures strings in the serialized output can be losslessly parsed back into their original forms when they contain whitespace characters. - If the {@link javax.xml.stream.XMLInputFactory#IS_REPLACING_ENTITY_REFERENCES} setting was not useless +
    If the {@link javax.xml.stream.XMLInputFactory#IS_REPLACING_ENTITY_REFERENCES} setting was not useless in Java, we could support lossless readable XML for MIXED content. - But as of Java 8, it still does not work. +
    But as of Java 8, it still does not work.

    XML suffers from other deficiencies as well that affect MIXED content. - For example, <X></X> and <X/> are equivalent in XML and +
    For example, <X></X> and <X/> are equivalent in XML and indistinguishable by the Java XML parsers. - This makes it impossible to differentiate between an empty element and an element containing an empty +
    This makes it impossible to differentiate between an empty element and an element containing an empty string. - This causes empty strings to get lost in translation. - To alleviate this, we use the constructs "_xE000_" to represent an empty string, and +
    This causes empty strings to get lost in translation. +
    To alleviate this, we use the constructs "_xE000_" to represent an empty string, and "_x0020_" to represent leading and trailing spaces.

    The examples below show how whitespace is handled under various circumstances:

    - +
    @@ -6040,7 +6040,7 @@
    The {@link org.apache.juneau.xml.annotation.XmlFormat#TEXT_PWS} is the same except whitespace is preserved in the output.

    -
    Data type XML
    +
    @@ -6078,7 +6078,7 @@ XML before being set as the property value. This process may not be perfect (e.g. double quotes may be replaced by single quotes, etc...).

    -
    Data type JSON example
    +
    @@ -6112,72 +6112,45 @@

    2.16.7- Namespaces

    - Let's go back to the example of our original Person bean class: + Let's go back to the example of our original Person bean class, but add some namespace annotations:

    -

    +

    Sample Beans
    +

    + @Xml(prefix="per") + @Bean(typeName="person") public class Person { + // Bean properties - public int id; public String name; - - // Bean constructor (needed by parser) - public Person() {} - - // Normal constructor - public Person(int id, String name) { - this.id = id; - this.name = name; - } + @Swap(CalendarSwap.ISO8601DTZ.class) public Calendar birthDate; + public List<Address> addresses; + + // Getters/setters omitted } -

    -

    - However, this time we'll leave namespaces enabled on the serializer: -

    -

    - // Create a new serializer with readable output, this time with namespaces enabled. - // Note that this is identical to XmlSerializer.DEFAULT_NS_SQ_READABLE. - XmlSerializer s = XmlSerializer.create().ns().ws().sq().build(); + + @Xml(prefix="addr") + @Bean(typeName="address") + public class Address { - // Create our bean. - Person p = new Person(1, "John Smith"); + // Bean properties + @Xml(prefix="mail") public String street, city; + @Xml(prefix="mail") public StateEnum state; + @Xml(prefix="mail") public int zip; + public boolean isCurrent; - // Serialize the bean to XML. - String xml = s.serialize(p); -

    -

    - Now when we run this code, we'll see namespaces added to our output: -

    -

    - <object - xmlns='http://www.apache.org/2013/Juneau'> - <id>1</id> - <name>John Smith</name> - </object> -

    -

    - This isn't too exciting yet since we haven't specified any namespaces yet. -
    Therefore, everything is defined under the default Juneau namespace. -

    -

    - Namespaces can be defined at the following levels: -

    -
      -
    • - At the package level by using the {@link org.apache.juneau.xml.annotation.XmlSchema @XmlSchema} - annotation. -
    • - At the class level by using the {@link org.apache.juneau.xml.annotation.Xml @Xml} annotation. -
    • - At the bean property level by using the {@link org.apache.juneau.xml.annotation.Xml @Xml} annotation. -
    -

    - It's typically best to specify the namespaces used at the package level. -
    We'll do that here for the package containing our test code. -

    -

    - // XML namespaces used in this package + // Getters/setters omitted + } +

    +

    + The namespace URLs can either be defined as part of the {@link org.apache.juneau.xml.annotation.Xml @Xml} + annotation, or can be defined at the package level with the {@link org.apache.juneau.xml.annotation.XmlSchema @XmlSchema} + annotation. +
    Below shows it defined at the package level: +

    +
    package-info.java
    +

    @XmlSchema( - prefix="ab", + prefix="ab", // Default namespace xmlNs={ @XmlNs(prefix="ab", namespaceURI="http://www.apache.org/addressBook/"), @XmlNs(prefix="per", namespaceURI="http://www.apache.org/person/"), @@ -6186,52 +6159,75 @@ } ) package org.apache.juneau.examples.addressbook; - import org.apache.juneau.xml.annotation.*; -

    -

    - We're defining four namespaces in this package and designating "http://www.apache.org/addressBook/" - as the default namespace for all classes and properties within this package. -

    -

    - Take special note that the @XmlSchema is modeled after the equivalent JAXB annotation, but is - defined in the {@link org.apache.juneau.xml.annotation} package. -
    Other XML annotations are also modeled after JAXB. - However, since many of the features of JAXB are already implemented for all serializers and parsers - at a higher level through various general annotations such as {@link org.apache.juneau.annotation.Bean @Bean} - and {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} it was decided to maintain separate Juneau XML - annotations instead of reusing JAXB annotations. -
    This may change in some future implementation, but for now it was decided that having separate Juneau XML - annotations was less confusing. -

    +

    +
    Sample Code
    +

    + Person p = new Person() + .name("John Smith") + .birthDate("1946-08-12T00:00:00Z") + .addresses( + new Address() + .street("100 Main Street") + .city("Anywhereville") + .state(NY) + .zip(12345) + .isCurrent(true); + ); + + // Create a new serializer with readable output, this time with namespaces enabled. + // Note that this is identical to XmlSerializer.DEFAULT_NS_SQ_READABLE. + XmlSerializer s = XmlSerializer.create().ns().ws().sq().build(); + + String xml = s.serialize(p); +

    - On our bean class, we'll specify to use the "http://www.apache.org/person/" namespace: + Now when we run this code, we'll see namespaces added to our output:

    -

    - @Xml(prefix="per") - @Bean(typeName="person") - public class Person { - ... +

    + <per:person> + <per:name>John Smith</per:name> + <per:birthDate>1946-08-12T04:00:00Z</per:birthDate> + <per:addresses> + <addr:address> + <mail:street>100 Main Street</mail:street> + <mail:city>Anywhereville</mail:city> + <mail:state>NY</mail:state> + <mail:zip>12345</mail:zip> + <addr:isCurrent>true</addr:isCurrent> + </addr:address> + </per:addresses> + </per:person>

    - Now when we serialize the bean, we get the following: + Enabling the {@link org.apache.juneau.xml.XmlSerializer#XML_addNamespaceUrisToRoot} setting results + in the namespace URLs being added to the root node:

    -

    - <per:person +

    + <per:person xmlns='http://www.apache.org/2013/Juneau' - xmlns:per='http://www.apache.org/person/'> - <per:id>1</per:id> + xmlns:per='http://www.apache.org/person/' + xmlns:addr='http://www.apache.org/address/' + xmlns:mail='http://www.apache.org/mail/' + > <per:name>John Smith</per:name> + <per:birthDate>1946-08-12T04:00:00Z</per:birthDate> + <per:addresses> + <addr:address> + <mail:street>100 Main Street</mail:street> + <mail:city>Anywhereville</mail:city> + <mail:state>NY</mail:state> + <mail:zip>12345</mail:zip> + <addr:isCurrent>true</addr:isCurrent> + </addr:address> + </per:addresses> </per:person>

    We can simplify the output by setting the default namespace on the serializer so that all the elements do not need to be prefixed: -

    +

    // Create a new serializer with readable output, this time with namespaces enabled. - XmlSerializer s = XmlSerializer.create() - .ws() - .sq() - .ns() + XmlSerializer s = XmlSerializer.create().ws().sq().ns() .defaultNamespaceUri("http://www.apache.org/person/") .build();

    @@ -6239,13 +6235,25 @@ This produces the following equivalent where the elements don't need prefixes since they're already in the default document namespace:

    -

    - <person +

    + <person + xmlns:juneau='http://www.apache.org/2013/Juneau' xmlns='http://www.apache.org/person/' - xmlns:juneau='http://www.apache.org/2013/Juneau'> - <id>1</id> + xmlns:addr='http://www.apache.org/address/' + xmlns:mail='http://www.apache.org/mail/' + > <name>John Smith</name> - </person> + <birthDate>1946-08-12T04:00:00Z</birthDate> + <addresses> + <addr:address> + <mail:street>100 Main Street</mail:street> + <mail:city>Anywhereville</mail:city> + <mail:state>NY</mail:state> + <mail:zip>12345</mail:zip> + <addr:isCurrent>true</addr:isCurrent> + </addr:address> + </addresses> + </person>

    One important property on the XML serializer class is @@ -6259,7 +6267,7 @@ The following code will produce the same output as before, but will perform slightly better since it avoids this pre-scan step.

    -

    +

    // Create a new serializer with readable output, this time with namespaces enabled. XmlSerializer s = XmlSerializer.create() .ws() @@ -6274,6 +6282,7 @@

    2.16.8- URI Properties

    + TODO
    @@ -6301,47 +6310,35 @@
    We'll use the classes from before, but remove the references to namespaces.
    Since we have not defined a default namespace, everything is defined under the default Juneau namespace.

    -

    +

    Sample Beans
    +

    @Bean(typeName="person") public class Person { + // Bean properties - public int id; public String name; - @Xml(format=ATTR) public URI uri; - public URI addressBookUri; - @BeanProperty(swap=CalendarSwap.ISO8601DTZ.class) public Calendar birthDate; - public LinkedList<Address> addresses = new LinkedList<Address>(); - - // Bean constructor (needed by parser) - public Person() {} - - // Normal constructor - public Person(int id, String name, String uri, String addressBookUri, String birthDate) - throws Exception { - this.id = id; - this.name = name; - this.uri = new URI(uri); - this.addressBookUri = new URI(addressBookUri); - this.birthDate = new GregorianCalendar(); - this.birthDate.setTime(DateFormat.getDateInstance(DateFormat.MEDIUM).parse(birthDate)); - } + @Swap(CalendarSwap.ISO8601DTZ.class) public Calendar birthDate; + public List<Address> addresses; + + // Getters/setters omitted } - + @Bean(typeName="address") public class Address { + // Bean properties - @Xml(format=ATTR) public URI uri; - public URI personUri; - public int id; - public String street, city, state; + public String street, city; + public StateEnum state; public int zip; public boolean isCurrent; - } + + // Getters/setters omitted + }

    The code for creating our POJO model and generating XML Schema is shown below:

    -

    +

    // Create a new serializer with readable output. XmlSerializer s = XmlSerializer.create() .ws() @@ -6353,52 +6350,12 @@ // Create the equivalent schema serializer. XmlSchemaSerializer ss = s.getSchemaSerializer(); - // Create our bean. - Person p = new Person(1, "John Smith", "http://sample/addressBook/person/1", - "http://sample/addressBook", "Aug 12, 1946"); - Address a = new Address(); - a.uri = new URI("http://sample/addressBook/address/1"); - a.personUri = new URI("http://sample/addressBook/person/1"); - a.id = 1; - a.street = "100 Main Street"; - a.city = "Anywhereville"; - a.state = "NY"; - a.zip = 12345; - a.isCurrent = true; - p.addresses.add(a); - - // Serialize the bean to XML. - String xml = s.serialize(p); // Get the XML Schema corresponding to the XML generated above. - String xmlSchema = ss.serialize(p); + String xmlSchema = ss.serialize(new Person());

    - -
    XML results
    -

    - <person - xmlns='http://www.apache.org/2013/Juneau' - uri='http://sample/addressBook/person/1'> - <id>1</id> - <name>John Smith</name> - <addressBookUri>http://sample/addressBook</addressBookUri> - <birthDate>1946-08-12T00:00:00Z</birthDate> - <addresses> - <address uri='http://sample/addressBook/address/1'> - <personUri>http://sample/addressBook/person/1</personUri> - <id>1</id> - <street>100 Main Street</street> - <city>Anywhereville</city> - <state>NY</state> - <zip>12345</zip> - <isCurrent>true</isCurrent> - </address> - </addresses> - </person> -

    -
    XML-Schema results
    -

    +

    <schema xmlns='http://www.w3.org/2001/XMLSchema' targetNamespace='http://www.apache.org/2013/Juneau' @@ -6407,13 +6364,10 @@ <element name='person' _type='juneau:org.apache.juneau.examples.addressbook.Person'/> <complexType name='org.apache.juneau.examples.addressbook.Person'> <sequence> - <element name='id' _type='integer' minOccurs='0'/> <element name='name' _type='string' minOccurs='0'/> - <element name='addressBookUri' _type='string' minOccurs='0'/> <element name='birthDate' _type='juneau:java.util.Calendar' minOccurs='0'/> <element name='addresses' _type='juneau:java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_' minOccurs='0'/> </sequence> - <attribute name='uri' _type='string'/> </complexType> <complexType name='java.util.Calendar'> <sequence> @@ -6430,69 +6384,50 @@ </complexType> <complexType name='org.apache.juneau.examples.addressbook.Address'> <sequence> - <element name='personUri' _type='string' minOccurs='0'/> - <element name='id' _type='integer' minOccurs='0'/> <element name='street' _type='string' minOccurs='0'/> <element name='city' _type='string' minOccurs='0'/> <element name='state' _type='string' minOccurs='0'/> <element name='zip' _type='integer' minOccurs='0'/> <element name='isCurrent' _type='boolean' minOccurs='0'/> </sequence> - <attribute name='uri' _type='string'/> </complexType> </schema>

    Now if we add in some namespaces, we'll see how multiple namespaces are handled.

    -

    - @Xml(prefix="per") - @Bean(typeName="person") +

    Sample Beans with multiple namespaces
    +

    + @Xml(prefix="per") + @Bean(typeName="person") public class Person { - ... + + // Bean properties + public String name; + @Swap(CalendarSwap.ISO8601DTZ.class) public Calendar birthDate; + public List<Address> addresses; + + // Getters/setters omitted } - + @Xml(prefix="addr") @Bean(typeName="address") public class Address { - ... - @Xml(prefix="mail") public String street, city, state; + + // Bean properties + @Xml(prefix="mail") public String street, city; + @Xml(prefix="mail") public StateEnum state; @Xml(prefix="mail") public int zip; - ... - } -

    - -
    XML results
    -

    - <per:person - xmlns='http://www.apache.org/2013/Juneau' - xmlns:per='http://www.apache.org/person/' - xmlns:addr='http://www.apache.org/address/' - xmlns:mail='http://www.apache.org/mail/' - uri='http://sample/addressBook/person/1'> - <per:id>1</per:id> - <per:name>John Smith</per:name> - <per:addressBookUri>http://sample/addressBook</per:addressBookUri> - <per:birthDate>1946-08-12T00:00:00Z</per:birthDate> - <per:addresses> - <addr:address uri='http://sample/addressBook/address/1'> - <addr:personUri>http://sample/addressBook/person/1</addr:personUri> - <addr:id>1</addr:id> - <mail:street>100 Main Street</mail:street> - <mail:city>Anywhereville</mail:city> - <mail:state>NY</mail:state> - <mail:zip>12345</mail:zip> - <addr:isCurrent>true</addr:isCurrent> - </addr:address> - </per:addresses> - </per:person> + public boolean isCurrent; + + // Getters/setters omitted + }

    The schema consists of 4 documents separated by a '\u0000' character.

    -
    XML-Schema results
    -

    +

    <schema xmlns='http://www.w3.org/2001/XMLSchema' targetNamespace='http://www.apache.org/2013/Juneau' @@ -6548,7 +6483,7 @@ xmlns:per='http://www.apache.org/person/' xmlns:addr='http://www.apache.org/address/' xmlns:mail='http://www.apache.org/mail/'> - <import namespace='http://www.apache.org/2013/Juneau' schemaLocation='juneau.xsd'/> + <import namespace='http://www.apache.org/2013/Juneau' schemaLocation='juneau.xsd'/> <import namespace='http://www.apache.org/address/' schemaLocation='addr.xsd'/> <import namespace='http://www.apache.org/mail/' schemaLocation='mail.xsd'/> <element name='person' _type='per:org.apache.juneau.examples.addressbook.Person'/> @@ -6558,9 +6493,7 @@ </sequence> <attribute name='uri' _type='string'/> </complexType> - <element name='id' _type='juneau:int'/> <element name='name' _type='juneau:java.lang.String'/> - <element name='addressBookUri' _type='juneau:java.net.URI'/> <element name='birthDate' _type='juneau:java.util.Calendar'/> <element name='addresses' _type='juneau:java.util.LinkedList_x003C_org.apache.juneau.examples.addressbook.Address_x003E_'/> </schema> @@ -6581,10 +6514,7 @@ <sequence> <any minOccurs='0' maxOccurs='unbounded'/> </sequence> - <attribute name='uri' _type='string'/> </complexType> - <element name='personUri' _type='juneau:java.net.URI'/> - <element name='id' _type='juneau:int'/> <element name='isCurrent' _type='juneau:boolean'/> </schema> [\u0000] @@ -6618,6 +6548,7 @@

    2.17 - HTML Details

    + TODO @@ -6635,7 +6566,7 @@ Tags are added to help differentiate data types when they cannot be inferred through reflection. These tags are ignored by browsers and treated as plain text.

    -
    Data type JSON example
    +
    @@ -6676,7 +6607,7 @@ The _type attribute is added to differentiate between objects (maps/beans) and arrays (arrays/collections).

    -
    Data type JSON example
    +
    @@ -6777,7 +6708,7 @@

    Collections and arrays are represented as ordered lists.

    -
    Data type JSON example
    +
    @@ -6897,7 +6828,7 @@
    Data type JSON example
    Collections
    - +
    @@ -6965,7 +6896,7 @@
    Data type JSON example
    Beans
    - +
    @@ -7050,7 +6981,7 @@
    Data type JSON example
    Beans with Map properties
    - +
    @@ -7131,10 +7062,6 @@
    Data type JSON example
    - - TODO - Special characters - \n\t\b\f - TODO BeanWithPropertiesWithTypeNames... - TODO @@ -7227,12 +7154,14 @@

    2.17.4 - @Html Annotation

    + TODO

    2.17.5 - HTML-Schema Support

    + TODO
    @@ -7253,191 +7182,124 @@ Juneau uses UON (URL-Encoded Object Notation) for representing POJOs. The UON specification can be found here.

    -

    - The example shown here is from the Address Book resource located in the - org.apache.juneau.sample.war application. -
    The POJO model consists of a List of Person beans, with each Person - containing zero or more Address beans. + The following example shows JSON for a typical bean:

    -

    - When you point a browser at /sample/addressBook/people/1, the POJO is rendered as HTML: +

    Sample Beans
    +

    + public class Person { + + // Bean properties + public String name; + @Swap(CalendarSwap.ISO8601DTZ.class) public Calendar birthDate; + public List<Address> addresses; + + // Getters/setters omitted + } + + public class Address { + + // Bean properties + public String street, city; + public StateEnum state; + public int zip; + public boolean isCurrent; + + // Getters/setters omitted + }

    - -

    - By appending ?Accept=application/x-www-form-urlencoded&plainText=true to the URL, you can - view the data as a URL-encoded string: +

    Sample Code
    +

    + Person p = new Person() + .name("John Smith") + .birthDate("1946-08-12T00:00:00Z") + .addresses( + new Address() + .street("100 Main Street") + .city("Anywhereville") + .state(NY) + .zip(12345) + .isCurrent(true); + );

    -

    - 0=( - uri=http://localhost:10000/addressBook/people/1, - addressBookUri=http://localhost:10000/addressBook/, - id=1, - name='Barack+Obama', - birthDate='Aug+4,+1961', +

    UON
    +

    + ( + name='John+Smith', + birthDate='1946-08-12T00:00:00Z', addresses=@( ( - uri=http://localhost:10000/addressBook/addresses/1, - personUri=http://localhost:10000/addressBook/people/1, - id=1, - street='1600+Pennsylvania+Ave', - city=Washington, - state=DC, - zip=20500, + street='100 Main Street', + city=Anywhereville, + state=NY, + zip=12345, isCurrent=true - ), - ( - uri=http://localhost:10000/addressBook/addresses/2, - personUri=http://localhost:10000/addressBook/people/1, - id=2, - street='5046+S+Greenwood+Ave', - city=Chicago, - state=IL, - zip=60615, - isCurrent=false - ) - ), - age=56 - ) - &1=( - uri=http://localhost:10000/addressBook/people/2, - addressBookUri=http://localhost:10000/addressBook/, - id=2, - name='George+Walker+Bush', - birthDate='Jul+6,+1946', - addresses=@( - ( - uri=http://localhost:10000/addressBook/addresses/3, - personUri=http://localhost:10000/addressBook/people/2, - id=3, - street='43+Prairie+Chapel+Rd', - city=Crawford, - state=TX, - zip=76638, - isCurrent=true - ), - ( - uri=http://localhost:10000/addressBook/addresses/4, - personUri=http://localhost:10000/addressBook/people/2, - id=4, - street='1600+Pennsylvania+Ave', - city=Washington, - state=DC, - zip=20500, - isCurrent=false ) - ), - age=71 - ) -

    - -

    - Juneau supports two kinds of serialization: -

    -
      -
    • - Construction of full URL query parameter strings (e.g. &key=value pairs) from beans - and maps. -
    • - Construction of URL query parameter value strings (e.g. just the value portion of - &key=value pairs) from any POJO. -
    -

    - Top-level beans and maps can serialized as key/value pairs as shown below: -

    - -
    Example: A bean with 2 string properties, 'foo' and 'baz', serialized to a query string
    -

    - http://localhost/sample?foo=bar&baz=bing -

    -

    - Lower-level beans and maps are also serialized as key/value pairs, but are surrounded with a - "(...)" construct to denote an object mapping, and uses a comma as the parameter delimiter instead - of "&". -

    - -
    Example: A bean serialized as a query parameter value.
    -

    - http://localhost/sample?a1=(foo=bar,baz=bing) -

    + ) + ) +

    -
    General methodology:
    - - - - - - + +
    Java typeJSON equivalentUON
    Maps/beansOBJECT + + +

    2.18.1 - UON Methodology

    +
    +
    General methodology:
    + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - -
    Java typeJSON equivalentUON
    Maps/beansOBJECT a1=(b1=x1,b2=x2) a1=(b1=(c1=x1,c2=x2)) -
    Collections/arraysARRAY +
    Collections/arraysARRAY a1=@(x1,x2) a1=@(@(x1,x2),@(x3,x4)) a1=@((b1=x1,b2=x2),(c1=x1,c2=x2)) -
    BooleansBOOLEAN +
    BooleansBOOLEAN a1=true&a2=false -
    int/float/double/...NUMBER +
    int/float/double/...NUMBER a1=123&a2=1.23e1 -
    nullNULL +
    nullNULL a1=null -
    StringSTRING +
    StringSTRING a1=foobar a1='true' a1='null' a1='123' a1=' string with whitespace ' a1='string with ~'escaped~' quotes' -
    -

    - Refer to the UON specification for a complete set of syntax rules. -

    - PojoSwaps can be used to convert non-serializable POJOs into serializable forms, such as - converting Calendar object to ISO8601 strings, or byte[] arrays to - Base-64 encoded strings. -
    These transforms can be associated at various levels: -

    -
      -
    • On serializer and parser instances to handle all objects of the class type globally. -
    • On classes through the @Bean annotation. -
    • On bean properties through the @BeanProperty annotations. -
    - -
    Example: A serialized Calendar object using CalendarSwap.RFC2822DTZ transform.
    -

    - http://localhost/sample?a1='Sun,+03+Mar+1901+09:05:06+GMT' -

    - - - -

    2.18.1 - UON Methodology

    -
    +
    +

    + Refer to the UON specification for a complete set of syntax rules. +

    @@ -7518,194 +7380,125 @@ objects.

    - Juneau uses UON (URL-Encoded Object Notation) for representing POJOs. + Juneau uses UON (URL-Encoded Object Notation) for representing POJOs as URL-Encoded values in key-value pairs. The UON specification can be found here.

    - -

    - The example shown here is from the Address Book resource located in the - org.apache.juneau.sample.war application -
    The POJO model consists of a List of Person beans, with each Person - containing zero or more Address beans. -

    -

    - When you point a browser at /sample/addressBook/people/1, the POJO is rendered as HTML: -

    -

    - By appending ?Accept=application/x-www-form-urlencoded&plainText=true to the URL, you can - view the data as a URL-encoded string: -

    -

    - 0=( - uri=http://localhost:10000/addressBook/people/1, - addressBookUri=http://localhost:10000/addressBook/, - id=1, - name='Barack+Obama', - birthDate='Aug+4,+1961', - addresses=@( - ( - uri=http://localhost:10000/addressBook/addresses/1, - personUri=http://localhost:10000/addressBook/people/1, - id=1, - street='1600+Pennsylvania+Ave', - city=Washington, - state=DC, - zip=20500, - isCurrent=true - ), - ( - uri=http://localhost:10000/addressBook/addresses/2, - personUri=http://localhost:10000/addressBook/people/1, - id=2, - street='5046+S+Greenwood+Ave', - city=Chicago, - state=IL, - zip=60615, - isCurrent=false - ) - ), - age=56 - ) - &1=( - uri=http://localhost:10000/addressBook/people/2, - addressBookUri=http://localhost:10000/addressBook/, - id=2, - name='George+Walker+Bush', - birthDate='Jul+6,+1946', - addresses=@( - ( - uri=http://localhost:10000/addressBook/addresses/3, - personUri=http://localhost:10000/addressBook/people/2, - id=3, - street='43+Prairie+Chapel+Rd', - city=Crawford, - state=TX, - zip=76638, - isCurrent=true - ), - ( - uri=http://localhost:10000/addressBook/addresses/4, - personUri=http://localhost:10000/addressBook/people/2, - id=4, - street='1600+Pennsylvania+Ave', - city=Washington, - state=DC, - zip=20500, - isCurrent=false - ) - ), - age=71 - ) -

    - -

    - Juneau supports two kinds of serialization: -

    -
      -
    • - Construction of full URL query parameter strings (e.g. &key=value pairs) from beans - and maps. -
    • - Construction of URL query parameter value strings (e.g. just the value portion of - &key=value pairs) from any POJO. -
    -

    - Top-level beans and maps can serialized as key/value pairs as shown below: + The following example shows JSON for a typical bean:

    +
    Sample Beans
    +

    + public class Person { -

    Example: A bean with 2 string properties, 'foo' and 'baz', serialized to a query string
    -

    - http://localhost/sample?foo=bar&baz=bing -

    -

    - Lower-level beans and maps are also serialized as key/value pairs, but are surrounded with a - "(...)" construct to denote an object mapping, and uses a comma as the parameter delimiter - instead of "&". + // Bean properties + public String name; + @Swap(CalendarSwap.ISO8601DTZ.class) public Calendar birthDate; + public List<Address> addresses; + + // Getters/setters omitted + } + + public class Address { + + // Bean properties + public String street, city; + public StateEnum state; + public int zip; + public boolean isCurrent; + + // Getters/setters omitted + }

    - -
    Example: A bean serialized as a query parameter value.
    -

    - http://localhost/sample?a1=(foo=bar,baz=bing) +

    Sample Code
    +

    + Person p = new Person() + .name("John Smith") + .birthDate("1946-08-12T00:00:00Z") + .addresses( + new Address() + .street("100 Main Street") + .city("Anywhereville") + .state(NY) + .zip(12345) + .isCurrent(true); + );

    +
    URL-Encoding
    +

    + name='John+Smith' + &birthDate='1946-08-12T00:00:00Z' + &addresses=@( + ( + street='100 Main Street', + city=Anywhereville, + state=NY, + zip=12345, + isCurrent=true + ) + ) +

    -
    General methodology:
    - - - - - - + +
    Java typeJSON equivalentUON
    Maps/beansOBJECT + + +

    2.19.1 - URL-Encoding Methodology

    +
    +
    General methodology:
    + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - -
    Java typeJSON equivalentUON
    Maps/beansOBJECT a1=(b1=x1,b2=x2) a1=(b1=(c1=x1,c2=x2)) -
    Collections/arraysARRAY +
    Collections/arraysARRAY a1=@(x1,x2) a1=@(@(x1,x2),@(x3,x4)) a1=@((b1=x1,b2=x2),(c1=x1,c2=x2)) -
    BooleansBOOLEAN +
    BooleansBOOLEAN a1=true&a2=false -
    int/float/double/...NUMBER +
    int/float/double/...NUMBER a1=123&a2=1.23e1 -
    nullNULL +
    nullNULL a1=null -
    StringSTRING +
    StringSTRING a1=foobar a1='true' a1='null' a1='123' a1=' string with whitespace ' a1='string with ~'escaped~' quotes' -
    -

    - Refer to the UON specification for a complete set of syntax rules. -

    - PojoSwaps can be used to convert non-serializable POJOs into serializable forms, such as - converting Calendar object to ISO8601 strings, or byte[] arrays to - Base-64 encoded strings. -
    These transforms can be associated at various levels: -

    -
      -
    • On serializer and parser instances to handle all objects of the class type globally. -
    • On classes through the @Bean annotation. -
    • On bean properties through the @BeanProperty annotations. -
    - -
    Example: A serialized Calendar object using CalendarSwap.RFC2822DTZ transform.
    -

    - http://localhost/sample?a1='Sun,+03+Mar+1901+09:05:06+GMT' -

    - - - -

    2.19.1 - URL-Encoding Methodology

    -
    +
    +

    + Refer to the UON specification for a complete set of syntax rules. +

    @@ -7774,6 +7567,7 @@

    2.19.4 - @UrlEncoding Annotation

    + TODO
    @@ -7781,6 +7575,7 @@

    2.20 - MessagePack Details

    + TODO @@ -7849,18 +7644,21 @@

    2.21 - SOAP Details

    + TODO

    2.22 - CSV Details

    + TODO

    2.23 - Java Serialized Object Details

    + TODO
    @@ -7900,7 +7698,7 @@
    Maven Dependency
    -

    +

    <dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-marshall-rdf</artifactId> @@ -7909,12 +7707,12 @@

    Java Library
    -

    +

    juneau-marshall-rdf-7.1.0.jar

    OSGi Module
    -

    +

    org.apache.juneau.marshall.rdf_7.1.0.jar

    @@ -7934,7 +7732,7 @@ packaged separately so that you don't need to pull in the Jena dependency unless you need it.

    -

    +

    // A simple bean public class Person { public String name = "John Smith"; @@ -8020,6 +7818,7 @@

    3.1.1 - RDF Methodology

    + TODO
    @@ -8179,6 +7978,7 @@

    3.1.4 - @Rdf Annotation

    + TODO
    @@ -8203,7 +8003,7 @@ of this class.
    We do this by adding the following annotation to our class:

    -

    +

    @Rdf(prefix="per") public class Person {

    @@ -8211,7 +8011,7 @@ In general, the best approach is to define the namespace URIs at the package level using a package-info.java class, like so:

    -

    +

    // RDF namespaces used in this package @RdfSchema( prefix="ab", @@ -8232,7 +8032,7 @@

    Now when we rerun the sample code, we'll get the following:

    -

    +

    <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:j="http://www.apache.org/juneau/" @@ -8251,7 +8051,7 @@
    In high-performance environments, you may want to consider disabling auto-detection and providing an explicit list of namespaces to the serializer to avoid this scanning step.

    -

    +

    // Create a new serializer, but manually specify the namespaces. RdfSerializer s = RdfSerializer.create() .xmlabbrev() @@ -8281,7 +8081,7 @@ identifier for this bean.
    The second un-annotated property is interpreted as a reference to another resource.

    -

    +

    public class Person { // Bean properties @@ -8304,7 +8104,7 @@

    We alter our code to pass in values for these new properties.

    -

    +

    // Create our bean. Person p = new Person(1, "John Smith", "http://sample/addressBook/person/1", "http://sample/addressBook"); @@ -8312,7 +8112,7 @@

    Now when we run the sample code, we get the following:

    -

    +

    <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:j="http://www.apache.org/juneau/" @@ -8334,7 +8134,7 @@ The following properties would have produced the same output as before. Note that the @URI annotation is only needed on the second property.

    -

    +

    public class Person { // Bean properties @@ -8356,7 +8156,7 @@

    The following code produces the same output as before, but the URIs on the beans are relative.

    -

    +

    // Create a new serializer with readable output. RdfSerializer s = RdfSerializer.create() .xmlabbrev() @@ -8400,7 +8200,7 @@

    To enable, set the RDF_addRootProperty property to true on the serializer:

    -

    +

    // Create a new serializer. RdfSerializer s = RdfSerializer.create() .xmlabbrev() @@ -8411,7 +8211,7 @@

    Now when we rerun the sample code, we'll see the added root attribute on the root resource.

    -

    +

    <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:j="http://www.apache.org/juneau/" @@ -8455,7 +8255,7 @@

    To enable, set the RDF_addLiteralTypes property to true on the serializer:

    -

    +

    // Create a new serializer (revert back to namespace autodetection). RdfSerializer s = RdfSerializer.create() .xmlabbrev() @@ -8466,7 +8266,7 @@

    Now when we rerun the sample code, we'll see the added root attribute on the root resource.

    -

    +

    <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:j="http://www.apache.org/juneau/" @@ -8507,7 +8307,7 @@

    Maven Dependency
    -

    +

    <dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-dto</artifactId> @@ -8516,12 +8316,12 @@

    Java Library
    -

    +

    juneau-dto-7.1.0.jar

    OSGi Module
    -

    +

    org.apache.juneau.dto_7.1.0.jar

    @@ -8546,7 +8346,7 @@

    The following examples show how to create HTML tables.

    - +
    @@ -8660,7 +8460,7 @@
    The following code shows a feed being created programmatically using the {@link org.apache.juneau.dto.atom.AtomBuilder} class.

    -

    +

    import static org.apache.juneau.dto.atom.AtomBuilder.*; Feed feed = @@ -8700,7 +8500,7 @@

    Example with no namespaces
    -

    +

    // Create a serializer with readable output, no namespaces yet. XmlSerializer s = XmlSerializer.create().sq().ws().build(); @@ -8709,7 +8509,7 @@

    Results
    -

    +

    <feed> <id> tag:juneau.apache.org @@ -8801,7 +8601,7 @@ The following is an example Swagger document from the Swagger website.

    -

    +

    { "swagger": "2.0", "info": { @@ -8870,7 +8670,7 @@

    This document can be generated by the following Java code:

    -

    +

    static import org.apache.juneau.dto.swagger.SwaggerBuilder.*; Swagger swagger = swagger() @@ -8921,7 +8721,7 @@ Methods that take in beans and collections of beans can also take in JSON representations of those objects.

    -

    +

    // Pass in a JSON object representation of an Info object. swagger.info("{title:'Swagger Petstore',...}");

    @@ -8931,7 +8731,7 @@
    These methods can also be used to set and retrieve non-Swagger attributes such as "$ref" (which is not a part of the Swagger spec, but is part of the JSON Schema spec).

    -

    +

    // Set a non-standard attribute. swagger.set("$ref", "http://foo.com"); @@ -8941,7 +8741,7 @@

    Swagger docs can be parsed back into Swagger beans using the following code:

    -

    +

    Swagger swagger = JsonParser.DEFAULT.parse(swaggerJson, Swagger.class);

    @@ -8954,7 +8754,7 @@
    Maven Dependency
    -

    +

    <dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-svl</artifactId> @@ -8963,12 +8763,12 @@

    Java Library
    -

    +

    juneau-svl-7.1.0.jar

    OSGi Module
    -

    +

    org.apache.juneau.svl_7.1.0.jar

    @@ -9007,14 +8807,14 @@
  • {@link org.apache.juneau.svl.vars.LowerCaseVar} - $LC{arg}
    Example:
    -

    +

    // Use the default variable resolver to resolve a string that contains $S (system property) variables String myProperty = VarResolver.DEFAULT.resolve("The Java home directory is $S{java.home}");

    The following shows how variables can be arbitrarily nested...

    -

    +

    // Look up a property in the following order: // 1) MYPROPERTY environment variable. // 2) 'my.property' system property if environment variable not found. @@ -9034,7 +8834,7 @@

    The following is an example of a variable that performs URL-Encoding on strings.

    -

    +

    // First create our var. public class UrlEncodeVar extends SimpleVar { @@ -9080,7 +8880,7 @@

    The following is the list of default variables defined in all modules:

    -
  • Java code HTML
    +
    @@ -9247,7 +9047,7 @@

    Example:
    -

    +

    // Create a resolver that copies the default resolver and adds $C and $A vars. VarResolver myVarResolver = VarResolver.DEFAULT .builder() @@ -9284,7 +9084,7 @@

    Maven Dependency
    -

    +

    <dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-config</artifactId> @@ -9293,12 +9093,12 @@

    Java Library
    -

    +

    juneau-config-7.1.0.jar

    OSGi Module
    -

    +

    org.apache.juneau.config_7.1.0.jar

    @@ -9310,7 +9110,7 @@ The juneau-config library contains a powerful API for creating and using INI-style config files.

    Example configuration file:
    -

    +

    # A set of entries [Section1] @@ -9331,7 +9131,7 @@ are created through the {@link org.apache.juneau.config.ConfigBuilder} class.
    Builder creator methods are provided on the Config class:

    -

    +

    // Create a Config object Config c = Config.create().name("MyConfig.cfg").build(); @@ -9341,7 +9141,7 @@

    Once instantiated, reading values from the config are simple:

    -

    +

    // Read values from section #1 int key1 = c.getInt("Section1/key1"); boolean key2 = c.getBoolean("Section1/key2"); @@ -9390,7 +9190,7 @@

    • Each config file contains zero or more sections containing zero or more entries: -

      +

      [Section1] key1 = 1 @@ -9399,12 +9199,12 @@

    • Unicode escapes can be used in values. -

      +

      key1 = \u0070\u0075\u0062\u006c\u0069\u0063

    • Comment lines start with the '#' character and can be placed on lines before sections and entries: -

      +

      # A comment about this section [Section1] @@ -9413,19 +9213,19 @@

    • Comments can also be placed on the same line as entries: -

      +

      key1 = 1 # A comment about this entry

    • Values containing '#' must be escaped to prevent identification as a comment character: -

      +

      valueContainingPound = Value containing \u0023 character


      Likewise, '\' should be escaped to prevent confusion with unicode escapes.
    • Values containing newlines can span multiple lines.
      Subsequent lines start with a tab character. -

      +

      multiLineValue = line 1, line 2, @@ -9438,7 +9238,7 @@ Whitespace is not ignored within multi-line values (except for the leading tab character on each line).

    • Blank lines can be used anywhere in the file. -

      +

      # A comment line # Another comment line @@ -9448,7 +9248,7 @@

    • Values located before any sections are considered part of the no-name section, meaning they are accessed simply by key and not section/key. -

      +

      # Top of file # Use config.getString("key1") to retrieve. @@ -9463,7 +9263,7 @@

    • Section and key names must be at least one character long and not consist of any of the following characters: -

      +

      / \ [ ] = #

    • @@ -9487,7 +9287,7 @@

      The most common case for configuration values are primitives.

      -

      +

      # A string key1 = foo @@ -9527,14 +9327,14 @@

      On integers and longs, "K", "M", and "G" can be used to identify kilo, mega, and giga.

      -

      +

      key1 = 100K # Same as 1024000 key2 = 100M # Same as 104857600

      Numbers can also use hexadecimal and octal notation:

      -

      +

      hex1 = 0x12FE hex2 = 0X12FE octal1 = 01234 @@ -9542,14 +9342,14 @@

      Strings with newlines get broken into separate lines:

      -

      +

      key1 = This is a particularly long sentence that we want to split onto separate lines.

      Typically, multi-line values are started on the next line for clarity like so:

      -

      +

      key1 = This is a particularly long sentence that we want to split onto separate lines. @@ -9583,18 +9383,18 @@ An example of an object convertible from a String was already shown in an example above.
      In that case, it was a URL which has a public constructor that takes in a String:

      -

      +

      # A POJO key4 = http://bar

      -

      +

      // Read values from section #1 URL key4 = c.getObject("Section1/key4", URL.class);

      Beans are represented as {@link org.apache.juneau.json.JsonSerializer#DEFAULT_LAX Lax JSON} by default:

      -

      +

      // Contact information [ContactInfo] address = @@ -9605,7 +9405,7 @@ zip: 12345 }

      -

      +

      // Example bean public class Address { public String street, city; @@ -9660,34 +9460,34 @@

    The getStringArray() methods allow you to retrieve comma-delimited lists of values: -

    +

    key1 = foo, bar, baz

    -

    +

    String[] key1 = c.getStringArray("key1");

    String arrays can also be represented in JSON when using the getObject() methods:

    -

    +

    key1 = ['foo','bar','baz']

    -

    +

    String[] key1 = c.getObject("key1", String.class);

    Primitive arrays can also be retrieved using the getObject() methods:

    -

    +

    key1 = [1,2,3]

    -

    +

    int[] key1 = c.getObject("key1", int[].class);

    Arrays of POJOs can also be retrieved using the getObject() methods:

    -

    +

    addresses = [ { @@ -9704,7 +9504,7 @@ } ]

    -

    +

    Address[] addresses = c.getObject("addresses", Address[].class);

    @@ -9751,7 +9551,7 @@
    Produces: LinkedHashMap<Integer,ArrayList<MyBean[]>>
    Example:
    -

    +

    addresses = [ { @@ -9768,14 +9568,14 @@ } ]

    -

    +

    List<Address> addresses = c.getObject("addresses", ArrayList.class, Address.class);

    Oftentimes, it might be useful to parse into the {@link org.apache.juneau.ObjectList} and {@link org.apache.juneau.ObjectMap} classes that provide the various convenience methods for working with JSON-like data structures:

    -

    +

    ObjectMap m = c.getObject("key1", ObjectMap.class); ObjectList l = c.getObject("key2", ObjectList.class);

    @@ -9815,16 +9615,16 @@

    For example:

    -

    +

    key = Zm9vYmFycw==

    -

    +

    byte[] bytes = c.getBytes("key");

    Binary lines can be split up into separate lines for readability:

    -

    +

    key = Zm9vYm Fycw== @@ -9847,7 +9647,7 @@ Config files can contain variables that get resolved dynamically using the previously-described {@link org.apache.juneau.svl.VarResolver} API.

    Example:
    -

    +

    #-------------------------- # My section #-------------------------- @@ -9868,7 +9668,7 @@ # A POJO with embedded variables aBean = {foo:'$S{foo}',baz:$C{MySection/anInt}}

    -

    +

    Config c = Config.create().build(); Locale locale = cf.getObject("MySection/locale", Locale.class); @@ -9917,7 +9717,7 @@

    The $IF variable can be used for simple if/else logic:

    -

    +

    # Value set to 'foo' if myBooleanProperty is true key1 = $IF{ @@ -9944,7 +9744,7 @@

    The $SW variable can be used for switch blocks based on pattern matching:

    -

    +

    # Shell command depends on the OS shellCommand = $SW{ @@ -9957,7 +9757,7 @@

    The $CO variable can be used for coalescing of values (finding the first non-null/empty match):

    -

    +

    # Debug flag can be enabled by system property or environment variable. debug = $CO{ @@ -9969,7 +9769,7 @@

    The $PM variable can be used for calculating boolean values:

    -

    +

    # Debug flag can be enabled by system property or environment variable. isWindows = $PM{ @@ -9993,7 +9793,7 @@

    For example, the following password is marked for encoding:

    -

    +

    [MyHost] url = http://localhost:9080/foo user = me @@ -10038,7 +9838,7 @@ {@link org.apache.juneau.config.Config#getSectionAsMap(String)}.

    Example:
    -

    +

    // Example config file [MyAddress] street = 123 Main Street @@ -10046,7 +9846,7 @@ state = NY zip = 12345

    -

    +

    // Example usage Config c = Config.create("MyConfig.cfg").build(); @@ -10071,7 +9871,7 @@ {@link org.apache.juneau.config.Config#getSectionAsBean(String,Class,boolean)}.

    Example:
    -

    +

    // Example config file [MyAddress] street = 123 Main Street @@ -10079,7 +9879,7 @@ state = NY zip = 12345

    -

    +

    // Example bean public class Address { public String street, city; @@ -10109,7 +9909,7 @@ call, section interfaces can also be use to set values in the underlying configuration.

    Example:
    -

    +

    // Example config file [MySection] string = foo @@ -10119,7 +9919,7 @@ int3dArray = [[[123,null],null],null] bean1d3dListMap = {key:[[[[{foo:'bar',baz:123}]]]]}

    -

    +

    // Example interface. // Setters are optional. public interface MyConfigInterface { @@ -10179,7 +9979,7 @@

  • {@link org.apache.juneau.config.Config#removeSection(String) removeSection(String)} -

    +

    // Construct the sample config file programmatically Config c = Config.create("MyConfig.cfg").build() .set("key1", 1) @@ -10196,7 +9996,7 @@ The method {@link org.apache.juneau.config.Config#set(String,Object,Serializer,ConfigMod[],String,List)} can be used for adding comments and pre-lines to entries, and specifying encoded values.

    -

    +

    // Set an encoded value with some comments. c.set("key1", 1, null, ConfigMod.ENCODED, "Same-line comment", Arrays.asList( @@ -10204,7 +10004,7 @@ ) );

    -

    +

    # Comment 1 # Comment 2 @@ -10219,7 +10019,7 @@

    Sections can be added with optional pre-lines using the setSection methods:

    -

    +

    // Set an encoded value with some comments. c.setSection("NewSection", Arrays.asList( @@ -10227,7 +10027,7 @@ ) );

    -

    +

    # Section comment 1 # Section comment 2 @@ -10278,11 +10078,11 @@ Setter methods that take in a Serializer can be used to provide custom serialization of entries instead of using the predefined serializer.

    -

    +

    // Set an XML value instead of JSON. c.set("key1", myAddress, XmlSerializer.DEFAULT_SQ_READABLE);

    -

    +

    key1 = <address> <street>123 Main Street</street> @@ -10294,7 +10094,7 @@

    The value can then be retrieved using the equivalent parser:

    -

    +

    Address myAddress = c.getObject("key1", XmlParser.DEFAULT, Address.class);

    @@ -10369,7 +10169,7 @@

    In both cases, the listener is triggered after the changes have been committed.

    -

    +

    final Config c = Config.create("MyConfig.cfg").build(); // Add a listener for changes to MySection/key1 @@ -10443,7 +10243,7 @@

    Read is self-explanatory:

    -

    +

    public String read(String name) { // Return the contents of the specified configuration. } @@ -10451,7 +10251,7 @@

    Write is slightly trickier:

    -

    +

    public String write(String name, String oldContents, String newContents) { // If the old contents match the current stored contents, the new contents will get stored, @@ -10466,7 +10266,7 @@

    The update method is called whenever the stored file gets modified externally:

    -

    +

    public String update(String name, String newContents) { // Do something with the updated contents. } @@ -10486,7 +10286,7 @@

    Example:
    -

    +

    // Create a config with in-memory storage. Config c = Config.create("MyConfig.cfg").store(ConfigMemoryStore.DEFAULT).build();

    @@ -10507,7 +10307,7 @@

    However, the implementation provides a good idea on how stores work (especially the write method):

    -

    +

    public class ConfigMemoryStore extends ConfigStore { // Some methods ommitted. @@ -10569,7 +10369,7 @@

    Example:
    -

    +

    // Create a config store with a watcher thread and high sensitivity. ConfigFileStore fs = ConfigFileStore.create().directory("configs").useWatcher().watcherSensitivity(HIGH).build(); @@ -10591,7 +10391,7 @@
    Completing it is left as an exercise:

    Example Store Class:
    -

    +

    public class ConfigSqlStore extends ConfigStore { // Configurable properties @@ -10699,7 +10499,7 @@ that's passed to the ConfigStore:

    Example Builder Class:
    -

    +

    public class ConfigSqlStoreBuilder extends ConfigStoreBuilder { public ConfigSqlStoreBuilder() { @@ -10784,7 +10584,7 @@

  • {@link org.apache.juneau.config.Config#CONFIG_readOnly}
    Example:
    -

    +

    // Create a read-only config Config c = Config.create("MyConfig.cfg").readOnly().build();

    @@ -10802,7 +10602,7 @@ their listeners get unregistered from the underlying storage APIs.

    Example:
    -

    +

    // Create a transient config. Config c = Config.create("MyConfig.cfg").build(); @@ -10821,7 +10621,7 @@

    Maven Dependency
    -

    +

    <dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-rest-server</artifactId> @@ -10830,12 +10630,12 @@

    Java Library
    -

    +

    juneau-rest-server-7.1.0.jar

    OSGi Module
    -

    +

    org.apache.juneau.rest.server_7.1.0.jar

    @@ -10945,7 +10745,7 @@

    Like any servlet, we could define our resource in the web.xml file of the web application like so...

    -

    +

    <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.3"> <servlet> @@ -10961,7 +10761,7 @@

    Our servlet code is shown below:

    -

    +

    // Sample REST resource that prints out a simple "Hello world!" message. @RestResource( path="/helloWorld", @@ -10991,10 +10791,10 @@

    This is what it looks like in a browser:

    -

    +

    http://localhost:10000/helloWorld

    - +

    It doesn't much simpler than that.
    In this case, we're simply returning a string that will be converted to any of the supported languages (e.g. @@ -11132,7 +10932,7 @@
    You should notice that very little code is being used and everything is configurable through annotations:

    -

    +

    @RestResource( serializers={ HtmlDocSerializer.class, @@ -11224,7 +11024,7 @@ {@link org.apache.juneau.rest.annotation.RestResource#children() @RestResource.children()} annotation.

    Example:
    -

    +

    /** Parent Resource */ @RestResource( path="/parent", @@ -11232,7 +11032,7 @@ ) public MyResource extends BasicRestServlet {...}

    -

    +

    /** Child Resource */ @RestResource( path="/foo" // Path relative to parent resource. @@ -11266,7 +11066,7 @@

    The RootResources class in the Samples project is an example of a router page:

    -

    +

    /** * Sample REST resource showing how to implement a "router" resource page. */ @@ -11303,17 +11103,17 @@ When you bring up this resource in a browser, you see the following that provides a list of navigable links to your child resources:

    -

    +

    http://localhost:10000

    - +

    The {@link org.apache.juneau.rest.BasicRestServletGroup} class is nothing more than a subclass of {@link org.apache.juneau.rest.BasicRestServlet} with a getChildren() method mapped to the servlet root path.
    The method returns a POJO with is just a linked-list of beans with name/description properties.

    -

    +

    // The entire contents of the BasicRestServletGroup class. public class BasicRestServletGroup extends BasicRestServlet { @@ -11370,7 +11170,7 @@

    For example, if you want to add an initialization method to your resource:

    -

    +

    @RestResource(...) public class MyResource { @@ -11386,7 +11186,7 @@

    Or if you want to intercept REST calls:

    -

    +

    @RestResource(...) public class MyResource { @@ -11448,7 +11248,7 @@ resource classes that can be extended by all your child resources so that they all share common settings.

    -
  • ModuleClassPattern
    +
    @@ -11602,7 +11402,7 @@

    To access this object, simply pass it in as a constructor argument or in an INIT hook:

    -

    +

    // Option #1 - Pass in through constructor. public MyResource(RestContextBuilder builder) { builder @@ -11635,7 +11435,7 @@
    The annotation allows the framework to identify the available REST methods through reflection.

    Example:
    -

    +

    @RestMethod(name=GET, path="/") public String sayHello() { return "Hello world!"; @@ -11744,7 +11544,7 @@

    Example:
    -

    +

    @RestMethod(name=GET, path="/example1/{a1}/{a2}/{a3}/*") public String doGetExample1( RestRequest req, @@ -11786,7 +11586,7 @@ with various built-in convenience methods for use in building REST interfaces.
    It can be accessed by passing it as a parameter on your REST Java method:

    -

    +

    @RestMethod(...) public Object myMethod(RestRequest req) {...}

    @@ -11822,7 +11622,7 @@ with various built-in convenience methods for use in building REST interfaces.
    It can be accessed by passing it as a parameter on your REST Java method:

    -

    +

    @RestMethod(...) public Object myMethod(RestResponse req) {...}

    @@ -11848,12 +11648,12 @@ The {@link org.apache.juneau.rest.RequestBody} object is the API for accessing the body of an HTTP request.
    It can be accessed by passing it as a parameter on your REST Java method:

    -

    +

    @RestMethod(...) public Object myMethod(RequestBody body) {...}

    Example:
    -

    +

    @RestMethod(...) public void doPost(RequestBody body) { // Convert body to a linked list of Person objects. @@ -11886,12 +11686,12 @@ The {@link org.apache.juneau.rest.RequestHeaders} object is the API for accessing the headers of an HTTP request.
    It can be accessed by passing it as a parameter on your REST Java method:

    -

    +

    @RestMethod(...) public Object myMethod(RequestHeaders headers) {...}

    Example:
    -

    +

    @RestMethod(...) public Object myMethod(RequestHeaders headers) { @@ -11929,12 +11729,12 @@ The {@link org.apache.juneau.rest.RequestQuery} object is the API for accessing the GET query parameters of an HTTP request.
    It can be accessed by passing it as a parameter on your REST Java method:

    -

    +

    @RestMethod(...) public Object myMethod(RequestQuery query) {...}

    Example:
    -

    +

    @RestMethod(...) public Object myMethod(RequestQuery query) { @@ -11976,12 +11776,12 @@ The {@link org.apache.juneau.rest.RequestFormData} object is the API for accessing the HTTP request body as form data.
    It can be accessed by passing it as a parameter on your REST Java method:

    -

    +

    @RestMethod(...) public Object myMethod(RequestFormData query) {...}

    Example:
    -

    +

    @RestMethod(...) public Object myMethod(RequestFormData formData) { @@ -12025,7 +11825,7 @@
    Note how the variables are passed in as additional arguments on the method, and how those arguments are automatically converted to the specified class type...

    -

    +

    // Default method @RestMethod(name=GET, path="/*") public void doGetDefault() { @@ -12048,7 +11848,7 @@ By default, path patterns are matched using a best-match heuristic.
    When overlaps occur, URLs are matched from most-specific to most-general order:

    -

    +

    // Try first @RestMethod(name=GET, path="/foo/bar") public void method1() { @@ -12090,7 +11890,7 @@

    The following example shows the distinction.

    -

    +

    @RestMethod(name=GET, path="/*") public void doGet(@PathRemainder String remainder) { // URL path pattern can have remainder accessible through req.getRemainder(). @@ -12105,7 +11905,7 @@ Annotations are provided for easy access to URL parameters with automatic conversion to any parsable type.
    For example, the following example can process the URL "/urlWithParams?foo=foo&bar=[1,2,3]&baz=067e6162-3b6f-4ae2-a171-2470b63dff00"...

    -

    +

    // Example GET request with access to query parameters @RestMethod(name=GET, path="/urlWithParams") public String doGetWithParams(@Query("foo") String foo, @Query("bar") int bar, @Query("baz") UUID baz) throws Exception { @@ -12129,12 +11929,12 @@ The {@link org.apache.juneau.rest.RequestPathMatch} object is the API for accessing the matched variables and remainder on the URL path.

    -

    +

    @RestMethod(...) public Object myMethod(RequestPathMatch path) {...}

    Example:
    -

    +

    @RestMethod(..., path="/{foo}/{bar}/{baz}/*") public void doGet(RequestPathMatch path) { // Example URL: /123/qux/true/quux @@ -12171,7 +11971,7 @@ setting the output using the {@link org.apache.juneau.rest.RestResponse#setOutput(Object)} method.

    Example:
    -

    +

    @RestMethod(name=GET) public String doGet() { return "Hello World!"; @@ -12230,7 +12030,7 @@ {@link org.apache.juneau.rest.RestResponse#getNegotiatedWriter()} and writing the output yourself.

    Example:
    -

    +

    // Equivalent method 1 @RestMethod(name=GET, path="/example1/{personId}") public Person doGet1(@Path UUID personId) { @@ -12278,7 +12078,7 @@
    This allows these objects to be returned as responses by REST methods.

    Example:
    -

    +

    @RestMethod(...) public Object sayHello(RestRequest req) { @@ -12319,7 +12119,7 @@
    This allows these objects to be returned as responses by REST methods.

    Example:
    -

    +

    @RestMethod(...) public Object showPicture(RestRequest req) { @@ -12359,7 +12159,7 @@ The following example shows the difference between handling redirects via RestResponse and the simplified approach of using this class.

    Example:
    -

    +

    // Redirect to "/contextPath/servletPath/foobar" // Using RestRequest/RestResponse @@ -12378,7 +12178,7 @@ The constructor can use a MessageFormat-style pattern with multiple arguments.

    Example:
    -

    +

    @RestMethod(...) public Redirect redirectExample3() { return new Redirect("foo/{0}/bar/{1}", id1, id2); @@ -12390,7 +12190,7 @@

    Redirecting to the servlet root can be accomplished by simply using the no-arg constructor.

    Example:
    -

    +

    // Simply redirect to the servlet root. // Equivalent to res.sendRedirect(req.getServletURI()). @RestMethod(...) @@ -12410,7 +12210,7 @@ header value.

    Example:
    -

    +

    // GET method that gets invoked for administrators @RestMethod(name=GET, path="/*", matchers=IsAdminMatcher.class) public Object doGetForAdmin() { @@ -12426,7 +12226,7 @@

    The interface for matchers is simple:

    -

    +

    public class IsAdminMatcher extends RestMatcher { @Override /* RestMatcher */ @@ -12470,7 +12270,7 @@ The {@link org.apache.juneau.rest.annotation.Body @Body} annotation provides easy access to the HTTP body content as any parsable POJO type
    In the example below, we're POSTing beans.

    -

    +

    // Example POST of a bean @RestMethod(name=POST, path="/") public void doPost(@Body Person person) throws Exception { @@ -12482,7 +12282,7 @@ {@link org.apache.juneau.rest.RestRequest#getBody()} method, or a parameter annotated with {@link org.apache.juneau.rest.annotation.Body @Body}.

    -

    +

    // Equivalent method 1 @RestMethod(name=POST, path="/example1") public void doPost1(@Body Person p) { @@ -12517,7 +12317,7 @@ form "aString=foo&aNumber=123&aDate=2001-07-04T15:30:45Z".
    The code is shown here:

    -

    +

    @RestResource( path="/urlEncodedForm" ) @@ -12541,7 +12341,7 @@

    Another possibility is to access the form parameters individually:

    -

    +

    /** POST request handler */ @RestMethod(name=POST, path="/") public Object doPost(@FormData("aString") String aString, @FormData("aNumber") int aNumber, @FormData("aDate") Calendar aDate) throws Exception { @@ -12577,7 +12377,7 @@ be uploaded as multipart form posts.

    Example:
    -

    +

    @RestResource( path="/tempDir" ) @@ -12622,7 +12422,7 @@ The {@link org.apache.juneau.rest.annotation.FormData @FormData} annotation is used to retrieve request form post entries.

    Example:
    -

    +

    @RestMethod(name=POST) public void doPost(RestRequest req, RestResponse res, @FormData("p1") int p1, @@ -12632,7 +12432,7 @@

    This is functionally equivalent to the following code:

    -

    +

    @RestMethod(name=POST) public void doPost(RestRequest req, RestResponse res) { RequestFormData fd = req.getFormData(); @@ -12677,7 +12477,7 @@ {@link org.apache.juneau.rest.RestRequest#getBody()} method for application/x-www-form-urlencoded POST calls.

    Example:
    -

    +

    @RestMethod(name=GET) public void doGet(RestRequest req, RestResponse res, @Query("p1") int p1, @@ -12687,7 +12487,7 @@

    This is functionally equivalent to the following code:

    -

    +

    @RestMethod(name=GET) public void doGet(RestRequest req, RestResponse res) { RequestQuery q = req.getQuery(); @@ -12717,14 +12517,14 @@ The {@link org.apache.juneau.rest.annotation.Header @Header} annotation is used to retrieve request headers.

    Example:
    -

    +

    @RestMethod(name=GET) public void doGet(RestRequest req, RestResponse res, @Header("ETag") UUID etag) {...}

    This is functionally equivalent to the following code:

    -

    +

    @RestMethod(name=GET) public void doPostPerson(RestRequest req, RestResponse res) { RequestHeaders h = req.getHeaders(); @@ -12772,7 +12572,7 @@

    The following are all equivalent ways of defining serializers used by a resource:

    -

    +

    // Option #1 - Defined via annotation. @RestResource(serializers={JsonSerializer.class, XmlSerializer.class}) public class MyResource { @@ -12840,7 +12640,7 @@

    The following are all equivalent ways of defining parsers used by a resource:

    -

    +

    // Option #1 - Defined via annotation. @RestResource(parsers={JsonParser.class, XmlParser.class}) public class MyResource { @@ -12893,7 +12693,7 @@

  • {@link org.apache.juneau.rest.RestContextBuilder} - Various methods on the context builder.
    Example:
    -

    +

    import static org.apache.juneau.BeanContext.*; import static org.apache.juneau.serializer.Serializer.*; import static org.apache.juneau.json.JsonSerializer.*; @@ -12916,7 +12716,7 @@

    The programmatic equivalent to this is:

    -

    +

    // Servlet with properties applied @RestResource(...) public MyRestServlet extends BasicRestServlet { @@ -12937,7 +12737,7 @@

  • {@link org.apache.juneau.rest.annotation.RestMethod#properties()}
  • {@link org.apache.juneau.rest.RequestProperties} -

    +

    // GET method with method-level properties @RestMethod( name=GET, path="/*", @@ -12958,7 +12758,7 @@

    Using the {@link org.apache.juneau.rest.RequestProperties} object:

    -

    +

    // Access it from RestRequest. public Object doGet(RestRequest req) { RequestProperties properties = req.getProperties(); @@ -13013,7 +12813,7 @@

  • {@link org.apache.juneau.rest.RestContextBuilder#beanFilters(Object...)}
  • {@link org.apache.juneau.rest.RestContextBuilder#pojoSwaps(Object...)} -

    +

    // Servlet with transforms applied @RestResource( pojoSwaps={ @@ -13033,7 +12833,7 @@

    The programmatic equivalent to this is:

    -

    +

    // Servlet with properties applied @RestResource(...) public MyRestServlet extends BasicRestServlet { @@ -13066,7 +12866,7 @@

  • {@link org.apache.juneau.rest.annotation.RestMethod#guards()}
  • {@link org.apache.juneau.rest.RestContextBuilder#guards(Class...)} -

    +

    // Define a guard that only lets Billy make a request public BillyGuard extends RestGuard { @@ -13088,12 +12888,12 @@

    A common use for guards is to only allow admin access to certain Java methods...

    -

    +

    // DELETE method @RestMethod(name=DELETE, guards={AdminGuard.class}) public void doDelete(RestRequest req, RestResponse res) throws Exception {...}

    -

    +

    public class AdminGuard extends RestGuard { @Override /* RestGuard */ @@ -13108,7 +12908,7 @@ {@link org.apache.juneau.rest.RestGuard#guard(RestRequest,RestResponse)} and processing the response yourself.

    -

    +

    public class AdminGuard extends RestGuard { @Override /* RestGuard */ @@ -13146,7 +12946,7 @@

  • {@link org.apache.juneau.rest.RestContextBuilder#converters(Class...)}
    Example:
    -

    +

    // Associate the Traversable converter to all Java REST methods in this servlet @RestResource(converters=Traversable.class) public MyRestServlet extends BasicRestServlet { @@ -13156,7 +12956,7 @@

    They can also be defined at the method level:

    -

    +

    // GET person request handler. // Traversable conversion enabled to allow nodes in returned POJO tree to be addressed. // Queryable conversion enabled to allow returned POJO to be searched/viewed/sorted. @@ -13175,7 +12975,7 @@
    The converter uses the {@link org.apache.juneau.utils.PojoRest} wrapper class to address nodes in the tree.

    -

    +

    /** * Converter for enablement of PojoRest support on response objects returned by a @RestMethod method. * When enabled, objects in a POJO tree returned by the REST method can be addressed through additional URL path information. @@ -13242,7 +13042,7 @@

    The {@link org.apache.juneau.rest.annotation.RestResource#messages @RestResource.messages()} annotation is used to associate a resource bundle with a servlet class.

    -

    +

    // Servlet with associated resource bundle @RestResource(messages="nls/MyMessages") public MyRestServlet extends BasicRestServlet { @@ -13257,7 +13057,7 @@ The resource bundle can also be passed into the method by simply specifying a parameter of type {@link java.util.ResourceBundle} or {@link org.apache.juneau.utils.MessageBundle}:

    -

    +

    @RestMethod(name=GET) public String printLocalizedGreeting(MessageBundle messages) { return messages.getString("greeting"); @@ -13267,13 +13067,13 @@ If a resource bundle is shared by multiple servlets, the label and description can be prefixed by the class name:

    -

    +

    #-------------------------------------------------------------------------------- # Contents of MyMessages.properties #-------------------------------------------------------------------------------- greeting = Hello!

    -

    +

    #-------------------------------------------------------------------------------- # Contents of shared MyMessages.properties #-------------------------------------------------------------------------------- @@ -13297,7 +13097,7 @@

    Example:
    -

    +

    // Servlet with automated support for GZIP compression @RestResource(encoders={GzipEncoder.class}) public MyRestServlet extends BasicRestServlet { @@ -13331,7 +13131,7 @@ In the previous examples, there were several cases where embedded variables were contained within annotation values:

    -

    +

    @RestResource( title="$L{my.label}" ) @@ -13358,7 +13158,7 @@

  • {@link org.apache.juneau.rest.RestContextBuilder#vars(Class[])}
    Example:
    -

    +

    // Defined a variable that simply wrapps all strings inside [] brackets. // e.g. "$BRACKET{foobar}" -> "[foobar]" public class BracketVar extends SimpleVar { @@ -13406,7 +13206,7 @@

    Default REST SVL Variables:
    -
  • Annotation Inheritence Rules
    +
    @@ -13585,7 +13385,7 @@

    Example:
    -

    +

    #-------------------------- # Examples #-------------------------- @@ -13597,7 +13397,7 @@

    These properties are then accessible through the {@link org.apache.juneau.config.Config} class.

    -

    +

    Config c = Config.create("myconfig.cfg").build(); String path = c.getString("MyProperties/path"); File javaHome = c.getObject("MyProperties/javaHome", File.class); @@ -13611,7 +13411,7 @@

    Example:
    -

    +

    @RestResource( // Config file is located at ./config_dir/myconfig.cfg config="config_dir/myconfig.cfg", @@ -13624,7 +13424,7 @@
    For example, the Microservice API {@link org.apache.juneau.rest.BasicRestServlet} class defines the location of the config file as a system property "juneau.configFile":

    -

    +

    @RestResource( // Config file location is defined as a system property config="$S{juneau.configFile}", @@ -13639,7 +13439,7 @@

    A common usage is to use this method to initialize fields in your servlet.

    -

    +

    @RestResource( // Config file is located at ./config_dir/myconfig.cfg config="config_dir/myconfig.cfg", @@ -13658,7 +13458,7 @@

    Another common usage is to refer to config properties through $C variables in your annotations:

    -

    +

    @RestResource( // Get stylesheet from myconfig.cfg, but default to devops.css if it's not specified htmldoc=@HtmlDoc( @@ -13672,14 +13472,14 @@ It's even possible to reference request-level variables in your config file if you use {@link org.apache.juneau.rest.RestRequest#getConfig()} to access the config file:

    -

    +

    #------------------------------------- # Contents of config_dir/myconfig.cfg #------------------------------------- [HelloWorldResource] message = Hello $RQ{person}!

    -

    +

    /** * Sample REST resource that prints out a simple "Hello world!" message. */ @@ -13702,20 +13502,20 @@

    You can even add resource bundles into the mix:

    -

    +

    #------------------------------------- # Contents of config_dir/myconfig.cfg #------------------------------------- [HelloWorldResource] message = $L{localizedMessage,$RQ{person}}

    -

    +

    #------------------------------------------- # Contents of HelloWorldResource.properties #------------------------------------------- localizedMessage = Hello {0}!

    -

    +

    /** * Sample REST resource that prints out a simple "Hello world!" message. */ @@ -13757,7 +13557,7 @@

    Example:
    -

    +

    package com.foo.mypackage; @RestResource( @@ -13811,7 +13611,7 @@

  • {@link org.apache.juneau.rest.annotation.RestMethod#clientVersion()}
    Example:
    -

    +

    // Option #1 - Defined via annotation resolving to a config file setting with default value. @RestResource(clientVersionHeader="Client-Version") public class MyResource { @@ -13851,15 +13651,15 @@

    OPTIONS page for HelloWorld sample resource
    -

    +

    http://localhost:10000/helloWorld/?method=OPTIONS

    - +

    The {@link org.apache.juneau.rest.BasicRestServlet} class implements the page by creating a method mapped to the OPTIONS HTTP method that simply returns a Swagger bean:

    -

    +

    @RestResource(...) public class BasicRestServlet extends RestServlet { @@ -13986,14 +13786,14 @@

  • Specify localized JSON Swagger files on your classpath.
    Example:
    -

    +

    MyResource_ja_JP.json

  • Use {@link org.apache.juneau.rest.annotation.ResourceSwagger @ResourceSwagger} and {@link org.apache.juneau.rest.annotation.MethodSwagger @MethodSwagger} annotations on your resource classes and methods.
    Example:
    -

    +

    @RestMethod( swagger=@MethodSwagger(tags="foo,bar,baz") ) @@ -14002,7 +13802,7 @@

  • Use properties files identified by the {@link org.apache.juneau.rest.annotation.RestResource#messages @RestResource.messages()} annotation.
    Example:
    -

    +

    MyResource.myMethod.tags = foo,bar,baz

  • @@ -14010,7 +13810,7 @@
  • Extend the BasicRestInfoProvider and provide customized behavior.
    Example:
    -

    +

    // Our customized info provider. // Extend from the default implementation and selectively override values. public class MyRestInfoProvider extends BasicRestInfoProvider { @@ -14054,7 +13854,7 @@ on the {@link org.apache.juneau.html.HtmlDocSerializer} class.
    For example, the following two pieces of code are equivalent:

    -

    +

    // Title defined via property. @RestResource( properties={ @@ -14073,7 +13873,7 @@ The purpose of these annotation is to populate the HTML document view which by default consists of the following structure:

    -

    +

    <html> <head> <style type='text/css'> @@ -14106,7 +13906,7 @@

    The HelloWorldResource class was an example of the @HtmlDoc annotation in use:

    -

    +

    /** * Sample REST resource that prints out a simple "Hello world!" message. */ @@ -14130,7 +13930,7 @@

    SVL variables can be used in any of these annotations:

    -

    +

    @RestResource( path="/helloWorld", // Register a config file. @@ -14175,7 +13975,7 @@

  • {@link org.apache.juneau.rest.RestContext#REST_widgets}
    Example:
    -

    +

    @RestMethod( widgets={ MyWidget.class @@ -14219,7 +14019,7 @@
    It shows an example of a widget that renders an image located in the htdocs static files directory in your classpath (see {@link org.apache.juneau.rest.annotation.RestResource#staticFiles() @RestResource.staticFiles()}):

    -

    +

    public class MyWidget extends Widget { @Override /* Widget */ @@ -14257,7 +14057,7 @@

    Example:
    -

    +

    public class MyWidget extends Widget { ... @@ -14299,10 +14099,10 @@

    The sample root page below includes some default branding for Juneau and Apache:

    -

    +

    http://localhost:10000/helloWorld

    - +

    In particular, you may want to replace these icons:

    @@ -14315,7 +14115,7 @@

    The Juneau icon shown is a result of the header annotation on the {@link org.apache.juneau.rest.BasicRestServlet} class:

    -

    +

    @RestResource( ... htmldoc=@HtmlDoc( @@ -14345,7 +14145,7 @@ To change this image, you can extend the BasicRestServlet class and simply override the annotations pointing to your own icon.

    -

    +

    @RestResource( ... htmldoc=@HtmlDoc( @@ -14368,7 +14168,7 @@

    The footer icon shown is generated by a predefined widget:

    -

    +

    @RestResource( htmldoc=@HtmlDoc( widgets={ @@ -14383,7 +14183,7 @@

    The widget definition is shown below:

    -

    +

    public class PoweredByApache extends Widget { /** @@ -14399,7 +14199,7 @@

    To provide your own footer icon, simply define it in your own footer section:

    -

    +

    @RestResource( htmldoc=@HtmlDoc( footer="<img style='float:right;padding-right:20px;height:32px' src='$U{servlet:/my-htdocs/my-project.png}'>" @@ -14421,10 +14221,10 @@

    The sample root page renders in the default "devops" look-and-feel:

    -

    +

    http://localhost:10000

    - +

    The sample root page provides a dropdown widget to try out the other default look-and-feels:

    @@ -14432,21 +14232,21 @@

    For example, the "light" look-and-feel:

    -

    +

    http://localhost:10000/?stylesheet=styles%2Flight.css

    - +

    And the "dark" look-and-feel:

    -

    +

    http://localhost:10000/?stylesheet=styles%2Fdark.css

    - +

    The stylesheet URL is controlled by the {@link org.apache.juneau.rest.annotation.HtmlDoc#stylesheet() @HtmlDoc.stylesheet()} annotation.
    The {@link org.apache.juneau.rest.BasicRestServlet} class defines the stylesheet served up as a static file: -

    +

    @RestResource( htmldoc=@HtmlDoc( stylesheet="$C{REST/stylesheet,servlet:/styles/devops.css}", @@ -14465,7 +14265,7 @@ To provide your own stylesheet, simply override the stylesheet attribute and point to a different file:

    -

    +

    @RestResource( htmldoc=@HtmlDoc( stylesheet="servlet:/my-styles/my-style.css}", @@ -14482,7 +14282,7 @@

    In case you're curious about how the menu item works, it's defined via a widget:

    -

    +

    @RestResource( htmldoc=@HtmlDoc( widgets={ @@ -14504,7 +14304,7 @@ specialized widget for creating pop-up menus.
    In the case of StyleMenuItem, it's simply returning a list of links wrapped in a div tag:

    -

    +

    import static org.apache.juneau.dto.html5.HtmlBuilder.*; public class StyleMenuItem extends MenuItemWidget { @@ -14547,7 +14347,7 @@

    Example:
    -

    +

    // Servlet with default headers @RestResource( @@ -14610,7 +14410,7 @@

    Example:
    -

    +

    logger.logObjects(DEBUG, "Pojo contents:\n{0}", myPojo);

    @@ -14627,7 +14427,7 @@

    In addition, the logger can be accessed by passing it as a parameter to your REST java method:

    -

    +

    @RestMethod() public Object doSomething(RestLogger logger) {...}

    @@ -14655,7 +14455,7 @@

    Non-OK (200) status codes are automatically triggered by the following conditions:

    -
  • ModuleClassPatternInitialization
    time
    Request
    time
    +
    @@ -14719,7 +14519,7 @@

    For example, the URL "/sample/foo?method=BAR" will cause the following method to be invoked...

    -

    +

    @RestMethod(name="BAR") public void doBar(RestRequest req, RestResponse res) { // Handle BAR requests @@ -14729,7 +14529,7 @@ To support overloaded methods, the {@link org.apache.juneau.rest.annotation.RestResource#allowedMethodParams() @RestResource.allowedMethodParams()} setting must be enabled on your servlet.

    -

    +

    @RestResource( // Allow &method parameter on BAR requests allowedMethodParams="BAR" @@ -14744,7 +14544,7 @@

    The following URL parameters have special meaning and can be passed in through the URL of the request:

    -
    Code Description
    +
    @@ -14815,7 +14615,7 @@ It's the PhotosResource class pulled from the Samples project. It shows an example of defining a serializer and parser to handle images.

    -

    +

    /** * Sample resource that allows images to be uploaded and retrieved. */ @@ -14939,7 +14739,7 @@

    The following code shows how to register your REST servlets in an OSGi Activator:

    -

    +

    package org.apache.juneau.examples.rest; import org.osgi.framework.*; @@ -15013,7 +14813,7 @@ The following simplified example shows how a method on a POJO on a server can be called through an interface on a client...

    -

    +

    @Remoteable public interface IAddressBook { @@ -15057,7 +14857,7 @@

    The client side code for invoking this method is shown below...

    -

    +

    // Create a RestClient using JSON for serialization, and point to the server-side remoteable servlet. RestClient client = RestClient.create() .rootUrl("http://localhost:10000/remoteable") @@ -15078,7 +14878,7 @@

    Under the covers, this method call gets converted to a REST POST.

    -

    +

    HTTP POST http://localhost:10000/remoteable/org.apache.juneau.examples.rest.IAddressBook/createPerson Accept: application/json Content-Type: application/json @@ -15108,7 +14908,7 @@ To define a remoteable interface, simply add the {@link org.apache.juneau.remoteable.Remoteable @Remoteable} annotation to your interface class.

    -

    +

    @Remoteable public interface MyInterface {...}

    @@ -15130,7 +14930,7 @@ The RemoteableServlet class is a simple specialized servlet with an abstract getServiceMap() method to define the server-side POJOs:

    -

    +

    @RestResource( path="/remoteable" ) @@ -15158,7 +14958,7 @@
    You simply define a Java method whose return type is an interface, and return the implementation of that interface:

    -

    +

    // Our exposed proxy object. @RestMethod(name=PROXY, path="/addressbookproxy/*") public IAddressBook getProxy() { @@ -15193,7 +14993,7 @@ little additional code.
    The entire code for the RestClient.getRemoteableProxy(Class) method is shown below:

    -

    +

    public <T> T getRemoteableProxy(final Class<T> interfaceClass) { return (T)Proxy.newProxyInstance( interfaceClass.getClassLoader(), @@ -15238,7 +15038,7 @@
    The method that must be implemented is {@link org.apache.juneau.rest.remoteable.RemoteableServlet#getServiceMap()} that simply returns a mapping of Java interfaces (or classes) to POJO instances.

    -

    +

    @RestResource( path="/remoteable" ) @@ -15268,36 +15068,36 @@

    If you point your browser to that URL, you get a list of available interfaces:

    -

    +

    http://localhost:10000/remoteable

    - +

    Clicking the hyperlinks on each shows you the list of methods that can be invoked on that service.
    Note that the IAddressBook link shows that you can only invoke methods defined on that interface, whereas the AddressBook link shows ALL public methods defined on that class.

    IAddressBook
    -

    +

    http://localhost:10000/remoteable/org.apache.juneau.examples.addressbook.IAddressBook

    - +

    Since AddressBook extends from LinkedList, you may notice familiar collections framework methods listed.

    AddressBook
    -

    +

    http://localhost:10000/remoteable/org.apache.juneau.examples.addressbook.AddressBook

    - +

    Let's see how we can interact with this interface through nothing more than REST calls to get a better idea on how this works.
    We'll use the same method call as in the introduction.
    First, we need to create the serialized form of the arguments:

    -

    +

    Object[] args = new Object[] { new CreatePerson("Test Person", AddressBook.toCalendar("Aug 1, 1999"), @@ -15309,7 +15109,7 @@

    That produces the following JSON output:

    -

    +

    [ { name: 'Test Person', @@ -15336,7 +15136,7 @@
    Methods are invoked by POSTing the serialized object array to the URI of the interface method. In this case, we want to POST our JSON to the following URL:

    -

    +

    http://localhost:10000/remoteable/org.apache.juneau.examples.addressbook.IAddressBook/createPerson(org.apache.juneau.examples.addressbook.CreatePerson)

    @@ -15344,16 +15144,16 @@
    We also want the results to be returned as JSON, so we set the Accept header to text/json as well.

    - +

    When we execute the POST, we should see the following successful response whose body contains the returned Person bean serialized to JSON:

    - +

    From there, we could use the following code snippet to reconstruct the response object from JSON:

    -

    +

    String response = "output from above"; Person p = JsonParser.DEFAULT.parse(response, Person.class);

    @@ -15361,7 +15161,7 @@ If we alter our servlet to allow overloaded GET requests, we can invoke methods using nothing more than a browser...

    -

    +

    @RestResource( path="/remoteable", @@ -15373,19 +15173,19 @@

    For example, to invoke the getPeople() method on our bean:

    -

    +

    http://localhost:10000/remoteable/org.apache.juneau.examples.addressbook.IAddressBook/getPeople?method=POST

    - +

    Here we call the findPerson(int) method to retrieve a person and get the returned POJO (in this case as HTML since that's what's in the Accept header when calling from a browser):

    -

    +

    http://localhost:10000/remoteable/org.apache.juneau.examples.addressbook.IAddressBook/findPerson(int)?method=POST&body=@(3)

    - +

    When specifying the POST body as a &body parameter, the method arguments should be in UON notation. @@ -15399,9 +15199,9 @@ passing parameters in UON notation as URL-encoded form posts.

    Sample form entry page
    - +
    Sample form entry page results
    - + @@ -15418,7 +15218,7 @@

    For example, to expose only the first 2 methods in our IAddressBook interface...

    -

    +

    public interface IAddressBook { @Remoteable Person createPerson(CreatePerson cp) throws Exception; @Remoteable Person findPerson(int id); @@ -15429,7 +15229,7 @@

    On the server side, the option to restrict access to only annotated methods is defined through a property:

    -

    +

    @RestResource( path="/remoteable", properties={ @@ -15443,7 +15243,7 @@ The @Remoteable annotation can also be applied to the interface class to expose all public methods defined on that interface.

    -

    +

    @Remoteable public interface IAddressBook { Person createPerson(CreatePerson cp) throws Exception; @@ -15470,7 +15270,7 @@

    The general approach starts with defining a resolver that uses the Spring application context for resolution:

    -

    +

    public class SpringRestResourceResolver extends RestResourceResolverSimple { private final ApplicationContext appContext; @@ -15494,7 +15294,7 @@

    Next, define the Spring configuration to return our resolver:

    -

    +

    @Configuration public abstract class MySpringConfiguration { @@ -15519,7 +15319,7 @@ Finally, define your Root resource with a constructor that takes in our rest resource resolver and sets it on the config object during initialization.

    -

    +

    @RestResource( children={ ... @@ -15543,7 +15343,7 @@

    After that, just define constructors on your child resources to take in Spring beans:

    -

    +

    @RestResource( path="/child" ) @@ -15590,7 +15390,7 @@ properties for labeling and linking to child resources.
    The following examples is pulled from the REST examples:

    -

    +

    public class PredefinedLabelsResource extends BasicRestServlet { @RestMethod(name=GET, path="/") @@ -15610,7 +15410,7 @@ The internals of the class show it simply has two bean properties with a link annotation defined on the name property:

    -

    +

    public class ResourceDescription { @Html(link="servlet:/{name}") @@ -15623,7 +15423,7 @@ The {@link org.apache.juneau.rest.labels.BeanDescription} class provides a simple view of a bean and it's properties.

    -

    +

    @RestMethod(name=GET, path="/beanDescription") public BeanDescription getBeanDescription() { return new BeanDescription(Person.class); @@ -15637,7 +15437,7 @@ The {@link org.apache.juneau.html.annotation.HtmlLink @HtmlLink} annotation can also be useful for rendering custom hyperlinks:

    -

    +

    @RestMethod(name=GET, path="/htmlLinks") public ALink[] htmlLinks() { return new ALink[] { @@ -15689,7 +15489,7 @@

    Maven Dependency
    -

    +

    <dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-rest-server-jaxrs</artifactId> @@ -15698,12 +15498,12 @@

    Java Library
    -

    +

    juneau-rest-server-jaxrs-7.1.0.jar

    OSGi Module
    -

    +

    org.apache.juneau.rest.server_7.1.0.jar

    @@ -15787,7 +15587,7 @@
    Maven Dependency
    -

    +

    <dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-rest-client</artifactId> @@ -15796,12 +15596,12 @@

    Java Library
    -

    +

    juneau-rest-client-7.1.0.jar

    OSGi Module
    -

    +

    org.apache.juneau.rest.client_7.1.0.jar

    @@ -15813,7 +15613,7 @@ Built upon the Apache HttpClient libraries, it extends that API and provides specialized APIs for working with REST interfaces while maintaining all the functionality available in the HttpClient API.

    -

    +

    // Create a reusable JSON client. try (RestClient client = RestClient.create().build()) { @@ -15872,7 +15672,7 @@

    Example:
    -

    +

    // Examples below use the Juneau Address Book resource example // Create a reusable client with JSON support @@ -15986,7 +15786,7 @@ special annotations that tell us how to convert input and output to HTTP headers, query parameters, form post parameters, or request/response bodies.

    -

    +

    // Our interface. @Remoteable public interface MyProxyInterface { @@ -16004,7 +15804,7 @@

    The call above translates to the following REST call:

    -

    +

    POST http://hostname/some/rest/interface/method?debug=true HTTP/1.1 Accept: application/json Content-Type: application/json @@ -16122,7 +15922,7 @@

    Example:
    -

    +

    // Create a client that ignores self-signed or otherwise invalid certificates. RestClientBuilder builder = RestClient.create() .enableSSL(SSLOpts.LAX); @@ -16134,7 +15934,7 @@

    This is functionally equivalent to the following:

    -

    +

    RestClientBuilder builder = RestClient.create(); HostnameVerifier hv = new NoopHostnameVerifier(); @@ -16167,7 +15967,7 @@

    Contents of MyConfig.cfg
    -

    +

    #================================================================================ # My Connection Settings #================================================================================ @@ -16177,7 +15977,7 @@

    Code that reads an SSLOpts bean from the config file
    -

    +

    // Read config file and set SSL options based on what's in that file. Config c = Config.create("MyConfig.cfg").build(); SSLOpts ssl = c.getObject(SSLOpts.class, "Connection/ssl"); @@ -16201,7 +16001,7 @@

    Example:
    -

    +

    // Create a client that performs BASIC authentication using the specified user/pw. RestClient restClient = RestClient.create() .basicAuth(HOST, PORT, USER, PW) @@ -16210,7 +16010,7 @@

    This is functionally equivalent to the following:

    -

    +

    RestClientBuilder builder = RestClient.create(); AuthScope scope = new AuthScope(HOST, PORT); Credentials up = new UsernamePasswordCredentials(USER, PW); @@ -16236,7 +16036,7 @@ The following example shows how the JazzRestClient class provides FORM-based authentication support.

    -

    +

    /** * Constructor. */ @@ -16317,7 +16117,7 @@ The following example shows how the JazzRestClient class provides OIDC authentication support.

    -

    +

    /** * Constructor. */ @@ -16462,7 +16262,7 @@

    Example:
    -

    +

    // Throw a RestCallException if SUCCESS is not found in the output. restClient.doPost(URL) .successPattern("SUCCESS") @@ -16474,7 +16274,7 @@

    Example:
    -

    +

    // Throw a RestCallException if FAILURE or ERROR is found in the output. restClient.doPost(URL) .failurePattern("FAILURE|ERROR") @@ -16492,7 +16292,7 @@

    Example:
    -

    +

    final List<Number> xList = new ArrayList<Number>(); final List<String> yList = new ArrayList<String>(); @@ -16550,7 +16350,7 @@

    Example:
    -

    +

    // Pipe output from REST call to System.out in real-time. restClient.doPost(URL).byLines().pipeTo(new PrintWriter(System.out)).run();

    @@ -16570,7 +16370,7 @@
    This causes the following output to be generated by the Java org.apache.juneau.rest.client logger at WARNING level:

    -

    +

    === HTTP Call (outgoing) ======================================================= === REQUEST === POST http://localhost:10000/testUrl HTTP/1.1 @@ -16596,7 +16396,7 @@ This setting also causes a Debug: true header value to trigger logging of the request on the server side as well.

    -

    +

    === HTTP Request (incoming) ==================================================== HTTP POST /testUrl ---Headers--- @@ -16626,7 +16426,7 @@

    Example:
    -

    +

    // Log the HTTP request/response to the specified logger. int rc = restClient.doGet(URL).logTo(INFO, getLogger()).run();

    @@ -16652,7 +16452,7 @@ The {@link org.apache.juneau.rest.client.RestCallLogger} class is an example of an interceptor that uses the various lifecycle methods to log HTTP requests.

    -

    +

    /** * Specialized interceptor for logging calls to a log file. */ @@ -16751,7 +16551,7 @@ The {@link org.apache.juneau.rest.client.RestClientBuilder#rootUrl(Object)} method can be used to specify a root URL on all requests so that you don't have to use absolute paths on individual calls.

    -

    +

    // Create a rest client with a root URL RestClient rc = RestClient.create().rootUrl("http://localhost:9080/foobar").build(); String r = rc.doGet("/baz").getResponseAsString(); // Gets "http://localhost:9080/foobar/baz" @@ -16762,7 +16562,7 @@
    For example, if you're parsing a response into POJOs and you want to ignore fields that aren't on the POJOs, you can use the {@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownBeanProperties} property.

    -

    +

    // Create a rest client that ignores unknown fields in the response RestClient rc = RestClient.create() .set(BEAN_ignoreUnknownBeanProperties, true) @@ -16776,7 +16576,7 @@
    This can be particularly useful if you're attempting to connect to a REST resource that may be in the process of still initializing.

    -

    +

    // Create a rest call that retries every 10 seconds for up to 30 minutes as long as a connection fails // or a 400+ is received. restClient.doGet(URL) @@ -16792,7 +16592,7 @@

    Maven Dependency
    -

    +

    <dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-microservice-server</artifactId> @@ -16801,17 +16601,17 @@

    Java Library
    -

    +

    juneau-microservice-server-7.1.0.jar

    OSGi Module
    -

    +

    org.apache.juneau.microservice.server_7.1.0.jar

    Microservice Starter Project
    -

    +

    my-microservice.zip

    @@ -16902,7 +16702,7 @@ RootResources.java - The top-level REST resource.
    This class routes HTTP requests to child resources:

    -

    +

    @RestResource( path="/", title="My Microservice", @@ -16931,7 +16731,7 @@
    Contains various useful settings.
    Can be used for your own resource configurations.

    -

    +

    #======================================================================================================================= # Basic configuration file for REST microservices # Subprojects can use this as a starting point. @@ -17022,7 +16822,7 @@ jetty.xml - The Jetty configuration file.
    A bare-bones config file that can be extended to use any Jetty features.

    -

    +

    <Configure id="ExampleServer" class="org.eclipse.jetty.server.Server"> <Set name="connectors"> @@ -17101,7 +16901,7 @@ Go to Run -> Run Configurations -> Java Application -> my-microservice and click Run.
    In your console view, you should see the following output:

    -

    +

    Running class 'RestMicroservice' using config file 'my-microservice.cfg'. Server started on port 10000 @@ -17116,10 +16916,10 @@ Now open your browser and point to http://localhost:10000. You should see the following:

    -

    +

    http://localhost:10000

    - +

    You have started a REST interface on port 10000.
    You can enter the command exit to shut it down. @@ -17137,7 +16937,7 @@

    The easiest way to build your microservice is to run the following from the project root.

    -

    +

    mvn clean install

    @@ -17151,13 +16951,13 @@

    To start from a command line, run the following command from inside your target directory:

    -

    +

    java -jar my-microservice-1.0.jar

    You should see the following console output:

    -

    +

    Running class 'RestMicroservice' using config file 'my-microservice.cfg'. Server started on port 10000 @@ -17184,7 +16984,7 @@ The generated META-INF/MANIFEST.MF file is used to describe the microservice.
    If you open it, you'll see the following:

    -

    +

    Main-Class: org.apache.juneau.microservice.RestMicroservice Main-ConfigFile: my-microservice.cfg

    @@ -17209,7 +17009,7 @@ The {@link org.apache.juneau.microservice.Microservice#getManifest()} method is a static method that can be used to retrieve the manifest file as a {@link org.apache.juneau.utils.ManifestFile}.

    -

    +

    // Get Main-Class from manifest file. String mainClass = Microservice.getInstance().getManifest().getString("Main-Class", "unknown");

    @@ -17248,14 +17048,14 @@
  • {@link org.apache.juneau.rest.RestContext#getConfig()}
    Any initialization-time variables can be used.
    Example usage:
    -

    +

    #------------------------------- # Properties for MyHelloResource #------------------------------- [MyHelloResource] greeting = Hello world!

    -

    +

    @RestResource(...) public class MyHelloResource extends BasicRestServlet { // Access config file when initializing fields. @@ -17279,7 +17079,7 @@
    Any initialization-time or request-time variables can be used.

    Example usage:
    -

    +

    #----------------------------- # Contents of microservice.cfg #----------------------------- @@ -17287,7 +17087,7 @@ greeting = Hello $RP{person}! localizedGreeting = $L{HelloMessage,$RP{person}}

    -

    +

    #--------------------------------- # Contents of MyHelloResource.java #--------------------------------- @@ -17311,7 +17111,7 @@ } }

    -

    +

    #--------------------------------------- # Contents of nls/Messages_en.properties #--------------------------------------- @@ -17363,13 +17163,13 @@ Now let's take a look at the resource classes themselves.
    The top-level page...

    -

    +

    http://localhost:10000

    - +

    ...is generated by this class... -

    +

    @RestResource( path="/", title="My Microservice", @@ -17406,14 +17206,14 @@

    If you click the helloWorld link in your application, you'll get a simple hello world message:

    -

    +

    http://localhost:10000/helloWorld

    - +

    ...which is generated by this class...

    -

    +

    @RestResource( path="/helloWorld", title="Hello World example", @@ -17490,13 +17290,13 @@

    First, the manifest file needs to be modified to point to our new microservice:

    -

    +

    Main-Class: com.foo.SampleCustomRestMicroservice

    Then we define the following class:

    -

    +

    /** * Sample subclass of a RestMicroservice that provides customized behavior. * This class must be specified in the Main-Class entry in the manifest file and optionally @@ -17539,7 +17339,7 @@

    Archive File
    -

    +

    juneau-examples-core-7.1.0.zip

    @@ -17578,7 +17378,7 @@
    Archive File
    -

    +

    juneau-examples-rest-7.1.0.zip

    @@ -17609,10 +17409,10 @@ The microservice can be started from the juneau-examples-rest.launch file. It will start up the microservice on port 10000 which you can then view through a browser:

    -

    +

    http://localhost:10000

    - + @@ -17643,14 +17443,14 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000

    - +

    The RootResources class can also be defined as a servlet in a web.xml file:

    -

    +

    <web-app version='2.3'> <servlet> <servlet-name>RootResources</servlet-name> @@ -17667,7 +17467,7 @@

    RootResources.java
    -

    +

    /** * Sample REST resource showing how to implement a "router" resource page. */ @@ -17775,7 +17575,7 @@

    HelloWorldResource.java
    -

    +

    /** * Sample REST resource that prints out a simple "Hello world!" message. */ @@ -17821,18 +17621,18 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/helloWorld

    - +

    Using the special &Accept=text/json and &plainText=true parameters allows us to see this page rendered as JSON:

    -

    +

    http://localhost:10000/helloWorld?Accept=text/json&plainText=true

    - +
    @@ -17859,7 +17659,7 @@

    MethodExampleResource.java
    -

    +

    /** * Sample REST resource that shows how to define REST methods and OPTIONS pages */ @@ -18089,17 +17889,17 @@

    When you visit this page through the router page, you can see the top level page:

    -

    +

    http://localhost:10000/methodExample

    - +

    Clicking the first link on the page results in this page:

    -

    +

    http://localhost:10000/methodExample/example1/foo/123/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/path-remainder?q1=456&q2=bar

    - +

    Notice how the conversion to POJOs is automatically done for us, even for non-standard POJOs such as UUID.

    @@ -18136,7 +17936,7 @@

    BasicRestServlet.java
    -

    +

    /** OPTIONS request handler */ @RestMethod(name=OPTIONS, path="/*") public Swagger getOptions(RestRequest req) { @@ -18148,7 +17948,7 @@ through a property defined by the {@link org.apache.juneau.html.HtmlDocSerializer} class and specified on the resource class annotation:

    -

    +

    @RestResource( htmldoc=@HtmlDoc( navlinks={ @@ -18165,10 +17965,10 @@

    Clicking the options link on the page presents you with information about how to use this resource:

    -

    +

    http://localhost:10000/methodExample/?method=OPTIONS

    - +

    This page (like any other) can also be rendered in JSON or XML by using the &Accept URL parameter.

    @@ -18193,7 +17993,7 @@

    UrlEncodedFormResource.java
    -

    +

    /** * Sample REST resource for loading URL-Encoded form posts into POJOs. */ @@ -18284,7 +18084,7 @@

    UrlEncodedFormResource.properties
    -

    +

    #-------------------------------------------------------------------------------- # UrlEncodedFormResource labels #-------------------------------------------------------------------------------- @@ -18302,18 +18102,18 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/urlEncodedForm

    - +

    Entering some values and clicking submit causes the form bean to be populated and returned back as a POJO response:

    -

    +

    http://localhost:10000/urlEncodedForm

    - +
    Additional Information
      @@ -18355,7 +18155,7 @@

      RequestEchoResource.java
      -

      +

      /** * Sample REST resource for echoing HttpServletRequests back to the browser */ @@ -18428,7 +18228,7 @@

      Hypothetical RequestEchoResource.createSerializers() method
      -

      +

      /** Override the default rest serializers to add some transforms through an INIT hook*/ @RestHook(INIT) public void init(RestContextBuilder builder) throws Exception { @@ -18452,10 +18252,10 @@ Pointing a browser to the resource shows the following:

      -

      +

      http://localhost:10000/echo

      - +

      This gives you an idea of what kinds of POJO models can be serialized, since you are serializing a regular old HttpServletRequest object. @@ -18508,10 +18308,10 @@

      Pointing a browser to the resource shows the following:

      -

      +

      http://localhost:10000/addressBook/people

      - + @@ -18551,7 +18351,7 @@

      package-info.java
      -

      +

      // XML and RDF namespaces used in this package @Xml(ns="ab", namespaces={ @@ -18582,7 +18382,7 @@

      IAddressBook.java
      -

      +

      /** * Interface used to help illustrate proxy interfaces. * See {@link SampleRemoteableServlet}. @@ -18624,7 +18424,7 @@

      AddressBook.java
      -

      +

      /** Address book bean */ @Bean(typeName="addressBook") public class AddressBook extends LinkedList<Person> implements IAddressBook { @@ -18661,7 +18461,7 @@

      Person.java
      -

      +

      /** Person bean */ @Xml(prefix="per") @Rdf(prefix="per") @@ -18727,7 +18527,7 @@

      Address.java
      -

      +

      /** Address bean */ @Xml(prefix="addr") @Rdf(prefix="addr") @@ -18773,7 +18573,7 @@

      CreatePerson.java
      -

      +

      /** Person creator bean */ @Xml(prefix="per") @Rdf(prefix="addr") @@ -18802,7 +18602,7 @@

      CreateAddress.java
      -

      +

      /** Address creator bean */ @Xml(ns="addr") @Rdf(ns="addr") @@ -18834,7 +18634,7 @@

      AddressBookResource.java
      -

      +

      /** * Proof-of-concept resource that shows off the capabilities of working with POJO resources. * Consists of an in-memory address book repository. @@ -19205,7 +19005,7 @@

      AddressBookResource.properties
      -

      +

      title = AddressBook sample resource description = Proof-of-concept resource that shows off the capabilities of working with POJO resources @@ -19292,17 +19092,17 @@

      Pointing a browser to the resource shows the results of running the getRoot() method:

      -

      +

      http://localhost:10000/addressBook

      - +

      Clicking the people link shows you the result of running the getAllPeople() method:

      -

      +

      http://localhost:10000/addressBook/people

      - +

      Notice how the URI properties automatically became hyperlinks.

      @@ -19315,22 +19115,22 @@

      JSON
      -

      +

      http://localhost:10000/addressBook/people?Accept=text/json&plainText=true

      - +
      Lax JSON
      -

      +

      http://localhost:10000/addressBook/people?Accept=text/json+simple&plainText=true

      - +
      XML
      -

      +

      http://localhost:10000/addressBook/people?Accept=text/xml&plainText=true

      - +

      Notice how our XML_enableNamespaces and XML_autoDetectNamespaces settings result in namespaces being used. @@ -19341,10 +19141,10 @@

      RDF/XML
      -

      +

      http://localhost:10000/addressBook/people?Accept=text/xml+rdf+abbrev&plainText=true

      - +

      Notice how the @BeanProperty(uri=true) annotations are used to identify values for rdf:about values. @@ -19358,22 +19158,22 @@

      HTML Schema
      -

      +

      http://localhost:10000/addressBook/people?Accept=text/html+schema

      - +
      JSON Schema
      -

      +

      http://localhost:10000/addressBook/people?Accept=text/json+schema&plainText=true

      - +
      XML Schema
      -

      +

      http://localhost:10000/addressBook/people?Accept=text/xml+schema&plainText=true

      - +

      Now let's see what else you can do.

      @@ -19381,18 +19181,18 @@ Clicking on the first personUri link executes the getPerson() method, which renders a serialized Person object:

      -

      +

      http://localhost:10000/addressBook/people/1

      - +

      Clicking on the OPTIONS link on the page shows you the Swagger doc generated from our annotations and resource bundle properties:

      -

      +

      http://localhost:10000/addressBook/?method=OPTIONS

      - +
    @@ -19403,15 +19203,15 @@ Because you added the Traversable converter to the getPerson method, you can also address child nodes in the POJO model through path remainders:

    -

    +

    http://localhost:10000/addressBook/people/1/addresses/0

    - +

    -

    +

    http://localhost:10000/addressBook/people/1/addresses/0/street

    - +
  • @@ -19424,22 +19224,22 @@

    Show only the name and addresses columns
    -

    +

    http://localhost:10000/addressBook/people?v=name,addresses

    - +
    Show only names that start with 'B*'
    -

    +

    http://localhost:10000/addressBook/people?s=name=B*

    - +
    Show only entries with age greater than 60
    -

    +

    http://localhost:10000/addressBook/people?s=age>=60

    - +
    @@ -19450,10 +19250,10 @@ The Introspectable converter on the getPerson method allows us to invoke public methods on the addressed POJO (in this case, public methods on the String class):

    -

    +

    http://localhost:10000/addressBook/people/1/name?invokeMethod=substring(int,int)&invokeArgs=[1,5]

    - +
    @@ -19469,7 +19269,7 @@

    ClientTest.java
    -

    +

    /** * Sample client code for interacting with AddressBookResource */ @@ -19556,7 +19356,7 @@

    The output from running this code is the following:

    -

    +

    Running client test... Number of entries = 2 Deleted person Barack Obama, response = DELETE successful @@ -19581,7 +19381,7 @@
    The same actions done programmatically in the last section can also be done using URLs.
    By default, you can override the HTTP Method and Content through GET parameters, as shown below:

    -

    +

    // Delete the existing entries http://localhost:10000/addressBook/people/1?method=DELETE http://localhost:10000/addressBook/people/2?method=DELETE @@ -19644,27 +19444,27 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/tempDir

    - +

    Pointing a browser to the upload link shows a form entry page:

    -

    +

    http://localhost:10000/tempDir/upload

    - +

    Submitting a file redirects to the top-level page:

    -

    +

    http://localhost:10000/tempDir

    - +
    TempDirResource.java
    -

    +

    /** * Sample resource that extends DirectoryResource to open up the temp directory as a REST resource. */ @@ -19778,27 +19578,27 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/atom

    - +

    True ATOM feeds require using an Accept:text/xml header:

    -

    +

    http://localhost:10000/atom?Accept=text/xml&plainText=true

    - +

    Other languages, such as JSON are also supported:

    -

    +

    http://localhost:10000/atom?Accept=text/json&plainText=true

    - +
    AtomFeedResource.java
    -

    +

    /** * Sample resource that shows how to generate ATOM feeds. */ @@ -19909,12 +19709,12 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/docker

    - +
    DockerRegistryResource.java
    -

    +

    /** * Sample resource that shows how to mirror query results from a Docker registry. */ @@ -19992,7 +19792,7 @@ In this example, we're pulling the aside message from an external file:

    resources/DockerRegistryResourceAside.html
    -

    +

    <div style='min-width:200px' class='text'> <p>REST API for searching Docker registries.</p> <p>To use, you must first specify the Docker registry URL in the <code>[Docker]</code> section of the config file.</p> @@ -20004,7 +19804,7 @@

    examples.cfg
    -

    +

    #================================================================================ # DockerRegistryResource properties #================================================================================ @@ -20034,13 +19834,13 @@ Pointing a browser at a Tumblr blog name, such as ibmblr causes a REST call to be make to the Tumblr blog and the results to be parsed:

    -

    +

    http://localhost:10000/tumblrParser/ibmblr

    - +
    TumblrParserResource.java
    -

    +

    @RestResource( path="/tumblrParser", messages="nls/TumblrParserResource", @@ -20126,20 +19926,20 @@

    The resource consists of a simple registry of images with integer IDs.

    -

    +

    http://localhost:10000/photos

    - +

    It is initialized with a single entry, which can be accessed through a GET request.

    -

    +

    http://localhost:10000/photos/cat

    - +
    PhotosResource.java
    -

    +

    /** * Sample resource that allows images to be uploaded and retrieved. */ @@ -20304,20 +20104,20 @@ The resource consists of a pre-initialized {@link org.apache.juneau.dto.jsonschema.Schema} object. Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/jsonSchema

    - +

    For true JSON-Schema, you need to specify the header Accept: text/json:

    -

    +

    http://localhost:10000/jsonSchema?Accept=text/json&plainText=true

    - +
    JsonSchemaResource.java
    -

    +

    /** * Sample resource that shows how to serialize JSON-Schema documents. */ @@ -20413,21 +20213,21 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/sqlQuery

    - +

    Running a query results in the following output:

    -

    +

    select count(*) from SYS.SYSTABLES; select TABLEID,TABLENAME,TABLETYPE from SYS.SYSTABLES;

    - +
    SqlQueryResource.java
    -

    +

    /** * Sample resource that shows how Juneau can serialize ResultSets. */ @@ -20589,7 +20389,7 @@ }

    samples.cfg
    -

    +

    #================================================================================ # SqlQueryResource properties #================================================================================ @@ -20612,24 +20412,24 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/config

    - +

    An edit page is provided for altering the raw config file:

    -

    +

    http://localhost:10000/config/edit

    - +

    The {@link org.apache.juneau.config.Config} class is a serializable POJO, which makes the resource relatively straightforward to implement.

    ConfigResource.java
    -

    +

    /** * Shows contents of the microservice configuration file. */ @@ -20767,10 +20567,10 @@

    Pointing a browser to the resource shows the following:

    -

    +

    http://localhost:10000/logs

    - + @@ -20809,7 +20609,7 @@

    The following example shows a potential vector that circumvents the restriction above:

    -

    +

    // Don't do this! Class c = Class.forName(someUserInputString); JsonParser.DEFAULT.parse(input, c); // Oops! Security hole! @@ -20831,7 +20631,7 @@ vulnerabilities. However, it is possible to circumvent this through your swap implementation as shown below:

    -

    +

    // Don't do this! public class MyInsecureSwap extends PojoSwap<ObjectMap,Object> { public Object swap(BeanSession session, ObjectMap input) throws Exception { @@ -20883,7 +20683,7 @@ An example of a potential security hole is shown below that could potentially expose any file on a file system through a REST request:

    -

    +

    public String doUnsafeGet(RestRequest req) { // Security hole! return req.getVarResolver().resolve("$RQ{foo}"); @@ -21442,7 +21242,7 @@

  • Added the following annotations to the {@link org.apache.juneau.rest.BasicRestServlet} class (which were previously defined on the Resource class): -

    +

    @RestResource( htmldoc=@HtmlDoc( navlinks={ @@ -21507,7 +21307,7 @@

    • New static create() methods for builders on serializers and parsers.
      This simplifies the syntax of creation of serializers and parsers by scratch. -

      +

      // Old way JsonSerializer s1 = new JsonSerializerBuilder().ws().build(); @@ -21552,7 +21352,7 @@

    • New pluggable console commands.
      When you start up the microservice, you'll now see the following: -

      +

      Running class 'RestMicroservice' using config file 'examples.cfg'. Server started on port 10000 @@ -21584,7 +21384,7 @@

      Commands are pluggable and extensible through the config file. -

      +

      #======================================================================================================================= # Console settings #======================================================================================================================= @@ -21657,7 +21457,7 @@ Removed annotation @HtmlDoc(favIcon).
      This was a discouraged way of defining fav-icons anyway, and with the addition of @HtmlDoc(head), you can define them using: -

      +

      head={ "<link rel='icon' href='$U{servlet:/htdocs/juneau.png}'/>" } @@ -21678,7 +21478,7 @@

      The library now consists of the following artifacts found in the Maven group "org.apache.juneau":

      -
  • GET Parameter Description
    +
    @@ -21863,7 +21663,7 @@
    Replaces the @Pojo and @BeanProperty.swap() annotations.
  • Support for per-media-type swaps.
    Programmatic example: -

    +

    @Swap(MyJsonOnlySwap.class) public class MyPojo {} @@ -21878,7 +21678,7 @@ }


    Annotated example: -

    +

    @Swap(impl=ToStringSwap.class, mediaTypes="*/json") public class MyBean { ... } @@ -21890,7 +21690,7 @@

  • Support for templated swaps which provide additional context information for a swap.
    The following is an example of a templated swap class used to serialize POJOs to HTML using FreeMarker: -

    +

    // Our abstracted templated swap class. public abstract class FreeMarkerSwap extends PojoSwap<Object,Reader> { @@ -21903,13 +21703,13 @@ } }

    -

    +

    @Swap(impl=FreeMarkerSwap.class, template="MyPojo.div.ftl") public class MyPojo {}

  • New {@link org.apache.juneau.annotation.Swaps @Swaps} annotation for defining multiple swaps against the same POJO when they're differentiated by media types: -

    +

    @Swaps( { @Swap(MyJsonSwap.class), @@ -21929,7 +21729,7 @@ directly to the output stream or writer.
    When used with conjunction with PojoSwaps, this can be used to provide customized output for specific content types. -

    +

    @Pojo(swap=MyBeanSwap.class) public class MyBean {...} @@ -21950,7 +21750,7 @@

  • {@link org.apache.juneau.serializer.SerializerSession} and {@link org.apache.juneau.parser.ParserSession} objects are now reusable if used within the same thread. -

    +

    // Old way (still works) JsonSerializer.DEFAULT.serialize(writer1, pojo1); JsonSerializer.DEFAULT.serialize(writer2, pojo2); @@ -22216,7 +22016,7 @@

    • {@link org.apache.juneau.rest.annotation.HtmlDoc#navlinks() navlinks()} - Now an array of strings instead of a JSON object. Simplified syntax.
      For example: -

      +

      // Old syntax htmldoc=@HtmlDoc( links="{" @@ -22332,7 +22132,7 @@

    Instead, the {@link org.apache.juneau.rest.BasicRestServlet} class defines the following default header that can be easily overridden: -

    +

    htmldoc=@HtmlDoc( header={ "<h1>$R{resourceTitle}</h1>", @@ -22347,7 +22147,7 @@ files in the classpath.
    The DockerRegistryResource examples shows how it can be used to pull in a localized file from the classpath to populate the aside section of a page. -

    +

    htmldoc=@HtmlDoc( // Pull in aside contents from file. aside="$F{resources/DockerRegistryResourceAside.html}" @@ -22397,7 +22197,7 @@

  • All parsers now allow for numeric types with 'K'/'M'/'G' suffixes to represent kilobytes, megabytes, and gigabytes. -

    +

    // Example int i = JsonParser.DEFAULT.parse("123M"); // 123MB

    @@ -22452,11 +22252,11 @@
  • "request:/..." - Relative to the request URI. For example, currently we define HTML page links using variables and servlet-relative URIs... -

    +

    pages="{up:'$R{requestParentURI}', options:'?method=OPTIONS', upload:'upload'}"

    With these new protocols, we can define them like so: -

    +

    links="{top:'context:/', up:'request:/..' ,options:'servlet:/?method=OPTIONS', upload:'servlet:/upload'}"

    The old method of using variables and servlet-relative URIs will still be supported, but using @@ -22479,7 +22279,7 @@
  • New annotation property: {@link org.apache.juneau.annotation.BeanProperty#value() @BeanProperty.value()}.
    The following two annotations are considered equivalent: -

    +

    @BeanProperty(name="foo") @BeanProperty("foo") @@ -22623,7 +22423,7 @@

  • ConfigFile - The external config file for the resource. So, for example... -

    +

    /** Old way */ @RestMethod(name="*", path="/example1/{a1}/{a2}/{a3}/*") public String example1( @@ -22801,7 +22601,7 @@ Revamped the serializer, parser classes to use builders for creation. Serializers and parsers are now unmodifiable objects once they are created. This is a breaking code change that will require adoption. -

    +

    /* Creating a new serializer or parser */ // Old way @@ -22939,7 +22739,7 @@

  • @RestResource.pageLinks()
  • @RestMethod.pageLinks() -

    +

    // Old method @RestResource( properties={ @@ -22960,7 +22760,7 @@ Typically you're going to simply want to use the title and description annotations which apply to both the page title/text and the swagger doc:

    -

    +

    @RestResource( title="System properties resource", description="REST interface for performing CRUD operations on system properties.", @@ -22972,7 +22772,7 @@ and is now immutable. It also includes a new {@link org.apache.juneau.rest.StreamResourceBuilder} class.

  • Simplified remoteable proxies using the @RestMethod(name="PROXY") annotation on REST methods. Used to expose interface proxies without the need for {@link org.apache.juneau.rest.remoteable.RemoteableServlet}. -

    +

    // Server side @RestMethod(name="PROXY", path="/myproxy/*") public IAddressBook getProxy() { @@ -22988,7 +22788,7 @@ without affecting functionality. Very useful for debugging.

  • You can now use numeric values in path annotations.
    When using numeric variable names, you don't need to specify the variable name in the @Path annoation: -

    +

    @RestMethod(name="GET", path="/myurl/{0}/{1}/{2}/*") public void doGet(RestRequest req, RestResponse res, @Path String foo, @Path int bar, @Path UUID baz) { @@ -23161,7 +22961,7 @@ Using these methods, you can construct arbitrarily complex objects consisting of maps and collections. You could do this before, but it required constructing a ClassMeta object.
    For example: -

    +

    // Old way: ClassMeta<?> cm = parser.getMapClassMeta( HashMap.class, @@ -23180,7 +22980,7 @@

  • No need for casting anymore if you were using the old parseMap() and parseCollection() methods!
  • Changes allow me to eliminate BeanContext.normalizeClassMeta() method.
  • Convenience methods added for setting parser properties: -

    +

    // Old way: new JsonParser().setProperty(PARSER_strict, true).setProperty(BEAN_locale, mylocale); @@ -23191,7 +22991,7 @@

  • Improvements to Serializer class:
    • Convenience methods added for setting serializer properties: -

      +

      // Old way: new JsonSerializer().setProperty(JSON_simpleMode, true).setProperty(SERIALIZER_quoteChar, '"'); @@ -24237,13 +24037,13 @@

    • Added methods RestServlet.getDescription(RestRequest) and RestServlet.getLabel(RestRequest).
    • {@link org.apache.juneau.rest.BasicRestServlet} and RestServletJenaDefault now provide default HTML titles and descriptions: -

      +

      @Property(name=HTMLDOC_title, value="$R{resourceTitle}"), @Property(name=HTMLDOC_description, value="$R{resourceDescription}")

    • Options pages on {@link org.apache.juneau.rest.BasicRestServlet} and RestServletJenaDefault now provide default descriptions and back links: and descriptions: -

      +

      @Property(name=HTMLDOC_navlinks, value="{back:'$R{servletURI}"), @Property(name=HTMLDOC_description, value="Resource options")

      @@ -24985,7 +24785,7 @@
      • New support for runtime-replaced variables in REST resource properties: -

        +

        @RestResource( messages="nls/Messages", properties={ diff --git a/juneau-doc/src/main/javadoc/resources/juneau-code.css b/juneau-doc/src/main/javadoc/resources/juneau-code.css index d58bb74..ed078e0 100644 --- a/juneau-doc/src/main/javadoc/resources/juneau-code.css +++ b/juneau-doc/src/main/javadoc/resources/juneau-code.css @@ -78,6 +78,16 @@ p.bcode { box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.5); } +.w400 { + width:400px !important; +} +.w500 { + width:500px !important; +} +.w800 { + width:800px !important; +} + /*--- Bordered code in a section of a method doc ---*/ dd p.bcode { margin-left:0px; diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/code-highlighting.css b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/code-highlighting.css deleted file mode 100644 index a016a6c..0000000 --- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/htdocs/code-highlighting.css +++ /dev/null @@ -1,136 +0,0 @@ -/*************************************************************************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations under the License. * - ***************************************************************************************************************************/ -code, -tt, -pre, -dt code { - font-size: 9pt; -} - -/*--- Bordered code ---*/ -p.bcode { - font-size: 9pt; - white-space: pre; - border: 1px solid black; - margin: 10px 20px; - padding: 10px; - border-radius: 10px; - overflow: hidden; - font-family: monospace; - background-color: #f8f8f8; - border-color: #cccccc; - -moz-tab-size: 3; - tab-size: 3; - -o-tab-size: 3; -} - -.fixedWidth { - max-width: 800px; -} - -/* Override padding bottom in javadoc comments. */ -.blockList p.bcode { - padding-bottom: 0px !important; -} - -/*--- Unbordered code ---*/ -p.code { - font-size: 9pt; - white-space: pre; - font-family: monospace; - padding-bottom: 15px; - margin: -15px; -} - -td.code { - font-size: 9pt; - white-space: pre; - font-family: monospace; -} - -table.code { - font-size: 9pt; - white-space: pre; - font-family: monospace; -} - -/*--- Java code effects ---*/ -jc,jd,jt,jk,js,jf,jsf,jsm,ja { - font-size: 9pt; - white-space: pre; - font-family: monospace; -} -/* Comment */ -jc { - color: green; -} -/* Javadoc comment */ -jd { - color: #3f5fbf; -} -/* Javadoc tag */ -jt { - color: #7f9fbf; - font-weight: bold; -} -/* Primitive */ -jk { - color: #7f0055; - font-weight: bold; -} -/* String */ -js { - color: blue; -} -/* Field */ -jf { - color: blue; -} -/* Static field */ -jsf { - color: blue; - font-style: italic; -} -/* Static method */ -jsm { - font-style: italic; -} -/* Annotation */ -ja { - color: grey; -} - -/*--- XML code effects ---*/ -xt,xa,xc,xs { - font-size: 9pt; - white-space: pre; - font-family: monospace; -} - -xt { - color: DarkCyan; -} - -xa { - color: purple; -} - -xc { - color: mediumblue; -} - -xs { - color: blue; - font-style: italic; -} - -- To stop receiving notification emails like this one, please contact jamesbognar@apache.org.

  • CategoryMaven ArtifactsDescriptionPrereqs