Apache Juneau Overview
Juneau is a single cohesive framework consisting of the following parts:
Questions via email to dev@juneau.apache.org are always welcome.
Juneau is packed with features that may not be obvious at first. Users are encouraged to ask for code reviews by providing links to specific source files such as through GitHub. Not only can we help you with feedback, but it helps us understand usage patterns to further improve the product.
Juneau started off as a popular internal IBM toolkit called Juno. Originally used for serializing POJOs to and from JSON, it later expanded in scope to include a variety of content types, and then later REST servlet, client, and microservice APIs. It's use grew to more than 50 projects and was one of the most popular community source projects within IBM.
In June of 2016, the code was donated to the Apache Foundation under the project
We've strived to keep prerequisites to an absolute minimum in order to make adoption as easy as possible.
The library consists of the following artifacts found in the Maven group "org.apache.juneau":
| Category | Maven Artifacts | Description | Prerequisites |
|---|---|---|---|
| juneau-core | juneau-marshall | Serializers and parsers for:
|
|
| juneau-marshall-rdf |
Serializers and parsers for:
|
|
|
| juneau-dto |
Data Transfer Objects for:
|
|
|
| juneau-svl | Simple Variable Language API |
|
|
| juneau-config | Configuration file API |
|
|
| juneau-rest | juneau-rest-server | REST Servlet API |
|
| juneau-rest-server-jaxrs | Optional JAX-RS support |
|
|
| juneau-rest-client | REST Client API |
|
|
| juneau-microservice | juneau-microservice-server | REST Microservice Server API |
|
| juneau-examples | juneau-examples-core | Core code examples | |
| juneau-examples-rest | REST code examples | ||
| juneau-all | juneau-all |
Combination of the following:
|
|
Each component are also packaged as stand-alone OSGi modules.
juneau-marshall-7.0.0.jar
org.apache.juneau.marshall_7.0.0.jar
The juneau-marshall artifact contains the API for defining serializers and parsers, and
marshalling support for JSON, XML, HTML, URL-Encoding, UON and others.
It also defines many convenience utility classes used throughout the framework.
One of the goals of Juneau was to make serialization as simple as possible. In a single line of code, you should be able to serialize and parse most POJOs. Despite this simplicity, Juneau provides lots of extensibility and configuration properties for tailoring how POJOs are serialized and parsed.
The built-in serializers in Juneau are fast, efficient, and highly configurable. They work by serializing POJOs directly to streams instead of using intermediate Document Object Model objects.
In most cases, you can serialize objects in one line of code by using one of the default serializers:
In addition to the default serializers, customized serializers can be created using various built-in options:
Default serialization support is provided for Java primitives, Maps, Collections,
beans, and arrays.
Extensible support for other data types such as Calendars, Dates,
Iterators is available through the use of POJO swaps (described later).
Parsers work by parsing input directly into POJOs instead of having to create intermediate Document Object Models. This allows them to parse input with minimal object creation.
Like the serializers, you can often parse objects in one line of code by using one of the default parsers:
The parsers can also be used to populating existing bean and collection objects:
Above the serializers and parsers are the {@link org.apache.juneau.serializer.SerializerGroup} and
{@link org.apache.juneau.parser.ParserGroup} classes.
These classes allow serializers and parsers to be retrieved by W3C-compliant HTTP Accept
and Content-Type values...
The REST servlet API builds upon the SerializerGroup and ParserGroup classes
to provide annotated REST servlets that automatically negotiate the HTTP media types and allow the developer
to work with requests and responses as POJOs.
The {@link org.apache.juneau.ObjectMap} and {@link org.apache.juneau.ObjectList} classes are generic Java representations of JSON objects and arrays. These classes can be used to create "unstructured" models for serialization (as opposed to "structured" models consisting of beans). If you want to quickly generate JSON/XML/HTML from generic maps/collections, or parse JSON/XML/HTML into generic maps/collections, these classes work well.
These classes extend directly from the following JCF classes:
The
These object can be serialized in one of two ways:
Any valid JSON can be parsed into an unstructured model consisting of generic
{@link org.apache.juneau.ObjectMap} and {@link org.apache.juneau.ObjectList} objects.
(In theory, any valid XML can also be parsed into an unstructured model, although this has not been
officially 'tested')
The ObjectMap and ObjectList classes have many convenience features:
Serializers and parsers have a wide variety of configurable properties.
They all extend from the {@link org.apache.juneau.BeanContextBuilder} class that allows you to easily construct
new instances from scratch or build upon existing instances.
For example, the following code shows how to configure a JSON serializer:
WriterSerializer s = JsonSerializer
.
Configurable settings can also be set declaratively.
The following produces the same serializer.
WriterSerializer s = JsonSerializer
.
However, each of the serializers and parsers already contain reusable instances with common configurations.
For example, JSON has the following predefined reusable serializers and parsers:
These can be used directly, as follows:
For performance reasons, serializers and parsers are immutable.
However, they can be 'copied' and modified using the builder() method.
The following is a list of all configurable properties across all serializers and parsers.
All the serializers, parsers, and REST server/client classes use the following design pattern:
BeanContext, JsonSerializer
BeanContextBuilder, JsonSerializerBuilder
Context objects.
BeanSession, JsonSerializerSession
Context contains one PropertyStore.
PropertyStore objects.
ContextBuilder contains one PropertyStoreBuilder.
For example, the class hierarchy for JsonSerializer is:
Object
Each context object in the hierarchy define properties that can be stored in a PropertyStore
such as
The class hierarchy for JsonSerializerBuilder is:
Object
The class hierarchy for JsonSerializerSession is:
Object
The general idea behind a {@link org.apache.juneau.PropertyStore} is to serve as a reusable configuration of an artifact (such as a serializer) such that the artifact can be cached and reused if the property stores are 'equal'.
For example, two serializers of the same type created with the same configuration will always end up being the same serializer:
This has the effect of significantly improving performance, especially if you're creating many serializers and parsers.
The {@link org.apache.juneau.PropertyStoreBuilder} class is used to build up and instantiate immutable
PropertyStore objects.
In the example above, the property store being built looks like the following:
PropertyStore ps = PropertyStore
.
Property stores are immutable, comparable, and their hashcodes are calculated exactly one time. That makes them particularly suited for use as hashmap keys, and thus for caching reusable serializers and parsers.
Refer to the {@link org.apache.juneau.PropertyStore} javadoc for a detailed explaination on how property stores work.
By default, the Juneau framework can serialize and parse a wide variety of POJOs out-of-the-box.
However, two special classes are provided tailor how certain Java objects are handled by the framework.
These classes are:
Transforms are added to serializers and parsers (and REST clients) using the following configuration properties:
Annotations are also provided for specifying transforms directly on classes and methods (all described in later sections):
{@link org.apache.juneau.transform.PojoSwap PojoSwaps} are a critical component of Juneau. They allow the serializers and parsers to handle Java objects that wouldn't normally be serializable.
Swaps are, simply put, 'object swappers' that swap in serializable objects for non-serializable ones during serialization, and vis-versa during parsing.
Some examples of non-serializable POJOs are File, Reader,
Iterable, etc...
These are classes that aren't beans and cannot be represented as simple maps, collections, or primitives.
In the following example, we introduce a PojoSwap that will swap in ISO8601 strings for
Date objects:
The swap can then be associated with serializers and parsers like so:
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:
Another example of a PojoSwap is one that converts arrays to
BASE64-encoded strings:
The following example shows the BASE64 swap in use:
Several PojoSwaps are already provided for common Java objects:
In particular, the {@link org.apache.juneau.transforms.CalendarSwap} and {@link org.apache.juneau.transforms.DateSwap} transforms provide a large number of customized swaps to ISO, RFC, or localized strings.
Swaps have access to the session locale and timezone through the {@link org.apache.juneau.BeanSession#getLocale()} and
{@link org.apache.juneau.BeanSession#getTimeZone()} methods.
This allows you to specify localized swap values when needed.
If using the REST server API, the locale and timezone are set based on the Accept-Language and
Time-Zone headers on the request.
Swaps can also be defined per-media-type.
The {@link org.apache.juneau.transform.PojoSwap#forMediaTypes()} method can be overridden to
provide a set of media types that the swap is invoked on.
It's also possible to define multiple swaps against the same POJO as long as they're differentiated
by media type.
When multiple swaps are defined, the best-match media type is used.
In the following example, we define 3 swaps against the same POJO. One for JSON, one for XML, and one for all other types.
In the previous sections, we defined two-way swaps, meaning swaps where the original objects could be
reconstructing during parsing.
However, there are certain kinds of POJOs that we may want to support for serializing, but that are not
possible to reconstruct during parsing.
For these, we can use one-way object swaps.
A one-way POJO swap is simply an object transform that only implements the {@code swap()} method.
The {@code unswap()} method is simply left unimplemented.
An example of a one-way swaps would be one that allows {@code Iterators} to be serialized as JSON arrays.
It can make sense to be able to render {@code Iterators} as arrays, but in general it's not possible to
reconstruct an {@code Iterator} during parsing.
Here is an example of our one-way swap being used.
Note that trying to parse the original object will cause a {@link org.apache.juneau.parser.ParseException}
to be thrown.
{@link org.apache.juneau.annotation.Swap @Swap} can be used to associate a swap class using an
annotation.
This is often cleaner than using the builder pojoSwaps() method since you can keep
your swap class near your POJO class.
Multiple swaps can be associated with a POJO by using the {@link org.apache.juneau.annotation.Swaps @Swaps} annotation:
Readers get serialized directly to the output of a serializer.
Therefore it's possible to implement a swap that provides fully-customized output.
The
The {@link org.apache.juneau.annotation.Swap#template() @Swap.template()} annotation allows you to associate
arbitrary contextual strings with swaps.
The primary purpose is for providing template names, such as for Apache FreeMarker, therefore
the name 'template'.
However, the usage of the string is open-ended.
For example, you could pair a template string like so:
The implementation of the FreeMarker swap would look something like this:
Various methods can be defined on a class directly to affect how it gets serialized.
This can often be simpler than using PojoSwaps.
Objects serialized as Strings can be parsed back into their original objects by
implementing one of the following methods on the class:
public static T fromString(String) method.
valueOf(String)
parse(String)
parseString(String)
forName(String)
forString(String)
public T(String) constructor.
Note that these methods cover conversion from several built-in Java types, meaning the parsers can automatically construct these objects from strings:
fromString(String) - {@link java.util.UUID}
valueOf(String) - {@link java.lang.Boolean}, {@link java.lang.Byte},
{@link java.lang.Double}, {@link java.lang.Float},
{@link java.lang.Integer}, {@link java.lang.Long}, {@link java.lang.Short}, {@link java.sql.Date},
{@link java.sql.Time}, {@link java.sql.Timestamp}
parse(String) - {@link java.text.DateFormat}, {@link java.text.MessageFormat},
{@link java.text.NumberFormat}, {@link java.util.Date}, {@link java.util.logging.Level}
parseString(String) - {@link javax.xml.bind.DatatypeConverter}
forName(String) - {@link java.lang.Class}
If you want to force a bean-like class to be serialized as a string, you can use the
{@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore} annotation on the class to force it to be
serialized to a string using the toString() method.
Serializing to other intermediate objects can be accomplished by defining a swap method directly on the class:
public X swap(BeanSession) method, where X is any serializable
object.
The BeanSession parameter allows you access to various information about the current
serialization session.
For example, you could provide customized results based on the media type being produced
({@link org.apache.juneau.BeanSession#getMediaType()}).
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.
Swapped objects can be converted back into their original form by the parsers by specifying one of the following methods:
public static T unswap(BeanSession, X) method where X is the
swap class type.
public T(X) constructor where X is the swap class type.
The following shows how our form template class can be modified to allow the parsers to reconstruct our original object:
Surrogate classes are very similar in concept to PojoSwaps except they're simpler to define.
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):
This could be solved with the following PojoSwap.
However, the same can be accomplished by using a surrogate class that simply contains a constructor with the non-serializable class as an argument:
The surrogate class is registered in the same way as a PojoSwap:
When the serializer encounters the non-serializable class, it will serialize an instance of the surrogate instead.
The {@link org.apache.juneau.annotation.Bean @Bean} annotation is used to tailor how beans are interpreted by the framework.
Bean property inclusion and ordering on a bean class can be done using the {@link org.apache.juneau.annotation.Bean#properties() @Bean.properties()} annotation.
Bean properties can be excluded using the {@link org.apache.juneau.annotation.Bean#excludeProperties() @Bean.excludeProperties()} annotation.
Bean properties can be sorted alphabetically using {@link org.apache.juneau.annotation.Bean#sort() @Bean.sort()}
The {@link org.apache.juneau.annotation.Bean#propertyNamer() @Bean.propertyNamer()} annotation is used to provide customized naming of properties.
Property namers are used to transform bean property names from standard form to some other form.
For example, the {@link org.apache.juneau.PropertyNamerDLC} will convert property names to
dashed-lowercase, and these will be used as attribute names in JSON and element names in XML.
The {@link org.apache.juneau.annotation.Bean#interfaceClass @Bean.interfaceClass()} annotation is used
to limit properties on beans to specific interface classes.
When specified, only the list of properties defined on the interface class will be used during
serialization.
Additional properties on subclasses will be ignored.
Note that this annotation can be used on the parent class so that it filters to all child classes.
Or can be set individually on the child classes.
The {@link org.apache.juneau.annotation.Bean#stopClass @Bean.stopClass()} annotation is another
way to limit which properties are serialized (except from the opposite direction).
It's identical in purpose to the stop class specified by {@link java.beans.Introspector#getBeanInfo(Class, Class)}.
Any properties in the stop class or in its base classes will be ignored during analysis.
For example, in the following class hierarchy, instances of C3 will include property
p3, but not p1 or p2.
The {@link org.apache.juneau.annotation.Bean#propertyFilter() @Bean.propertyFilter()} annotation and {@link org.apache.juneau.transform.PropertyFilter} class can be used to perform interception and inline handling of bean getter and setter calls.
The {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotation is used to tailor how individual bean properties are interpreted by the framework.
The {@link org.apache.juneau.annotation.BeanProperty#name() @BeanProperty.name()} annotation is used to override the name of the bean property.
If the {@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility} setting on the bean context excludes this field (e.g. the visibility is set to the default of PUBLIC, but the field is PROTECTED), this annotation can be used to force the field to be identified as a property.
The bean property named
This is similar in concept to the Jackson
The primary purpose is for backwards compatibility in parsing newer streams with addition
information into older beans.
The following shows various ways of using dynamic bean properties.
Similar rules apply for value types and swaps.
The property values optionally can be any serializable type or use swaps.
The {@link org.apache.juneau.annotation.BeanProperty#value() @BeanProperty.value()} annotation
is a synonym for {@link org.apache.juneau.annotation.BeanProperty#name() @BeanProperty.name()}.
Use it in cases where you're only specifying a name so that you can shorten your annotation.
The following annotations are equivalent:
The {@link org.apache.juneau.annotation.BeanProperty#type() @BeanProperty.type()} annotation
is used to identify a specialized class type for a generalized property.
Normally the type is inferred through reflection of the field type or getter return type.
However, you'll want to specify this value if you're parsing beans where the bean property class
is an interface or abstract class to identify the bean type to instantiate.
Otherwise, you may cause an {@link java.lang.InstantiationException} when trying to set these fields.
This property must denote a concrete class with a no-arg constructor.
The {@link org.apache.juneau.annotation.BeanProperty#params() @BeanProperty.params()} annotation
is for bean properties of type map or collection.
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.
The {@link org.apache.juneau.annotation.BeanProperty#properties() @BeanProperty.properties()}
annotation is used to limit which child properties are rendered by the serializers.
It can be used on any of the following bean property types:
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.
The {@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor} annotation is used to
map constructor arguments to property names on bean with read-only properties.
Since method parameter names are lost during compilation, this annotation essentially redefines
them so that they are available at runtime.
The definition of a read-only bean is a bean with properties with only getters, like shown below:
Beans can also be defined with a combination of read-only and read-write properties.
The {@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore} annotation is used to ignore classes, fields, and methods from being interpreted as beans or bean components.
When applied to classes, objects will be converted to strings even though they look like beans.
When applied to fields and getters/setters, they will be ignored as bean properties.
The {@link org.apache.juneau.annotation.NameProperty @NameProperty} annotation is used to identify a setter as a method for setting the name of a POJO as it's known by its parent object.
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.
The {@link org.apache.juneau.annotation.ParentProperty @ParentProperty} annotation is used to identify a setter as a method for adding a parent reference to a child object.
A commonly-used case is when you're parsing beans and a child bean has a reference to a parent bean.
Parsers will automatically set this field for you in the child beans.
Juneau parsers can use builders to instantiate POJOs.
This is useful in cases where you want to create beans with read-only properties.
Note that while it's possible to do this using the {@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor}
annotation, using builders can often be cleaner.
A typical builder usage is shown below:
MyBean b = MyBean.
The code for such a builder is shown below:
The POJO class can be any type including beans.
Builders MUST be beans with one or more writable properties.
The bean properties themselves do not need to be readable (i.e. getters are optional).
Builders require two parts:
The first can be accomplished through any of the following:
create() method on the POJO class that returns a builder instance.
The second can be accomplished through any of the following:
build() method on the builder class.
Juneau serializers have sophisticated support for transforming relative URIs to absolute form.
The following example shows a bean containing URIs of various forms and how they end up serialized.
URI resolution is controlled by the following settings:
Juneau automatically interprets any {@link java.net.URL} and {@link java.net.URI} objects as URIs and will
resolve them accordingly.
The {@link org.apache.juneau.annotation.URI @URI} annotation can be used to extend that to other bean
properties and class types so that they also get interpreted as URIs.
For example:
The {@link org.apache.juneau.transform.BeanFilter} class is the programmatic equivalent to the {@link org.apache.juneau.annotation.Bean @Bean} annotation.
In practice, it's usually simpler to use the {@link org.apache.juneau.annotation.Bean @Bean} and
{@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotations on your bean classes.
However, bean filters make it possible to accomplish the same when you can't add annotations
to existing code.
Bean filters are defined through {@link org.apache.juneau.transform.BeanFilterBuilder BeanFilterBuilders}.
In the previous examples, we defined this bean annotation:
The programmatic equivalent would be:
Bean filters are added to serializers and parsers using the following:
For example:
Note that if you use the annotation, you do NOT need to set anything on the serializers/parsers.
The annotations will be detected and bean filters will automatically be created for them.
The {@link org.apache.juneau.BeanContextBuilder#beanFilters(Object...)} method also allows you to pass in interfaces.
Any class that's not a subclass of {@link org.apache.juneau.transform.BeanFilterBuilder} get interpreted
as bean interface classes.
These cause bean implementations of those interfaces to only expose the properties defined on the
interface.
Occasionally, you may want to limit bean properties to only those defined on a parent class or interface.
This is accomplished through interface filters.
Interface filters are defined through the following:
For example, let's define the following interface and implementation:
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:
When serialized, the serialized bean will only include properties defined on the interface.
WriterSerializer s = JsonSerializer
.
The {@link org.apache.juneau.BeanContextBuilder#beanFilters(Object...)} method will automatically interpret any
non-BeanFilter classes passed in as meaning interface classes.
So in the previous example, the BeanFilter class could have been avoided altogether by just
passing in MyInterface. to the serializer, like so:
WriterSerializer s = JsonSerializer
.
The annotation equivalent is {@link org.apache.juneau.annotation.Bean#interfaceClass() Bean#interfaceClass()}.
The annotation can be used in a couple of ways.
Using the annotation on an interface will be inherited by all children.
The annotation can be used on parent classes as well.
Child beans will only serialize properties defined on the parent class.
Whereas interface filters limit properties defined on child classes, stop filters do the opposite and limit properties defined on parent classes.
Stop classes are defined through the following:
Stop classes are identical in purpose to the stop class specified by {@link java.beans.Introspector#getBeanInfo(Class, Class)}.
Any properties in the stop class or in its base classes will be ignored during serialization.
For example, in the following class hierarchy, instances of C3 will include property p3,
but not p1 or p2.
Juneau serializers treat instances of Readers and InputStreams special by
simply serializing their contents directly to the output stream or writer.
This allows you to embed fully customized serializer output.
Note that if you're serializing Readers and InputStreams, it's up to you to make sure you're producing valid output (in this case JSON).
A more typical scenario where this is useful is by using swaps to convert POJOs to Readers whose
contents are determined via the {@link org.apache.juneau.BeanSession#getMediaType()} method.
In the following example, we're customizing the JSON output for a particular bean type, but leaving
all other renditions as-is:
While parsing into beans, Juneau attempts to determine the class types of bean properties through
reflection on the bean property getter or setter.
Often this is insufficient if the property type is an interface or abstract class that cannot be
instantiated.
This is where bean names and dictionaries come into play.
Bean names and dictionaries are used for identifying class types when they cannot be inferred through reflection.
Bean classes are given names through the {@link org.apache.juneau.annotation.Bean#typeName() @Bean.typeName()}
annotation.
These names are then added to the serialized output as virtual
On the parsing side, these type names are resolved to classes through the use of bean dictionaries.
For example, if a bean property is of type Object, then the serializer will add
When serialized as JSON,
{
x: [
{_type:
Type names can be represented slightly differently in different languages.
For example, the dictionary name is used as element names when serialized to XML.
This allows the typeName annotation to be used as a shortcut for defining element names for
beans.
When serialized as XML, the bean is rendered as:
Bean dictionaries are registered through the following:
The bean dictionary setting can consist of any of the following types:
The
When using the annotation, you'll typically want to define it on an interface class so that it can be inherited by all subclasses.
object, array, number, boolean, null.
In addition to the bean type name support described above, simplified support is provided for bean subtypes.
Bean subtypes are similar in concept to bean type names, except for the following differences:
In the following example, the abstract class has two subclasses:
When serialized, the subtype is serialized as a virtual
JsonSerializer s = JsonSerializer.
The following shows what happens when parsing back into the original object.
JsonParser p = JsonParser.
The {@link org.apache.juneau.BeanContext#BEAN_useInterfaceProxies} setting (enabled by default) allows the Juneau parsers to parse content into virtual beans (bean interfaces without implementation classes).
For example, the following code creates an instance of the specified unimplemented interface:
Getter and setter values can be any parsable values, even other virtual beans.
Under-the-covers, a virtual bean is simply a proxy interface on top of an existing BeanMap
instance. From a programmatic point-of-view, they're indistinguishable from real beans, and can be
manipulated and serialized like any other bean.
Virtual beans can also be created programmatically using the BeanContext class:
Address address = BeanContext.
The following parsers can be configured to read continous streams of objects from the same input stream:
The {@link org.apache.juneau.json.JsonParser} and {@link org.apache.juneau.uon.UonParser}
classes can read continous streams by using the {@link org.apache.juneau.parser.Parser#PARSER_unbuffered}
setting.
This prevents the parsers from using an internal buffer that would read past the end of the currently
parsed POJO.
Note that this isn't perfect in all cases since you can't combine two JSON numbers into a single
reader (e.g. "123" + "456" = "123456").
For obvious reasons, do not use the following properties when reading continuous streams:
The {@link org.apache.juneau.msgpack.MsgPackParser} class doesn't use any internal buffering to begin with, so it can be used with continuous streams without any special properties.
Juneau was developed independently from Jackson, but shares many of the same features and capabilities. Whereas Jackson was created to work primarily with JSON, Juneau was created to work for multiple languages. Therefore, the terminology and annotations in Juneau are similar, but language-agnostic.
The following charts describe equivalent features between the two libraries:
| Jackson | Juneau |
|---|---|
|
|
{@link org.apache.juneau.annotation.BeanProperty @BeanProperty} |
|
|
{@link org.apache.juneau.annotation.BeanProperty#name() @BeanProperty(name="*")} |
|
|
{@link org.apache.juneau.annotation.BeanIgnore @BeanIgnore} |
|
{@link org.apache.juneau.annotation.Bean#excludeProperties @Bean(excludeProperties="...")} |
|
No equivalent annotation, but can be controlled via:
{@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility} {@link org.apache.juneau.BeanContext#BEAN_beanMethodVisibility} Future annotation support planned. |
|
|
{@link org.apache.juneau.annotation.BeanConstructor @BeanConstructor} |
|
No equivalent.
Future support planned. |
|
|
|
Juneau uses swaps to convert non-serializable object to serializable forms:
{@link org.apache.juneau.annotation.Swap @Swap} |
|
No equivalent annotation, but can be controlled via various settings:
{@link org.apache.juneau.BeanContext} {@link org.apache.juneau.serializer.Serializer} Future annotation support planned. |
|
|
{@link org.apache.juneau.annotation.Bean#properties @Bean(properties="...")}
{@link org.apache.juneau.annotation.Bean#sort @Bean(sort=x)} |
|
|
|
Can be replicated using swaps with Reader swapped values.
|
The following chart shows POJOs categorized into groups and whether they can be serialized or parsed:
| Group | Description | Examples | Can serialize? | Can parse? |
|---|---|---|---|---|
| 1 | Java primitives and primitive objects |
|
yes | yes |
| 2 | Java Collections Framework objects and Java arrays | |||
| 2a |
With standard keys/values
Map keys are group [1, 4a, 6a] objects. Map, Collection, and array values are group [1, 2, 3ac, 4a, 6a] objects. |
|
yes | yes |
| 2b |
With non-standard keys/values
Map keys are group [2, 3, 4b, 5, 6b, 7] objects. Map, Collection, and array values are group [3b, 4b, 5, 6b, 7] objects. |
|
yes | no |
| 3 | Java Beans | |||
| 3a |
With standard properties
These are beans that have one or more properties defined by public getter or public fields. Properties can also be defined as final read-only fields and passed in as constructor args. Property values are group [1, 2, 3ac, 4a, 6a] objects. |
yes | yes | |
| 3b |
With non-standard properties or not true beans
These include true beans that have one or more properties defined by getter and setter methods or properties, but property types include group [3b, 4b, 5, 6b, 7] objects. This also includes classes that look like beans but aren't true beans. For example, classes that have getters but not setters, or classes without no-arg constructors. |
yes | no | |
| 3c |
Virtual beans
These are unimplemented bean interfaces with properties of type [1, 2, 3ac, 4a, 6a] objects. Parsers will automatically create interface proxies on top of BeanMap instances. |
yes | yes | |
| 3d |
Read-only beans without setters
The same as 3a, but without property setters or constructor args. |
yes | no | |
| 4 |
Swapped objects
These are objects that are not directly serializable, but have {@link org.apache.juneau.transform.PojoSwap PojoSwaps} associated with them. The purpose of a POJO swap is to convert an object to another object that is easier to serialize and parse. For example, the {@link org.apache.juneau.transforms.DateSwap.ISO8601DT} class can be used to serialize {@link java.util.Date} objects to ISO8601 strings, and parse them back into {@link java.util.Date} objects. |
|||
| 4a |
2-way swapped to group [1, 2a, 3ac] objects
For example, a swap that converts a {@code Date} to a {@code String}. |
|
yes | yes |
| 4b |
1-way swapped to group [1, 2, 3] objects
For example, a swap that converts an {@code Iterator} to a {@code List}. This would be one way, since you cannot reconstruct an {@code Iterator}. |
|
yes | no |
| 5 |
Readers and InputStreams
Contents are serialized directly to the output stream or writer. Typically used for low-level language-specific replacement of POJOs using per-Media-Type POJO swaps. |
|
yes | no |
| 6 |
Non-serializable objects with standard methods for converting to a serializable form |
|||
| 6a |
Classes with a method that converts it to a serializable form:
|
|
yes | yes |
| 6b |
Classes that only have a method to convert to a serializable form:
|
yes | no | |
| 7 |
All other objects
Anything that doesn't fall into one of the groups above are simply converted to {@code Strings} using the {@code toString()} method. |
yes | no |
Extensive javadocs exist for individual language support. Refer to these docs for language-specific information.
juneau-marshall-rdf-7.0.0.jar
org.apache.juneau.marshall.rdf_7.0.0.jar
The juneau-marshall-rdf library provides additional serializers and parsers for RDF.
These rely on the Apache Jena library to provide support for the following languages:
The serializers and parsers work identically to those in juneau-marshall, but are
packaged separately so that you don't need to pull in the Jena dependency unless you need it.
juneau-dto-7.0.0.jar
org.apache.juneau.dto_7.0.0.jar
The juneau-dto library contains several predefined POJOs for generating commonly-used document types.
This section describes support for these POJOs.
The Juneau HTML5 DTOs are simply beans with fluent-style setters that allow you to quickly construct HTML fragments as Java objects. These object can then be serialized to HTML using one of the existing HTML serializers, or to other languages such as JSON using the JSON serializers.
The {@link org.apache.juneau.dto.html5.HtmlBuilder} class is a utility class with predefined static methods that allow you to easily construct DTO instances in a minimal amount of code.
The following examples show how to create HTML tables.
| Java code | HTML |
|---|---|
|
|
|
|
|
|
|
|
Using the HTML5 DTOs, you should be able to construct any valid HTML5 from full document bodies to any possible fragments.
The {@link org.apache.juneau.html.HtmlParser} class can be used convert these HTML documents back into POJOs.
Other serializers and parsers (e.g. {@link org.apache.juneau.json.JsonSerializer}) can be used to represent these POJOs in languages other than HTML.
The Juneau ATOM feed DTOs are simply beans with fluent-style setters.
The following code shows a feed being created programmatically using the
{@link org.apache.juneau.dto.atom.AtomBuilder} class.
To serialize this to ATOM, use the {@link org.apache.juneau.xml.XmlSerializer} class:
The {@link org.apache.juneau.xml.XmlParser} class can be used convert these Atom documents back into POJOs.
Other serializers and parsers (e.g. {@link org.apache.juneau.json.JsonSerializer}) can be used to represent these POJOs in languages other than XML.
The Juneau Swagger DTOs are simply beans with fluent-style setters that allow you to quickly construct Swagger documents as Java objects. These object can then be serialized to JSON using one of the existing JSON serializers, or to other languages such as XML or HTML using the other serializers.
The {@link org.apache.juneau.dto.swagger.SwaggerBuilder} class is a utility class with predefined static methods that allow you to easily construct DTO instances in a minimal amount of code.
The following is an example Swagger document from the Swagger website.
{
This document can be generated by the following Java code:
Methods that take in beans and collections of beans can also take in JSON representations of those objects.
Properties can also be accessed via the {@link org.apache.juneau.dto.swagger.SwaggerElement#get(String,Class)}
and {@link org.apache.juneau.dto.swagger.SwaggerElement#set(String,Object)} methods.
These methods can also be used to set and retrieve non-Swagger attributes such as
Swagger docs can be parsed back into Swagger beans using the following code:
Swagger swagger = JsonParser.
juneau-svl-7.0.0.jar
org.apache.juneau.svl_7.0.0.jar
The
In a nutshell, Simple Variable Language (or SVL) is text that contains variables of the form
It is used extensively in the Config, REST and Microservice APIs.
Most variables can be recursively nested within the varKey (e.g.
The {@link org.apache.juneau.svl.VarResolver} class is used to resolve variables.
The {@link org.apache.juneau.svl.VarResolver#DEFAULT} resolver is a reusable instance of this class
configured with the following basic variables:
$S{key[,default]}
$E{key[,default]}
The following logic variables are also provided:
$IF{arg,then[,else]}
$SW{arg,pattern1:then1[,pattern2:then2...]}
$CO{arg1[,arg2...]}
$PM{arg,pattern}
$NE{arg}
$UC{arg}
$LC{arg}
The following shows how variables can be arbitrarily nested...
Variables are defined through the {@link org.apache.juneau.svl.Var} API.
The API comes with several predefined variables and is easily extensible.
The following is an example of a variable that performs URL-Encoding on strings.
The following shows the class hierarchy of the {@link org.apache.juneau.svl.Var} class:
The following is the list of default variables defined in all modules:
| Module | Class | Pattern |
|---|---|---|
| juneau-svl | {@link org.apache.juneau.svl.vars.EnvVariablesVar} | $E{key[,default]} |
| {@link org.apache.juneau.svl.vars.SystemPropertiesVar} | $S{key[,default]} | |
| {@link org.apache.juneau.svl.vars.ArgsVar} | $A{key[,default]} | |
| {@link org.apache.juneau.svl.vars.ManifestFileVar} | $MF{key[,default]} | |
| {@link org.apache.juneau.svl.vars.IfVar} | $IF{arg,then[,else]} | |
| {@link org.apache.juneau.svl.vars.SwitchVar} | $SW{arg,pattern1:then1[,pattern2:then2...]} | |
| {@link org.apache.juneau.svl.vars.CoalesceVar} | $CO{arg1[,arg2...]} | |
| {@link org.apache.juneau.svl.vars.PatternMatchVar} | $PM{arg,pattern} | |
| {@link org.apache.juneau.svl.vars.NotEmptyVar} | $NE{arg} | |
| {@link org.apache.juneau.svl.vars.UpperCaseVar} | $UC{arg} | |
| {@link org.apache.juneau.svl.vars.LowerCaseVar} | $LC{arg} | |
| juneau-config | {@link org.apache.juneau.config.vars.ConfigVar} | $C{key[,default]} |
| juneau-rest-server | {@link org.apache.juneau.rest.vars.FileVar} | $F{path[,default]}} |
| {@link org.apache.juneau.rest.vars.ServletInitParamVar} | $I{name[,default]} | |
| {@link org.apache.juneau.rest.vars.LocalizationVar} | $L{key[,args...]} | |
| {@link org.apache.juneau.rest.vars.RequestAttributeVar} | $RA{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestFormDataVar} | $RF{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestHeaderVar} | $RH{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestHeaderVar} | $RI{key} | |
| {@link org.apache.juneau.rest.vars.RequestPathVar} | $RP{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestQueryVar} | $RQ{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.RequestVar} | $R{key1[,key2...]} | |
| {@link org.apache.juneau.rest.vars.SerializedRequestAttrVar} | $SA{contentType,key[,default]} | |
| {@link org.apache.juneau.rest.vars.UrlVar} | $U{uri}> | |
| {@link org.apache.juneau.rest.vars.UrlEncodeVar} | $UE{uriPart} | |
| {@link org.apache.juneau.rest.vars.WidgetVar} | $W{name} |
The main class for performing variable resolution is {@link org.apache.juneau.svl.VarResolver}.
Two methods are provided for resolving variables:
Var resolvers can rely on the existence of other objects.
For example, {@link org.apache.juneau.config.vars.ConfigVar} relies on the existence of a {@link org.apache.juneau.config.Config}.
This is accomplished through the following:
The following two classes are identical in behavior except for which objects they can access:
Context and session objects are set through the following methods:
Both kinds of objects are accessible through the following method:
Var resolvers can be cloned and extended by using the {@link org.apache.juneau.svl.VarResolver#builder()} method.
Cloning a resolver will copy it's {@link org.apache.juneau.svl.Var} class names and context objects.
$ , { }
'MYPROPERTY' has the value '$E{MYPROPERTY}').
So don't do that!
resolver.resolve("foobar" )) will simply be a no-op and return the same string.
juneau-config-7.0.0.jar
org.apache.juneau.config_7.0.0.jar
The juneau-config library contains a powerful API for creating and using INI-style config files.
Config files are access through the {@link org.apache.juneau.config.Config} class which
are created through the {@link org.apache.juneau.config.ConfigBuilder} class.
Builder creator methods are provided on the Config class:
Once instantiated, reading values from the config are simple:
The config language may look simple, but it is a very powerful feature with many capabilities including:
/ \ [ ] = #
Configuration files can contain entries for anything from primitive types up to complex hierarchies of POJOs consisting of maps, collections, and/or beans.
The most common case for configuration values are primitives.
The following methods are provided for accessing primitive values:
On integers and longs,
Numbers can also use hexadecimal and octal notation:
Strings with newlines get broken into separate lines:
Typically, multi-line values are started on the next line for clarity like so:
The following methods are provided for accessing POJO values:
In theory, any parsable POJO type can be represented
as a config value.
However in practice, we're typically talking about the following:
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:
Beans are represented as {@link org.apache.juneau.json.JsonSerializer#DEFAULT_LAX Lax JSON} by default:
The format for beans depends on the serializer and parser registered on the Config which is defined in the builder via the following methods:
The default parser can also be overridden on the following getters:
The following methods are provided for accessing arrays:
The getStringArray() methods allow you to retrieve comma-delimited lists of values:
String[] key1 = c.getStringArray(
String arrays can also be represented in JSON when using the getObject() methods:
String[] key1 = c.getObject(
Primitive arrays can also be retrieved using the getObject() methods:
Arrays of POJOs can also be retrieved using the getObject() methods:
Address[] addresses = c.getObject(
The following methods are provided for accessing maps and collections:
The Type,Type... arguments allow you to specify the component types for maps and collections.
List class arguments can be followed by zero or one arguments representing the entry types.
Map class arguments can be followed by zero or two arguments representing the key and value types.
The arguments can be chained to produce any data structure consisting of maps, collections, or POJOs.
Examples are shown below:
getObject("..." , List.class )
List<?>
getObject("..." , LinkedList.class )
LinkedList<?>
getObject("..." , HashSet.class , Integer.class )
HashSet<Integer>
getObject("..." , Map.class )
Map<?,?>
getObject("..." , HashMap.class )
HashMap<?,?>
getObject("..." , LinkedHashMap.class , String.class , MyBean.class )
LinkedHashMap<String,MyBean>
getObject("..." , HashMap.class , Integer.class , ArrayList.class , MyBean[].class )
LinkedHashMap<Integer,ArrayList<MyBean[]>>
List<Address> addresses = c.getObject(
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(
The following methods are provided for accessing binary data:
Binary data can be represented in 3 formats:
"Zm9vYmFycw=="
"666F6F62617273"
"66 6F 6F 62 61 72 73"
The binary data format is controlled via the following setting:
For example:
Binary lines can be split up into separate lines for readability:
Binary data line wrapping can be controlled via the following setting:
Config files can contain variables that get resolved dynamically using the previously-described {@link org.apache.juneau.svl.VarResolver} API.
Config c = Config.
By default, Configs use the {@link org.apache.juneau.svl.VarResolver#DEFAULT} variable resolver
which provides support for the following variables and constructs:
$S{key[,default]}
$E{key[,default]}
$C{key[,default]}
The variable resolver is controlled via the following setting:
Additionally, the following method can be used to retrieve a Config with a different variable resolver:
The default variable resolver also provides the following logic variables for performing simple logical operations:
$IF{arg,then[,else]}
$SW{arg,pattern1:then1[,pattern2:then2...]}
$CO{arg1[,arg2...]}
$PM{arg,pattern}
$NE{arg}
$UC{arg}
$LC{arg}
The $IF variable can be used for simple if/else logic:
The $SW variable can be used for switch blocks based on pattern matching:
The $CO variable can be used for coalescing of values (finding the first non-null/empty match):
The $PM variable can be used for calculating boolean values:
Encoded entries allow for sensitive information such as passwords to be obfuscated.
Encoded entries are denoted with a
For example, the following password is marked for encoding:
The default encoder is {@link org.apache.juneau.config.encode.ConfigXorEncoder} which is a simple XOR+Base64 encoder.
Custom encoders can be used to provide your own encoding support by implementing the {@link org.apache.juneau.config.encode.ConfigEncoder} interface.
Encoders are controlled via the following setting:
Encoded values can be set to plain-text values.
The curly brackets around the value identify whether the value has been encoded or not.
Unencoded values are encoded when the file is saved using the {@link org.apache.juneau.config.Config#commit()} method.
They can also be encoded immediately by calling {@link org.apache.juneau.config.Config#encodeEntries()}.
Config sections can be retrieved in-bulk using {@link org.apache.juneau.config.Config#getSectionAsMap(String)}.
Maps created this way are snapshot copies of the section at the time of the method call.
Config files can also be used to directly populate beans using {@link org.apache.juneau.config.Config#getSectionAsBean(String,Class,boolean)}.
Like maps, beans created this way are snapshot copies of the section at the time of the method call.
Config sections can also be accessed via interface proxies using {@link org.apache.juneau.config.Config#getSectionAsInterface(String,Class)}.
While section maps and beans retrieve copies of the configuration data at the time of the method call, section interfaces can also be use to set values in the underlying configuration.
The following methods allow you to add, remove, and modify entries and sections in a config file:
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.
The last 4 arguments in {@link org.apache.juneau.config.Config#set(String,Object,Serializer,ConfigMod[],String,List)}
are optional in that if you pass
To unset the same-line comment, you should pass in a blank string.
To remove pre-lines, you should pass in an empty list.
Sections can be added with optional pre-lines using the setSection methods:
Changes made to the configuration are transactional in nature.
They are kept in memory until you call the {@link org.apache.juneau.config.Config#commit()} method.
Until then, you still see the modified values when you call any of the getters, but the modified values
exist only in memory.
Changes can be rolled back using the {@link org.apache.juneau.config.Config#rollback()} method.
In general, external file modifications will be detected immediately in the Config
object when a watcher thread is enabled (explained later).
Otherwise, they are detected when a commit is performed.
The Config object maintains an in-memory record of all changes that have been applied to it
through getters and setters.
When the underlying file changes, the new contents are loaded and the in-memory changes are then
applied to the new configuration.
This provides the benefits of real-time updates of configurations while not losing any changes made in the JVM.
If the commit() method is called on the Config objects after the file system
contents have been modified, we will then reload the configuration from the file system, apply the
changes, and then try to save to the file system again (up to 10 times).
If the same entry is both internally and externally modified, the external modification will be overwritten (although both change events will be seen by listeners).
Setter methods that take in a Serializer can be used to provide custom serialization of entries
instead of using the predefined serializer.
The value can then be retrieved using the equivalent parser:
Address myAddress = c.getObject(
The following methods can be used to bulk-load configuration values:
Changes can then be committed using the {@link org.apache.juneau.config.Config#commit()} method.
Configuration change events can be listened for using the following methods:
The {@link org.apache.juneau.config.event.ConfigEventListener} interface consists of the following method:
The {@link org.apache.juneau.config.event.ConfigEvent} class provides access to all the information about the updated entry:
The listener method is triggered:
In both cases, the listener is triggered after the changes have been committed.
The following methods are used for serializing Config objects back into INI files:
Both methods are thread safe.
The Config class implements the {@link org.apache.juneau.Writable} which means it can be
returned as-is by REST methods to be serialized as INI text.
Configuration files are stored in entities called Stores.
The methods that need to be implemented on a store are:
Read is self-explanatory:
Write is slightly trickier:
The update method is called whenever the stored file gets modified externally:
Two configuration stores are provided by default:
The store is defined on the Config object via the following setting:
The default store used is {@link org.apache.juneau.config.store.ConfigFileStore#DEFAULT} which defines the execution directory as the file system directory to store and retrieve files.
The {@link org.apache.juneau.config.store.ConfigMemoryStore} class is simply an in-memory storage
location for configuration files.
There is no hard persistence and is used primarily for testing purposes.
However, the implementation provides a good idea on how stores work (especially the write method):
The {@link org.apache.juneau.config.store.ConfigFileStore} is the typical store used for configuration files. It provides the following configurable settings:
The ConfigStore API has been written to allow easy development of custom configuration storage classes.
The example below shows a starting point for an implementation based on polling a relational database.
Completing it is left as an exercise:
The purpose of the builder class is to simply set values in the {@link org.apache.juneau.PropertyStore}
that's passed to the ConfigStore:
The ConfigStore class has the following listener methods:
Note that this is a different listener than {@link org.apache.juneau.config.event.ConfigEventListener}.
In this case, we're just listening for changed files:
This listener is used by the Config class to listen for changes on the file system so that it can be
updated in real-time.
The following settings can be used to create read-only Config objects:
This causes all methods that make modifications to throw {@link java.lang.UnsupportedOperationException}.
In general, it's good practice to close Config if you're only creating them temporarily so that their listeners get unregistered from the underlying storage APIs.
juneau-rest-server-7.0.0.jar
org.apache.juneau.rest.server_7.0.0.jar
The
The primary goal for Juneau was to make it as easy as possible to implement easy-to-read and self-documenting
REST resources using very little code.
One of the biggest advantages of the Juneau REST framework over similar architectures is that it hides the
serialization layer from the developer.
The developer can work entirely with POJOs and let the Juneau framework handle all the serialization and
parsing work.
The developer need never know what the
The API builds upon the existing JEE Servlet API.
The root class, {@link org.apache.juneau.rest.RestServlet} is nothing but a specialized
{@link javax.servlet.http.HttpServlet}, and the {@link org.apache.juneau.rest.RestRequest} and
{@link org.apache.juneau.rest.RestResponse} classes are nothing more than specialized
{@link javax.servlet.http.HttpServletRequest} and {@link javax.servlet.http.HttpServletResponse} objects.
This allows maximum flexibility for the developer since you can let Juneau handle operations such as
serialization, or you can revert to the existing servlet APIs to do low-level processing of requests yourself.
It also means you need nothing more than a Servlet container such as Jetty to use the REST framework.
Many of the examples in this document are pulled directly from
A REST resource is simply a Java class annotated with {@link org.apache.juneau.rest.annotation.RestResource}.
The most common case is a class that extends {@link org.apache.juneau.rest.RestServlet}, which itself is simply an
extension of {@link javax.servlet.http.HttpServlet} which allows it to be deployed as a servlet.
In this example, we define a resource called
This example is located in the
It's assumed the reader is familiar with defining servlets in web applications.
Like any servlet, we could define our resource in the
Our servlet code is shown below:
This is what it looks like in a browser:
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.
JSON, XML, HTML, ...).
However, we could have returned any POJO consisting of beans, maps, collections, etc...
The {@link org.apache.juneau.rest.BasicRestServlet} class that we're using here is a subclass of
{@link org.apache.juneau.rest.RestServlet} that provides default support for a variety of content types.
Implementers can choose to use this class, or create their own subclass of
{@link org.apache.juneau.rest.RestServlet} with their own specialized serializers and parsers.
The class hierarchy for the REST servlet class is shown below:
The servlets with RDF support require Jena on the classpath.
All other serializers and parsers do not have any external library dependencies.
For this reason, we have separate servlets for supporting RDF so that you don't need Jena if you don't need to
support RDF.
Everything is configured through the following classes which you will see a lot:
REST resources are deployed in one of two ways:
When deployed in a J2EE container, you MUST extend from one of the servlet classes.
When deployed as a child of another resource, you MAY extend from one of the servlet classes but it's
not necessary.
The only requirement is that the class be annotated with
public T()
public T(RestContextBuilder)
And even that restriction is relaxed if you implement your own REST resource resolver (described later).
The {@link org.apache.juneau.rest.RestServlet} class is the entry point for your REST resources.
It extends directly from
When the servlet
These get constructed into a {@link org.apache.juneau.rest.RestContext} object that holds all the configuration
information about your resource in a read-only object.
Most developers are not going to be using the
The
However, the class does provide a couple of convenience methods to be aware of:
{@link org.apache.juneau.rest.RestServlet} extends HttpServlet
Since this is a servlet, you also have the ability to intercept calls to the
The {@link org.apache.juneau.rest.BasicRestServlet} class is a subclass of {@link org.apache.juneau.rest.RestServlet} preconfigured with the following:
The entirety of the class is shown below.
You should notice that very little code is being used and everything is configurable through
annotations:
Your top-level resource will simply extend from this class, as shown in the Hello World example from a couple sections back.
There's a lot going on in this class.
But not to worry, the details will be described later.
Child Resources are REST servlets or objects that are linked to parent resources through the {@link org.apache.juneau.rest.annotation.RestResource#children() @RestResource.children()} annotation.
The path of the child resource gets appended to the path of the parent resource.
So in the example above, the child resource is accessed through the URL
A HUGE advantage of using child resources is that they do not need to be declared in the JEE
Initialization of and access to the child resources occurs through the parent resource.
Children can be nested arbitrary deep to create complex REST interfaces with a single top-level REST servlet.
The {@link org.apache.juneau.rest.BasicRestServletGroup} class provides a default "router" page for child resources when a parent resource is nothing more than a grouping of child resources.
The
When you bring up this resource in a browser, you see the following that provides a list of navigable links to your child resources:
The {@link org.apache.juneau.rest.BasicRestServletGroup} class is nothing more than a subclass of
{@link org.apache.juneau.rest.BasicRestServlet} with a
The method returns a POJO with is just a linked-list of beans with name/description properties.
By default, you can add the {@link org.apache.juneau.rest.annotation.RestResource @RestResource} to any class as long as it has one of the following constructors:
public T()
public T(RestContextBuilder)
The latter constructor can be used to get access to the {@link org.apache.juneau.rest.RestContextBuilder} object to make any configurations to the resource before it's initialized.
Resource object resolution is controlled through the following API:
This API can be extended to provide your own custom resource resolution.
Later topics discuss how to use this API to instantiate resources using Spring.
Lifecycle hooks allow you to hook into lifecycle events of the servlet/resource creation and REST calls.
For example, if you want to add an initialization method to your resource:
Or if you want to intercept REST calls:
The hook events can be broken down into two categories:
The {@link org.apache.juneau.rest.annotation.RestResource @RestResource} annotation is the primary way of defining
and configuring REST resource classes.
The functionality of the class itself is covered in detail in the topics below.
The {@link org.apache.juneau.rest.annotation.RestResource @RestResource} annotation can also be used on parents and interfaces of resource classes.
When multiple annotations are defined at different levels, the annotation values are combined.
This is a particularly useful feature because it allows you to define your own configured parent resource classes that can be extended by all your child resources so that they all share common settings.
| {@link org.apache.juneau.rest.annotation.RestResource#guards() guards()} |
Guards on child are combined with those on parent class.
Guards are executed child-to-parent in the order they appear in the annotation. Guards on methods are executed before those on classes. |
| {@link org.apache.juneau.rest.annotation.RestResource#converters() converters()} |
Converters on child are combined with those on parent class.
Converters are executed child-to-parent in the order they appear in the annotation. Converters on methods are executed before those on classes. |
| {@link org.apache.juneau.rest.annotation.RestResource#beanFilters() beanFilters()} | Bean filters on child are combined with those on parent class. |
| {@link org.apache.juneau.rest.annotation.RestResource#pojoSwaps() pojoSwaps()} | POJO swaps on child are combined with those on parent class. |
| {@link org.apache.juneau.rest.annotation.RestResource#properties() properties()} |
Properties on child are combined with those on parent class.
Properties are applied parent-to-child in the order they appear in the annotation. Properties on methods take precedence over those on classes. |
| {@link org.apache.juneau.rest.annotation.RestResource#serializers() serializers()} |
Serializers on child are combined with those on parent class.
Serializers on methods take precedence over those on classes. |
| {@link org.apache.juneau.rest.annotation.RestResource#parsers() parsers()} |
Parsers on child are combined with those on parent class.
Parsers on methods take precedence over those on classes. |
| {@link org.apache.juneau.rest.annotation.RestResource#responseHandlers() responseHandlers()} | Response handlers on child are combined with those on parent class. |
| {@link org.apache.juneau.rest.annotation.RestResource#encoders() encoders()} | Encoders on child are combined with those on parent class. |
| {@link org.apache.juneau.rest.annotation.RestResource#defaultRequestHeaders() defaultRequestHeaders()} |
Headers on child are combined with those on parent class.
Headers are applied parent-to-child in the order they appear in the annotation. Headers on methods take precedence over those on classes. |
| {@link org.apache.juneau.rest.annotation.RestResource#defaultResponseHeaders() defaultResponseHeaders()} |
Headers on child are combined with those on parent class.
Headers are applied parent-to-child in the order they appear in the annotation. |
| {@link org.apache.juneau.rest.annotation.RestResource#children() children()} |
Children on child are combined with those on parent class.
Children are list parent-to-child in the order they appear in the annotation. |
| {@link org.apache.juneau.rest.annotation.RestResource#path() path()} | Path is searched for in child-to-parent order. |
| {@link org.apache.juneau.rest.annotation.RestResource#title() title()} | Label is searched for in child-to-parent order. |
| {@link org.apache.juneau.rest.annotation.RestResource#description() description()} | Description is searched for in child-to-parent order. |
| {@link org.apache.juneau.rest.annotation.RestResource#config() config()} | Config file is searched for in child-to-parent order. |
| {@link org.apache.juneau.rest.annotation.RestResource#staticFiles() staticFiles()} |
Static files on child are combined with those on parent class.
Static files are are executed child-to-parent in the order they appear in the annotation. |
The {@link org.apache.juneau.rest.RestContext} object is the workhorse class for all of the configuration
of a single REST resource class.
It's by-far the most important class in the REST API.
Every class annotated with
The object itself is read-only and unchangeable.
It is populated through the following:
The annotation should be self-explanatory at this point.
The builder allows you to perform all of the same configuration as the annotation programmatically.
The {@link org.apache.juneau.rest.RestContextBuilder} class extends {@link org.apache.juneau.BeanContextBuilder}
allowing you to programmatically set any properties defined on that builder class.
It also implements {@link javax.servlet.ServletConfig}
To access this object, simply pass it in as a constructor argument or in an INIT hook:
Warning: This class is huge.
Through it, you can configure bean/serializer/parser settings, define config files, children,
resource finders, info providers, etc...
REST Java methods are identified on REST servlets using the
{@link org.apache.juneau.rest.annotation.RestMethod @RestMethod} annotation.
The annotation allows the framework to identify the available REST methods through reflection.
There are no restrictions on the name of the Java method.
Java methods can contain any of the following parameters in any order:
RestRequest.
RestResponse.
@RestMethod (name="*" ))
The {@link org.apache.juneau.rest.RestRequest} object is an extension of the
It can be accessed by passing it as a parameter on your REST Java method:
There are many useful methods on this object, but the main ones are shown below:
{@link org.apache.juneau.rest.RestRequest} extends HttpServletRequest
The {@link org.apache.juneau.rest.RestResponse} object is an extension of the
It can be accessed by passing it as a parameter on your REST Java method:
The important methods on this class are shown below:
{@link org.apache.juneau.rest.RestResponse} extends HttpServletResponse
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:
The important methods on this class are:
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:
The important methods on this class are:
{@link org.apache.juneau.rest.RequestHeaders} extends TreeMap<String,String[]>
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:
An important distinction between the behavior of this object and
This can be useful in cases where you're mixing GET parameters and FORM POSTS and you don't want to
inadvertantly read the body of the request to get a query parameter.
The important methods on this class are:
{@link org.apache.juneau.rest.RequestQuery} extends LinkedHashMap<String,String[]>
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:
Note that this object does NOT take GET parameters into account and only returns values found in the body of the request.
The important methods on this class are:
{@link org.apache.juneau.rest.RequestFormData} extends LinkedHashMap<String,String[]>
The {@link org.apache.juneau.rest.annotation.RestMethod#path() @RestMethod.path()} annotation allows
you to define URL path patterns to match against.
These patterns can contain variables of the form
In the following example, 3 separate GET request handlers are defined with different path patterns.
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...
By default, path patterns are matched using a best-match heuristic.
When overlaps occur, URLs are matched from most-specific to most-general order:
The match heuristic behavior can be overridden by the
{@link org.apache.juneau.rest.annotation.RestMethod#priority() @RestMethod.priority()} annotation
property.
However, in practice this is almost never needed.
Paths that end with
Any remainder after the match can be accessed through
{@link org.apache.juneau.rest.RequestPathMatch#getRemainder()} or parameters with the
{@link org.apache.juneau.rest.annotation.PathRemainder @PathRemainder} annotation.
On the other hand, paths that don't end with
The following example shows the distinction.
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
The {@link org.apache.juneau.rest.RequestPathMatch} object is the API for accessing the matched variables and remainder on the URL path.
The important methods on this class are:
{@link org.apache.juneau.rest.RequestPathMatch} extends TreeMap<String,String>
The return type can be any serializable POJO as defined in POJO Categories.
It can also be
Out-of-the-box, besides POJOs, the following return types are handled as special cases:
This is controlled through the following extensible API:
REST Java methods can generate output in any of the following ways:
The {@link org.apache.juneau.rest.ReaderResource} class is a convenience object for defining thread-safe
reusable character-based responses.
In essence, it's a container for character data with optional response headers and support for
resolving SVL variables.
The {@link org.apache.juneau.rest.ReaderResource} class implements the {@link org.apache.juneau.Writable}
interface which is handled by the {@link org.apache.juneau.rest.response.WritableHandler} class.
This allows these objects to be returned as responses by REST methods.
The important methods on this class are:
The {@link org.apache.juneau.rest.StreamResource} class is the binary equivalent to the {@link org.apache.juneau.rest.ReaderResource} object.
In essence, it's a container for binary data with optional response headers.
The {@link org.apache.juneau.rest.StreamResource} class implements the {@link org.apache.juneau.Streamable}
interface which is handled by the {@link org.apache.juneau.rest.response.StreamableHandler} class.
This allows these objects to be returned as responses by REST methods.
The important methods on this class are:
The {@link org.apache.juneau.rest.Redirect} object is a convenience shortcut for performing HTTP 302 redirects.
This allows these objects to be returned as responses by REST methods.
The following example shows the difference between handling redirects via
The constructor can use a
The arguments are automatically URL-encoded.
Redirecting to the servlet root can be accomplished by simply using the no-arg constructor.
{@link org.apache.juneau.rest.RestMatcher RestMatchers} are used to allow multiple Java methods to be tied to the same HTTP method and path, but differentiated by some request attribute such as a specific header value.
The interface for matchers is simple:
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.
The HTTP body of a request can be retrieved as a parsed POJO using either the {@link org.apache.juneau.rest.RestRequest#getBody()} method, or a parameter annotated with {@link org.apache.juneau.rest.annotation.Body @Body}.
The Juneau framework will automatically determine the appropriate
So the body content could be JSON or XML or any other supported parsing types.
The best way to handle a form post is by using an input bean.
The samples include a
The code is shown here:
Another possibility is to access the form parameters individually:
The advantage to the form input bean is that it can handle any of the parsable types (e.g. JSON, XML...)
in addition to URL-Encoding.
The latter approach only supports URL-Encoding.
The Juneau framework does not natively support multipart form posts.
However, it can be done in conjunction with the Apache Commons File Upload library.
The samples include a
The {@link org.apache.juneau.rest.annotation.FormData @FormData} annotation is used to retrieve request form post entries.
This is functionally equivalent to the following code:
The registered {@link org.apache.juneau.rest.RestContext#REST_partParser} is used to convert strings
to POJOs and controls what POJO types are supported.
As a general rule, any POJO convertible from a String is supported.
application/x-www-form-urlencoded POST posts, since it will trigger the underlying servlet
API to parse the body content as key-value pairs resulting in empty content.
The {@link org.apache.juneau.rest.annotation.Query @Query} annotation is used to retrieve request URL query parameters.
It's identical to {@link org.apache.juneau.rest.annotation.FormData @FormData}, but only retrieves the parameter from the URL string, not URL-encoded form posts.
Unlike {@link org.apache.juneau.rest.annotation.FormData @FormData}, using this annotation does not result in the servlet reading the contents of
URL-encoded form posts.
Therefore, this annotation can be used in conjunction with the {@link org.apache.juneau.rest.annotation.Body @Body} annotation or
{@link org.apache.juneau.rest.RestRequest#getBody()} method for application/x-www-form-urlencoded POST calls.
This is functionally equivalent to the following code:
The registered {@link org.apache.juneau.rest.RestContext#REST_partParser} is used to convert strings
to POJOs and controls what POJO types are supported.
As a general rule, any POJO convertible from a String is supported.
The {@link org.apache.juneau.rest.annotation.Header @Header} annotation is used to retrieve request headers.
This is functionally equivalent to the following code:
The registered {@link org.apache.juneau.rest.RestContext#REST_partParser} is used to convert strings
to POJOs and controls what POJO types are supported.
As a general rule, any POJO convertible from a String is supported.
REST resources use the {@link org.apache.juneau.serializer.Serializer} API for defining serializers for serializing response POJOs.
The servlet will pick which serializer to use by matching the request
Serializers can be associated with REST servlets in the following ways:
The following are all equivalent ways of defining serializers used by a resource:
REST resources use the {@link org.apache.juneau.parser.Parser} API for defining parsers for parsing request body content and converting them into POJOs.
The servlet will pick which parser to use by matching the request
Parsers can be associated with REST servlets in the following ways:
The following are all equivalent ways of defining parsers used by a resource:
As shown in previous sections, Juneau serializers and parsers are highly-configurable through properties. (See Configurable Properties)
These properties can be defined for serializers and parsers registered on a REST resource via the following:
The programmatic equivalent to this is:
Properties can also be overridden at the Java method level:
Using the {@link org.apache.juneau.rest.RequestProperties} object:
Properties set via {@link org.apache.juneau.rest.RequestProperties} are session-override
properties that are passed in through {@link org.apache.juneau.serializer.SerializerSessionArgs}
and {@link org.apache.juneau.parser.ParserSessionArgs} and can only be used on configuration settings
marked as Session-overridable: .
Properties are open-ended and can be used for other purposes.
They're made available through the following methods:
The Juneau serializers and parsers can be configured on how to handle POJOs through the use of Transforms. (See Transforms)
Transforms are associated serializers and parsers registered on a REST resource via the following:
The programmatic equivalent to this is:
Guards are classes that control access to REST classes and methods.
Guards are associated with resource classes and methods via the following:
A common use for guards is to only allow admin access to certain Java methods...
A guard failure results in an
However, this can be configured by overriding the
{@link org.apache.juneau.rest.RestGuard#guard(RestRequest,RestResponse)} and processing the response
yourself.
When guards are associated at the class-level, it's equivalent to associating guards on all Java methods on
the servlet.
If multiple guards are present, ALL guards must pass.
Converters can be thought of as "post-processors" for POJOs before they get passed to the serializers.
Converters are associated with resource classes and methods via the following:
They can also be defined at the method level:
The following converter is used to provide support for addressing child nodes in a POJO tree with URL path
remainders.
In this code, the 3rd parameter is the object that was returned by the Java method.
The converter uses the {@link org.apache.juneau.utils.PojoRest} wrapper class to address nodes in the
tree.
Juneau defines the following converters out-of-the-box:
The {@link org.apache.juneau.rest.annotation.RestResource#messages @RestResource.messages()} annotation is used to associate a resource bundle with a servlet class.
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}:
If a resource bundle is shared by multiple servlets, the label and description can be prefixed by the class name:
The {@link org.apache.juneau.rest.annotation.RestResource#encoders @RestResource.encoders()} annotation can
be used to associate character encoders with a servlet class.
Encoders can be used to enable various kinds of compression (e.g.
Juneau defines the following encoders out-of-the-box:
In the previous examples, there were several cases where embedded variables were contained within annotation values:
Variables take the form
This is called Simple Variable Language, or SVL, and is defined here: juneau-svl.
Variables are configured on resources via the following API:
The methods involved with variables are:
There are two distinct groups of variables:
The following is the default list of supported variables.
| Module | Class | Pattern | Initialization time | Request time |
|---|---|---|---|---|
| juneau-svl | {@link org.apache.juneau.svl.vars.EnvVariablesVar} | $E{key[,default]} | yes | yes |
| {@link org.apache.juneau.svl.vars.SystemPropertiesVar} | $S{key[,default]} | yes | yes | |
| {@link org.apache.juneau.svl.vars.ArgsVar} | $A{key[,default]} | yes | yes | |
| {@link org.apache.juneau.svl.vars.ManifestFileVar} | $MF{key[,default]} | yes | yes | |
| {@link org.apache.juneau.svl.vars.IfVar} | $IF{arg,then[,else]} | yes | yes | |
| {@link org.apache.juneau.svl.vars.SwitchVar} | $SW{arg,pattern1:then1[,pattern2:then2...]} | yes | yes | |
| {@link org.apache.juneau.svl.vars.CoalesceVar} | $CO{arg1[,arg2...]} | yes | yes | |
| {@link org.apache.juneau.svl.vars.PatternMatchVar} | $PM{arg,pattern} | yes | yes | |
| {@link org.apache.juneau.svl.vars.NotEmptyVar} | $NE{arg} | yes | yes | |
| {@link org.apache.juneau.svl.vars.UpperCaseVar} | $UC{arg} | yes | yes | |
| {@link org.apache.juneau.svl.vars.LowerCaseVar} | $LC{arg} | yes | yes | |
| juneau-config | {@link org.apache.juneau.config.vars.ConfigVar} | $C{key[,default]} | yes | yes |
| juneau-rest-server | {@link org.apache.juneau.rest.vars.FileVar} | $F{path[,default]}} | no | yes |
| {@link org.apache.juneau.rest.vars.ServletInitParamVar} | $I{name[,default]} | yes | yes | |
| {@link org.apache.juneau.rest.vars.LocalizationVar} | $L{key[,args...]} | no | yes | |
| {@link org.apache.juneau.rest.vars.RequestAttributeVar} | $RA{key1[,key2...]} | no | yes | |
| {@link org.apache.juneau.rest.vars.RequestFormDataVar} | $RF{key1[,key2...]} | no | yes | |
| {@link org.apache.juneau.rest.vars.RequestHeaderVar} | $RH{key1[,key2...]} | no | yes | |
| {@link org.apache.juneau.rest.vars.RequestHeaderVar} | $RI{key} | no | yes | |
| {@link org.apache.juneau.rest.vars.RequestPathVar} | $RP{key1[,key2...]} | no | yes | |
| {@link org.apache.juneau.rest.vars.RequestQueryVar} | $RQ{key1[,key2...]} | no | yes | |
| {@link org.apache.juneau.rest.vars.RequestVar} | $R{key1[,key2...]} | no | yes | |
| {@link org.apache.juneau.rest.vars.SerializedRequestAttrVar} | $SA{contentType,key[,default]} | no | yes | |
| {@link org.apache.juneau.rest.vars.UrlVar} | $U{uri}> | no | yes | |
| {@link org.apache.juneau.rest.vars.UrlEncodeVar} | $UE{uriPart} | yes | yes | |
| {@link org.apache.juneau.rest.vars.WidgetVar} | $W{name} | no | yes |
The Server API provides methods for associating configuration files with REST servlets so that configuration properties can be defined in external files.
In recap, the Configuration API provides support for INI-style configuration files with embedded string variables:
These properties are then accessible through the {@link org.apache.juneau.config.Config} class.
Config c = Config.
Configuration files are associated with REST resources through the following:
The annotation itself can contain string variables.
For example, the Microservice API {@link org.apache.juneau.rest.BasicRestServlet} class defines the
location of the config file as a system property
Once a config file has been associated with a REST resource, it can be accessed through the {@link org.apache.juneau.rest.RestContextBuilder#getConfig()} method.
A common usage is to use this method to initialize fields in your servlet.
Another common usage is to refer to config properties through
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:
You can even add resource bundles into the mix:
The {@link org.apache.juneau.rest.annotation.RestResource#staticFiles @RestResource.staticFiles()} annotation is used to define paths and locations of statically-served files such as images or HTML documents.
The value is a JSON map of paths to packages/directories located on either the classpath or working directory.
Static files are found by calling {@link java.lang.Class#getResource(String)} up the class hierarchy. If not found, then an attempt is made to find the class in the Java working directory.
In the example above, given a GET request to
Client version headers are used to support backwards compatibility for breaking REST interface changes.
Using them, you're able to return different responses based on which client is making a request.
The APIs involved with defining client version headers are:
One of the most useful features of Juneau is the ability to generate Swagger-based OPTIONS pages for self-documenting designs (i.e. REST interfaces that document themselves).
The {@link org.apache.juneau.rest.BasicRestServlet} class implements the page by creating a method
mapped to the
This page is constructed using the Info Provider API described next.
The {@link org.apache.juneau.rest.RestInfoProvider} class is used to find the title
and description for your resource and also generate the Swagger documentation.
It can be overridden to provide your own custom Swagger documentation.
The methods on this interface are:
The info provider in turn supplies the information returned by the following methods:
Info providers are registered through the following property:
While you can implement this interface from scratch, you may want to instead consider extending
from the
The {@link org.apache.juneau.rest.BasicRestInfoProvider} class is the default implementation of the {@link org.apache.juneau.rest.RestInfoProvider} interface.
It finds and collects information gathered from the following locations:
The class itself is designed to be extended if you wish to rely mostly on the default behavior, but tweak certain aspects.
In addition to the methods defined on the
{@link org.apache.juneau.rest.BasicRestInfoProvider} implements {@link org.apache.juneau.rest.RestInfoProvider}
The default provider provides several options for defining Swagger documentation on your resource:
MyResource_ja_JP.json
The {@link org.apache.juneau.rest.annotation.HtmlDoc @HtmlDoc} annotation is used to customize the HTML
view of your serialized POJOs.
It's used in the following locations:
The annotation itself is just a convenience for setting configuration properties set
on the {@link org.apache.juneau.html.HtmlDocSerializer} class.
For example, the following two pieces of code are equivalent:
The purpose of these annotation is to populate the HTML document view which by default consists of the following structure:
The outline above is controlled by the {@link org.apache.juneau.html.HtmlDocTemplate} interface which can be overridden via the {@link org.apache.juneau.rest.annotation.HtmlDoc#template @HtmlDoc.template()} annotation.
The
SVL variables can be used in any of these annotations:
The {@link org.apache.juneau.rest.widget.Widget} class allows you to add arbitrary HTML, CSS, and Javascript
to HTML pages.
They are registered in the following locations:
The
The HTML content returned by the {@link org.apache.juneau.rest.widget.Widget#getHtml(RestRequest) getHtml(RestRequest)}
method is added wherever the
The CSS returned by {@link org.apache.juneau.rest.widget.Widget#getScript(RestRequest) getScript(RestRequest)} is added to the style section in the page header.
The Javascript returned by {@link org.apache.juneau.rest.widget.Widget#getScript(RestRequest) getScript(RestRequest)} is added to the script section in the page header.
The following examples shows how to associate a widget with a REST method and then have it rendered in the links
and aside section of the page.
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()}):
The
The HTML views of POJOs can somewhat be considered a rudimentary User Interface.
In reality, a better term for them would be a Developer Interface as they're meant to be used
primarily by developers and not end users.
Despite that distinction, it is possible to 'brand' the HTML page to whatever you desire.
The sample root page below includes some default branding for Juneau and Apache:
In particular, you may want to replace these icons:
The Juneau REST framework does not provide specific branding support (i.e. there is no concept of a brand icon).
Instead, it just uses the existing open-ended API for defining branding.
The Juneau icon shown is a result of the header annotation on the {@link org.apache.juneau.rest.BasicRestServlet} class:
The org.apache.juneau.rest.htdocs package and
is served up via the staticFiles annotation (i.e. anything in the org.apache.juneau.rest.htdocs
package is served up under the path /servlet-path/htdocs).
Then we just reference using a URI resolution variable
To change this image, you can extend the
The footer icon shown is generated by a predefined widget:
The widget definition is shown below:
To provide your own footer icon, simply define it in your own footer section:
Note how the "User Interface" is open-ended to pretty much lets you do whatever you want.
The sample root page renders in the default "devops" look-and-feel:
The sample root page provides a dropdown widget to try out the other default look-and-feels:
For example, the "light" look-and-feel:
And the "dark" look-and-feel:
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:
The org/apache/juneau/rest/styles/devops.css.
To provide your own stylesheet, simply override the stylesheet attribute and point to a different file:
You can try out different stylesheets by passing in a stylesheet attribute in the request
URL.
The example above show this in use.
In case you're curious about how the menu item works, it's defined via a widget:
The
In the case of
The following annotations are provided for specifying default header values for requests and responses:
Default headers can also be specified programmatically by overriding the following methods:
The {@link org.apache.juneau.rest.RestContext#REST_logger} property allows you to configure
logging for your resource.
The interface is shown below:
The {@link org.apache.juneau.rest.RestLogger#logObjects(Level,String,Object[]) logObjects()} method is particularly useful because it allows you to pass in POJOs as arguments that serialized using {@link org.apache.juneau.json.JsonSerializer#DEFAULT_LAX_READABLE}, but only if the message is actually logged.
logger.logObjects(
By default, the Juneau framework uses the built-in Java Logging API for logging.
But you can define your own implementation to use any framework you wish.
The {@link org.apache.juneau.rest.RestLogger} instance is accessible via the following:
In addition, the logger can be accessed by passing it as a parameter to your REST java method:
If your resource extends from {@link org.apache.juneau.rest.RestServlet}, you can also use and override the following methods:
By default, a 200 (OK) status is automatically set as the HTTP status when a Java method executes successfully.
Other status codes can be generated by throwing a {@link org.apache.juneau.rest.RestException} with a specific HTTP status code, or calling {@link javax.servlet.http.HttpServletResponse#setStatus(int)}.
Non-OK (200) status codes are automatically triggered by the following conditions:
| Unauthorized | A {@link org.apache.juneau.rest.RestGuard guard} prevented the method from being executed | |
| Not Found | No matching path patterns were found on any method | |
| Method Not Implemented | A path pattern matched, but no Java methods were found for the HTTP method | |
| Not Acceptable |
A path pattern matched, but no Java methods were found with a matching serializer for the
|
|
| Precondition Failed | A path pattern matched, but no Java methods were found that were not rejected by {@link org.apache.juneau.rest.RestMatcher matchers} | |
| Unsupported Media Type |
A path pattern matched, but no Java methods were found with a matching parser for the
|
|
| Internal Server Error | The Java method threw an exception other than {@link org.apache.juneau.rest.RestException} |
Through the use of the built-in
For example, the URL
To support overloaded methods, the {@link org.apache.juneau.rest.annotation.RestResource#allowedMethodParams() @RestResource.allowedMethodParams()} setting must be enabled on your servlet.
The following URL parameters have special meaning and can be passed in through the URL of the request:
| &plainText=true |
Response will always be Useful for debugging. |
| &debug=true | Request body content will be dumped to log file. |
| &noTrace=true |
If an error occurs, don't log the stack trace to the log file.
Useful for automated JUnit testcases testing error states to prevent the log file from filling up with useless stack traces. |
| &method=X |
Overload the HTTP method as a GET parameter (e.g Must be enabled via {@link org.apache.juneau.rest.annotation.RestResource#allowedMethodParams() @RestResource.allowedMethodParams()} setting. |
| &Header-Name=headerValue |
Specify a header value as a GET parameter.
Must be enabled via {@link org.apache.juneau.rest.annotation.RestResource#allowHeaderParams() @RestResource.allowHeaderParams()} setting. |
| &body=X |
Pass in the HTTP body content on PUT and POST methods as a UON-encoded GET parameter.
Must be enabled via {@link org.apache.juneau.rest.annotation.RestResource#allowBodyParam() @RestResource.allowBodyParam()} setting. |
| &x-response-headers=X |
Pass-through headers to the response.
Must be a UON-encoded map of key-value pairs. |
A very easy-to-use API is provided for defining your own serializers and parsers at both the servlet and method levels.
The following examples show a custom serializer and parser defined at the method level.
It's the
Since REST servlets are basically just
The following code shows how to register your REST servlets in an OSGi
The Remoteable Service API allows for client side code to use interface proxies for calling methods on POJOs on the server side.
Proxy interfaces are retrieved using the {@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class)} method. The remoteable servlet is a specialized subclass of {@link org.apache.juneau.rest.RestServlet} that provides a full-blown REST interface for calling remoteable services (e.g. POJOs) remotely.
The following simplified example shows how a method on a POJO on a server can be called through an interface on a client...
The client side code for invoking this method is shown below...
The requirements for a method to be callable through the remoteable service are:
Juneau provides the capability of calling methods on POJOs on a server through client-side proxy interfaces. It offers a number of advantages over other similar remote proxy interfaces, such as being much simpler to define and use, and allowing much more flexibility in the types of objects serialized.
The remote proxy interface API allows you to invoke server-side POJO methods on the client side using REST as the communications protocol:
Under the covers, this method call gets converted to a REST POST.
HTTP POST http://localhost/remoteable/org.apache.juneau.examples.rest.IAddressBook/createPerson Accept: application/json Content-Type: application/json [ { "name":"John Smith", "birthDate":"Aug 1, 1999", "addresses":[ { "street":"My street", "city":"My city", "state":"My state", "zip":12345, "isCurrent":true } ] } ]
Note that the body of the request is an array. This array contains the serialized arguments of the method. The object returned by the method is then serialized as the body of the response.
To define a remoteable interface, simply add the {@link org.apache.juneau.remoteable.Remoteable @Remoteable} annotation to your interface class.
This annotation tells the framework that all methods defined on this interface can be executed remotely. It can be applied to super-interfaces, super-classes, etc..., and exposes the methods at whatever level it is defined.
The {@link org.apache.juneau.remoteable.RemoteMethod @RemoteMethod} annotation can also be used on individual methods to tailor which methods are exposed or their paths.
There are two ways to expose remoteable proxies on the server side:
RemoteableServlet.
@RestMethod (name=PROXY ) annotation on a Java method.
The RemoteableServlet class is a simple specialized servlet with an abstract
getServiceMap() method to define the server-side POJOs:
The approach is easier if you only have a single
interface you want to expose.
You simply define a Java method whose return type is an interface, and return the implementation of that
interface:
In either case, the proxy communications layer is pure REST. Therefore, in cases where the interface classes are not available on the client side, the same method calls can be made through pure REST calls. This can also aid significantly in debugging, since calls to the remoteable service can be made directly from a browser with no coding involved.
The parameters and return types of the Java methods can be any of the supported serializable and parsable types. This ends up being WAY more flexible than other proxy interfaces since Juneau can handle so may POJO types out-of-the-box. Most of the time you don't even need to modify your existing Java implementation code.
The RemoteableServlet class itself shows how sophisticated REST interfaces can be built on the Juneau
RestServlet API using very little code.
The class consists of only 53 lines of code, yet is a sophisticated discoverable and
self-documenting REST interface.
And since the remote proxy API is built on top of REST, it can be debugged using just a browser.
The requirements for a method to be callable through a remoteable service are:
Throwables with public no-arg or single-arg-string constructors which will
be automatically recreated on the client side.
Remoteable interface proxies are retrieved through the existing {@link org.apache.juneau.rest.client.RestClient} class.
It may seem that the client-side code would need to be complex.
In reality, it builds upon existing serializing, parsing, and REST capabilities in Juneau resulting in very
little additional code.
The entire code for the RestClient.getRemoteableProxy(Class) method is shown below:
Since we build upon the existing RestClient API, we inherit all of it's features.
For example, convenience methods for setting POJO filters and properties to customize the behavior of the
serializers and parsers, and the ability to provide your own customized Apache HttpClient for
handling various scenarios involving authentication and Internet proxies.
The server side is only slightly more complex, but boasts useful debugging and discovery capabilities.
The {@link org.apache.juneau.rest.remoteable.RemoteableServlet} class is an implementation of
{@link org.apache.juneau.rest.RestServlet} that provides a REST interface for invoking calls on POJOs.
The RemoteableServlet class is abstract and must implement a single method for providing the set
of POJOs to expose as remote interfaces.
The samples bundle includes a sample implementation of a remoteable service that can be used to interact with the address book POJO also included in the bundle. 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.
Since this class is a servlet, and can be deployed as such.
In the sample code, it's listed as a child resource to org.apache.juneau.rest.samples.RootResources
which makes it available under the URL /juneau/sample/remoteable.
If you point your browser to that URL, you get a list of available interfaces:
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.
Since AddressBook extends from LinkedList, you may notice familiar collections
framework methods listed.
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 =
That produces the following JSON output:
[
{
name:
Note that in this example we're using JSON. However, various other content types can also be used such as XML, URL-Encoding, UON, or HTML. In practice however, JSON will preferred since it is often the most efficient.
Next, we can use a tool such as Poster to make the REST call.
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 /juneau/sample/remoteable/org.apache.juneau.examples.addressbook.IAddressBook/createPerson(org.apache.juneau.examples.addressbook.CreatePerson).
Make sure that we specify the Content-Type of the body as text/json.
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 =
If we alter our servlet to allow overloaded GET requests, we can invoke methods using nothing more than a browser...
For example, here we call the findPerson( 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):
When specifying the POST body as a &content parameter, the method arguments should be in UON
notation.
See {@link org.apache.juneau.uon.UonSerializer} for more information about this encoding.
Usually you can also pass in JSON if you specify &Content-Type=text/json in the URL parameters
but passing in unencoded JSON in a URL may not work in all browsers.
Therefore, UON is preferred.
What if you want fine-tuned control over which methods are exposed in an interface instead of just all public methods? For this, the {@link org.apache.juneau.remoteable.Remoteable @Remoteable} annotation is provided. It can be applied to individual interface methods to only expose those methods through the remoteable servlet.
For example, to expose only the first 2 methods in our IAddressBook interface...
On the server side, the option to restrict access to only annotated methods is defined through a property:
The
The Juneau REST server API is compatible with dependency injection frameworks such as Spring.
The important class is the {@link org.apache.juneau.rest.RestResourceResolver} class which is used to resolve child servlet/resource implementation classes inside parent contexts. In other words, it's used for resolving {@link org.apache.juneau.rest.annotation.RestResource#children() @RestResource.children()} instances.
The general approach starts with defining a resolver that uses the Spring application context for resolution:
Next, define the Spring configuration to return our resolver:
Finally, define your Root resource with a constructor that takes in our rest resource resolver and
sets it on the config object during initialization.
After that, just define constructors on your child resources to take in Spring beans:
Juneau is built as a veneer on top of the Servlet API, allowing you to use low-level Servlet APIs
whenever needed.
This allows you to take advantage of the newest HTTP/2 features implemented in the new Servlet 4.0
specification.
Coming soon (sorry)
The {@link org.apache.juneau.rest.labels} package contains some reusable beans that are useful for creating linked items in HTML views.
The {@link org.apache.juneau.rest.labels.ResourceDescription} class is a bean with name/description
properties for labeling and linking to child resources.
The following examples is pulled from the REST examples:
It get rendered as a table of name/description columns with links to child methods:
The internals of the class show it simply has two bean properties with a link annotation defined on the name property:
The {@link org.apache.juneau.rest.labels.BeanDescription} class provides a simple view of a bean and it's properties.
This example renders the following:
The {@link org.apache.juneau.html.annotation.HtmlLink @HtmlLink} annotation can also be useful for rendering custom hyperlinks:
This example renders the following consisting of a list of hyperlinks:
juneau-rest-server-jaxrs-7.0.0.jar
org.apache.juneau.rest.server_7.0.0.jar
The juneau-rest-server-jaxrs library provides an implementation of a MessageBodyReader
and MessageBodyWriter to allow any of the Juneau serializers and parsers to be used in a
JAX/RS environment.
The Juneau framework contains the
It should be noted that although some of the functionality of the Juneau Server API is provided through the JAX-RS integration components, it is not nearly as flexible as using the {@link org.apache.juneau.rest.RestServlet} class directly.
What you can do with the Juneau JAX-RS provider classes:
What you can't do with the Juneau JAX-RS provider classes:
The Juneau JAX-RS provider API consists of the following classes:
MessageBodyReader and MessageBodyWriter interfaces.
BaseProvider
to specify the serializers/parsers associated with a provider, and optionally filters and properties to
apply to those serializers and parsers.
For the most part, when using these components, you'll either use the existing
juneau-rest-client-7.0.0.jar
org.apache.juneau.rest.client_7.0.0.jar
The REST client API provides the ability to access remote REST interfaces and transparently convert the input and output to and from POJOs using any of the provided serializers and parsers.
Built upon the
Juneau provides an HTTP client API that makes it extremely simple to connect to remote REST interfaces and seemlessly send and receive serialized POJOs in requests and responses.
The client API is designed to work as a thin layer on top of the proven Apache HttpClient API. By leveraging the HttpClient library, details such as SSL certificate negotiation, proxies, encoding, etc... are all handled in Apache code.
The Juneau client API prereq's Apache HttpClient 4.5+. At a minimum, the following jars are required:
httpclient-4.5.jar
httpcore-4.4.1.jar
httpmime-4.5.jar
The juneau-rest-client library can also be used to define interface proxies against 3rd-party REST interfaces.
This is an extremely powerful feature that allows you to quickly define easy-to-use interfaces against
virtually any REST interface.
Similar in concept to remoteable services defined above, but in this case we simply define our interface with special annotations that tell us how to convert input and output to HTTP headers, query parameters, form post parameters, or request/response bodies.
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 E-Tag: 475588d4-0b27-4f56-9296-cc683251d314 { "foo": "bar", "baz": 123, "qux": true}
The Java method arguments can be annotated with any of the following:
Map<String,Object>
- Individual name-value pairs.
String
- Treated as a query string.
POST.
Map<String,Object>
- Individual name-value pairs.
Map<String,Object>
- Individual name-value pairs.
RestClient.
The return type of the Java method can be any of the following:
RestClient.
HttpResponse
- Returns the raw HttpResponse returned by the inner HttpClient.
The simplest way to enable SSL support in the client is to use the {@link org.apache.juneau.rest.client.RestClientBuilder#enableSSL(SSLOpts)} method and one of the predefined {@link org.apache.juneau.rest.client.SSLOpts} instances:
This is functionally equivalent to the following:
RestClientBuilder builder = RestClient.
More complex SSL support can be enabled through the various {@link org.apache.http.impl.client.HttpClientBuilder} methods defined on the class.
The {@link org.apache.juneau.rest.client.SSLOpts} class itself is a bean that can be created by the parsers. For example, SSL options can be specified in a config file and retrieved as a bean using the {@link org.apache.juneau.config.Config} class.
MyConfig.cfg
SSLOpts bean from the config file
The {@link org.apache.juneau.rest.client.RestClientBuilder#basicAuth(String,int,String,String)} method can be used to quickly enable BASIC authentication support.
This is functionally equivalent to the following:
RestClientBuilder builder = RestClient.
The {@link org.apache.juneau.rest.client.RestClientBuilder} class does not itself provide FORM-based
authentication since there is no standard way of providing such support.
Typically, to perform FORM-based or other types of authentication, you'll want to create your own
subclass of {@link org.apache.juneau.rest.client.RestClientBuilder} and override the
{@link org.apache.juneau.rest.client.RestClientBuilder#createHttpClient()} method to provide an
authenticated client.
The following example shows how the JazzRestClient class provides FORM-based
authentication support.
The following example shows how the JazzRestClient class provides OIDC authentication
support.
One issue with REST (and HTTP in general) is that the HTTP response code must be set as a header before the
body of the request is sent.
This can be problematic when REST calls invoke long-running processes, pipes
the results through the connection, and then fails after an HTTP 200 has already been sent.
One common solution is to serialize some text at the end to indicate whether the long-running process
succeeded (e.g.
The {@link org.apache.juneau.rest.client.RestClient} class has convenience methods for scanning the response without interfering with the other methods used for retrieving output.
The following example shows how the {@link org.apache.juneau.rest.client.RestCall#successPattern(String)} method can be used to look for a SUCCESS message in the output:
The {@link org.apache.juneau.rest.client.RestCall#failurePattern(String)} method does the opposite. It throws an exception if a failure message is detected.
These convenience methods are specialized methods that use the
{@link org.apache.juneau.rest.client.RestCall#responsePattern(ResponsePattern)} method which uses regular
expression matching against the response body.
This method can be used to search for arbitrary patterns in the response body.
The following example shows how to use a response pattern finder to find and capture patterns for
Using response patterns does not affect the functionality of any of the other methods
used to retrieve the response such as {@link org.apache.juneau.rest.client.RestCall#getResponseAsString()}
or {@link org.apache.juneau.rest.client.RestCall#getResponse(Class)}.
HOWEVER, if you want to retrieve the entire text of the response from inside the match methods,
use {@link org.apache.juneau.rest.client.RestCall#getCapturedResponse()} since this method will not absorb
the response for those other methods.
The {@link org.apache.juneau.rest.client.RestCall} class provides various convenience pipeTo()
methods to pipe output to output streams and writers.
If you want to pipe output without any intermediate buffering, you can use the {@link org.apache.juneau.rest.client.RestCall#byLines()} method. This will cause the output to be piped and flushed after every line. This can be useful if you want to display the results in real-time from a long running process producing output on a REST call.
Use the {@link org.apache.juneau.rest.client.RestClientBuilder#debug()} method to enable logging for HTTP requests made from the client.
Under-the-covers, this is simply a shortcut for adding the {@link org.apache.juneau.rest.client.RestCallLogger#DEFAULT}
interceptor to the client.
This causes the following output to be generated by the Java org.apache.juneau.rest.client
logger at
=== HTTP Call (outgoing) ======================================================= === REQUEST === POST http://localhost:10000/testUrl HTTP/1.1 ---request headers--- Debug: true No-Trace: true Accept: application/json ---request entity--- Content-Type: application/json ---request content--- {"foo":"bar","baz":123} === RESPONSE === HTTP/1.1 200 OK ---response headers--- Content-Type: application/json;charset=utf-8 Content-Length: 21 Server: Jetty(8.1.0.v20120127) ---response content--- {"message":"OK then"} === END ========================================================================
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--- Host: localhost:10000 Transfer-Encoding: chunked Accept: application/json Content-Type: application/json User-Agent: Apache-HttpClient/4.5 (Java/1.6.0_65) Connection: keep-alive Debug: true Accept-Encoding: gzip,deflate ---Default Servlet Headers--- ---Body--- {"foo":"bar","baz":123} === END ========================================================================
Use the {@link org.apache.juneau.rest.client.RestClientBuilder#logTo(Level,Logger)} and
{@link org.apache.juneau.rest.client.RestCall#logTo(Level,Logger)} methods to log HTTP calls.
These methods will cause the HTTP request and response headers and body to be logged to the specified logger.
The method call is ignored if the logger level is below the specified level.
Customized logging can be handled by sub-classing the {@link org.apache.juneau.rest.client.RestCallLogger} class and using the {@link org.apache.juneau.rest.client.RestCall#interceptor(RestCallInterceptor)} method.
The {@link org.apache.juneau.rest.client.RestClientBuilder#interceptors(RestCallInterceptor...)} and {@link org.apache.juneau.rest.client.RestCall#interceptor(RestCallInterceptor)} methods can be used to intercept responses during specific connection lifecycle events.
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.
Juneau provides the capability of calling methods on POJOs on a server through client-side proxy interfaces.
It offers a number of advantages over other similar remote proxy interfaces, such as being much simpler to
use and allowing much more flexibility.
Proxy interfaces are retrieved using the {@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class)}
method.
The remoteable servlet is a specialized subclass of {@link org.apache.juneau.rest.RestServlet} that
provides a full-blown REST interface for calling interfaces remotely.
In this example, we have the following interface defined that we want to call from the client side against a POJO on the server side (i.e. a Remoteable Service)...
The client side code for invoking this method is shown below...
The requirements for a method to be callable through a remoteable service are:
One significant feature is that the remoteable services servlet is a full-blown REST interface.
Therefore, in cases where the interface classes are not available on the client side, the same method calls
can be made through pure REST calls.
This can also aid significantly in debugging since calls to the remoteable service can be called directly
from a browser with no code involved.
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.
The {@link org.apache.juneau.rest.client.RestClientBuilder#set(String,Object)} method can be used to
set serializer and parser properties.
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.
The {@link org.apache.juneau.rest.client.RestCall#retryable(int,long,RetryOn)} method can be used to
automatically retry requests on failures.
This can be particularly useful if you're attempting to connect to a REST resource that may be in the
process of still initializing.
juneau-microservice-server-7.0.0.jar
org.apache.juneau.microservice.server_7.0.0.jar
my-microservice.zip
Juneau Microservice is an API for creating stand-alone executable jars that can be used to start lightweight configurable REST interfaces with all the power of the Juneau REST server and client APIs.
The Microservice API consists of a combination of the Juneau Core, Server, and Client APIs and an embedded
Eclipse Jetty Servlet Container.
It includes all libraries needed to execute in a Java 1.6+ environment.
Features include:
The juneau-microservice-server library consists of the following classes:
The
Follow these instructions to create a new template project in Eclipse.
The important elements in this project are:
At this point, you're ready to start the microservice from your workspace.
The
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 List of available commands: exit -- Shut down service restart -- Restarts service help -- Commands help >
Now open your browser and point to
You have started a REST interface on port 10000.
You can enter the command exit to shut it down.
The
The easiest way to build your microservice is to run the following from the project root.
mvn clean install
Your target directory should now contain the following files:
my-microservice-1.0.jar
my-microservice.cfg
jetty.xml
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 List of available commands: exit -- Shut down service restart -- Restarts service help -- Commands help >
If you get this error message: java.net.BindException: Address already in use,
then this microservice is already running elsewhere and so it cannot bind to port 10000.
The generated
If you open it, you'll see the following:
The
In most cases, this value will always be
However, it is possible to extend this class or implement your own microservice, in which case you'll need
to modify this value to point to the new class.
The
In addition to these predefined manifest entries, you can add your own particular entries to the manifest file and access them through the Manifest API described next.
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}.
The {@link org.apache.juneau.utils.ManifestFile} class extends {@link org.apache.juneau.ObjectMap}.
That makes it possible to retrieve entries as a wide variety of object types such as java primitives, arrays, collections,
maps, or even POJOs serialized as JSON.
The microservice config file is an external INI-style configuration file that is used to configure your microservice.
If you open the
The contents were shown in the previous sections.
Although the config file looks deceptively simple, the config file API is a very powerful feature with many capabilities, including:
There are 3 primary ways of getting access to the config file.
Additional user-defined variables can be defined at this level by adding a {@link org.apache.juneau.rest.annotation.HookEvent#INIT} hook method and using the {@link org.apache.juneau.rest.RestContextBuilder#vars(Class...)} method.
Additional user-defined variables can be defined at this level by overriding the {@link org.apache.juneau.rest.RestContextBuilder#vars(Class...)} method.
That
Here's what happens when an HTTP call is made to
This particular example is needlessly complex, but it gives an idea of how variables can be used recursively to produce sophisticated results
Now let's take a look at the resource classes themselves.
The top-level page...
...is generated by this class...
If you click the
...which is generated by this class...
The following predefined resource classes are also provided for easy inclusion into your microservice:
The {@link org.apache.juneau.microservice.RestMicroservice} class is the main application entry-point for REST microservices.
The class hierarchy is:
Refer to the Javadocs for these class for more information.
This example shows how the {@link org.apache.juneau.microservice.RestMicroservice} class
can be extended to implement lifecycle listener methods or override existing methods.
We'll create a new class
First, the manifest file needs to be modified to point to our new microservice:
Then we define the following class:
The microservice APIs provide several useful methods that can be used or extended.
juneau-examples-core-7.0.0.zip
The juneau-examples-core project contains various code examples for using the core APIs.
The project project can be loaded into your workspace by importing the
juneau-examples-core-7.0.0.zip file.
Download the juneau-examples-core-7.0.0.zip file from the downloads page
(located in the binaries) and import it into your workspace as an existing project:
Select the archive file and import the project:
Once loaded, you should see the following project structure:
The Core library samples are currently a work-in-progress so there's not much here yet. This section will be updated as new code is added.
juneau-examples-rest-7.0.0.zip
The juneau-examples-rest project includes everything you need to start the Samples REST
microservice in an Eclipse workspace.
This project is packaged as a Juneau Microservice project that allows REST resources to be started using embedded Jetty.
Download the juneau-examples-rest-7.0.0.zip file from the downloads page
(located in the binaries) and import it into your workspace as an existing project:
Select the archive file and import the project:
Once loaded, you should see the following project structure:
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:
The
The class hierarchy for this class is:
Pointing a browser to the resource shows the following:
The
The
The resource bundle contains the localized strings for the resource:
The
The
Child resources must also be subclasses of {@link org.apache.juneau.rest.RestServlet}, and
must specify a {@link org.apache.juneau.rest.annotation.RestResource#path() @RestResource.path()} annotation to
identify the subpath of the child.
For example, the
It should be noted that child resources do not need to be defined this way.
They could also be defined as servlets in the same way as the root resource.
The
Note that these router pages can be arbitrarily nested deep. You can define many levels of router pages for arbitrarily hierarchical REST interfaces.
The
The class hierarchy for this class is:
Pointing a browser to the resource shows the following:
Using the special
The
The resource is provided to show how various HTTP entities (e.g. parameters, headers) can be accessed
as either annotated Java parameters, or through methods on the
The class consists of 4 methods:
There's a lot going on in this method. Notice how you're able to access URL attributes, parameters, headers, and content as parsed POJOs. All the input parsing is already done by the toolkit. You simply work with the resulting POJOs.
As you might notice, using annotations typically results in fewer lines of code and are therefore usually preferred over the API approach, but both are equally valid.
When you visit this page through the router page, you can see the following (after the automatic redirection occurs):
Notice how the conversion to POJOs is automatically done for us, even for non-standard POJOs such as UUID.
One of the main features of Juneau is that it produces OPTIONS pages for self-documenting design (i.e. REST interfaces that document themselves).
Much of the information populated on the OPTIONS page is determined through reflection. This basic information can be augmented with information defined through:
SystemPropertiesResource example above.
$L localization variable.
MethodExampleResource.json).
MethodExampleResource_ja_JP.json);
OPTIONS pages are simply serialized {@link org.apache.juneau.dto.swagger.Swagger} DTO beans. Localized versions of these beans are retrieved using the {@link org.apache.juneau.rest.RestRequest#getSwagger()} method.
To define an OPTIONS request handler, the {@link org.apache.juneau.rest.BasicRestServlet} class defines the following Java method:
The
This simply creates a link that's the same URL as the resource URL appended with
Metadata about the servlet class is combined with localized strings from a properties file associated
through a annotation.
The properties file contains localized descriptions for the resource, resource methods, and method
parameters.
Clicking the
This page (like any other) can also be rendered in JSON or XML by using the
The
The class is shown below:
The {@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String,boolean)} method pulls in the following file located in the same package as the class:
The
The
Pointing a browser to the resource shows the following:
Entering some values and clicking
Another option is to construct the HTML form in Java using HTML5 beans. This is arguably a better approach since it's typically cleaner with less code, and the headers/links are already part of the page.
The
It provides examples of the following:
The class is shown below:
Again, there's a lot going on here that's new that requires some explanation.
The
The {@link org.apache.juneau.rest.annotation.RestResource#properties() @RestResource.properties()}, {@link org.apache.juneau.rest.annotation.RestResource#beanFilters() @RestResopurce.beanFilters()}, and {@link org.apache.juneau.rest.annotation.RestResource#pojoSwaps() @RestResopurce.pojoSwaps()} annotations are used to set behavior properties on the resource's underlying bean context, serializers, and parsers. You're using them here to modify the behavior of serialization for all content types. The annotations are functionally equivalent to using the {@link org.apache.juneau.rest.RestContextBuilder} class, as follows:
Note how the annotations generally require fewer lines of code.
Pointing a browser to the resource shows the following:
This gives you an idea of what kinds of POJO models can be serialized, since you are serializing a regular
old
The
Pointing a browser to the resource shows the following:
The code is straightforward, consisting of the following classes:
Persons.
The
Our address book uses the following interface:
The
@Xml (elementName="addressBook" ) annotation tells the toolkit that
when serialized as XML, the element name is
The
@Rdf (beanUri=true ) annotation identifies the @BeanProperty (swap=CalendarSwap.Medium.class ) annotation causes
the date field to be serialized in the format
The
@Xml (ns="mail" ) annotation.
The
The
The
The OPTIONS page uses the servlet resource bundle to specify the labels so that they're globalizable.
Pointing a browser to the resource shows the results of running the
Clicking the
Notice how the
Also notice how the dates are formatted as readable strings.
This was from the transform you added to the
Let's see what the output looks like in other formats:
Notice how our
Also notice how the annotations caused the
Notice how the annotations are used to identify
values for
Also notice how
Now lets look at the schema outputs that can be rendered that show information about the POJO classes themselves.
Now let's see what else you can do.
Clicking on the first
Clicking on the OPTIONS link on the page shows you the Swagger doc generated from our annotations and resource bundle properties:
Because you added the
The
The
The
You'll notice that the class is a stand-alone executable that can be invoked as a plain Java process.
The output from running this code is the following:
Running client test... Number of entries = 2 Deleted person Barack Obama, response = DELETE successful Deleted person George Walker Bush, response = DELETE successful Number of entries = 0 Created person Barack Obama, uri = http://localhost:9081/sample/addressBook/people/3 Created person George Walker Bush, uri = http://localhost:9081/sample/addressBook/people/4 Created address http://localhost:9081/sample/addressBook/addresses/7 Created address http://localhost:9081/sample/addressBook/addresses/8 Changed name, response = PUT successful New name = Barack Hussein Obama
The Juneau architecture is designed to make it easy to debug REST resources using nothing more than a browser. 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:
The ability to overload methods is enabled through the
setting.
RestResource.allowMethodParam()
The
The
The
Pointing a browser to the resource shows the following:
Clicking the hyperlinks on each shows you the list of methods that can be invoked on that service.
Note that the
Proxy interfaces are then retrieved using the {@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class)} method.
The client side code for invoking this method is shown below:
The
Pointing a browser to the resource shows the following:
Pointing a browser to the
Note how a system property variable can be defined in the properties file.
Note how the HTML file contains localized variables for the servlet label and description.
The
Pointing a browser to the resource shows the following:
True ATOM feeds require using an
Other languages, such as JSON are also supported:
The
Pointing a browser to the resource shows the following:
Clicking the
The Docker registry URL is specified in the
The
Pointing a browser at a Tumblr blog name, such as
The
The resource consists of a simple registry of images with integer IDs.
It is initialized with a single entry, which can be accessed through a GET request.
The
The resource consists of a pre-initialized {@link org.apache.juneau.dto.jsonschema.Schema} object. Pointing a browser to the resource shows the following:
For true JSON-Schema, you need to specify the header
The
The example uses embedded Derby to create a database whose name is defined in the external configuration files.
Pointing a browser to the resource shows the following:
Running a query results in the following output:
The {@link org.apache.juneau.microservice.resources.LogsResource} class is a reusable predefined resource.
It provides a REST interface for the log files generated by the microservice.
Pointing a browser to the resource shows the following:
The
The
Security is always an ongoing concern in any library. If you discover any security vulnerabilities in this code, please refer to the instructions found here:
One common security vulnerability is the ability to create arbitrary Java object instances through crafted
user input. For example, support for constructing POJOs based on an input attribute defining a
fully-qualified class name like
Fortunately, Juneau does not support an open-ended JsonParser.).
As long as the Class object passed into this method is not constructed from user-generated input,
it should be free from demarshalling vulnerabilities.
The following example shows a potential vector that circumvents the restriction above:
Juneau does support something similar to a
i.e. instead of
Since bean types are defined at compile time, it's impossible to instantiate arbitrary POJOs.
POJO types of generalized input are also inferred through swaps. Again, since the POJO types are hardcoded at compile time, these should not be subject to demarshalling vulnerabilities. However, it is possible to circumvent this through your swap implementation as shown below:
Note that the {@link org.apache.juneau.jso.JsoParser}, a thin layer of the Juneau Parser API written on
top of plain-old Java Object Serialization which itself is vulnerable to demarshalling issues.
Due to this, the JSO parser is not included in any of the default REST servlet implementations.
Be especially careful when using this parser, particularly if you want to use it for handing
application/x-java-serialized-object input through REST servlets.
All other parsers (JSON, URL-Encoding, MessagePack, etc...) work the same way in determining POJO types, so should be safe from demarshalling vulnerabilities.
When accessing security vulnerabilities of any library, dependent libraries must also be taken into account:
7.0.1, no known security vulnerabilities exist that affect Juneau at this time.
Care must be used when defining new {@link org.apache.juneau.svl.Var Vars} using the SVL API since mistakes could potentially expose system properties, environment variables, or even file system files.
For recap, the SVL support allows you to embed variables of the form
An example of a potential security hole is shown below that could potentially expose any file on a file system through a REST request:
This code is simply echoing the value of the foo query parameter.
Now say for example that a bad actor passes in the query string $F variable allows you to resolve the contents of files using SVL, and is provided
by default using the built-in variable resolver returned by the RestRequest object.
You've potentially just exposed the contents of that file through your REST interface.
In reality, the above security hole does not exist because of the following restrictions:
Vars have two methods {@link org.apache.juneau.svl.Var#allowNested()} and
{@link org.apache.juneau.svl.Var#allowRecurse()} that can be overridden to prevent recursive processing
of string variables. These are both $R variable, so the $F
variable in the result will never get processed and instead be treated as plain text.
$F variable only allows you to retrieve files within the JVM starting directory.
Even though the built-in Juneau variables are safe, special care is needed when defining your own custom variables. If your variable resolves user input in any way, it's HIGHLY recommended that you override the {@link org.apache.juneau.svl.Var#allowNested()} and {@link org.apache.juneau.svl.Var#allowRecurse()} methods to prevent recursive handling of variables.
Denial of service attacks can be alleviated through the {@link org.apache.juneau.rest.annotation.RestResource#maxInput() maxInput()} setting. Arbitrarily-large input will trigger an exception before causing out-of-memory errors. The default value for this setting is 100MB.
Since the parsers do not use intermediate DOMs and instead parse directly into Java objects, deeply nested data structures will almost always trigger stack overflow errors long before memory consumption becomes an issue. However, this is NOT true of the RDF parsers that use an intermediate DOM. If parsing RDF, you may want to consider lowering the max-input value above.
TBD
Resource and ResourceGroup classes removed.
ResourceJena and ResourceJenaGroup classes rename to
{@link org.apache.juneau.microservice.BasicRestServletJena} and {@link org.apache.juneau.microservice.BasicRestServletJenaGroup} can be used instead.
Version 7.1.0 is a major update with major implementation refactoring across all aspects of the product.
Context classes (e.g. JsonSerializerContext) have been folded into
their respective serializer or parser classes (e.g. JsonSerializer).
JsonSerializer is now:
Context objects are thread-safe and read-only.
JsonSerializerSession is now:
JsonSerializerBuilder is now:
Context objects.
PropertyStore class was overly-complicated with many read/write
locks to ensure thread-safety.
PropertyStore objects
that can be used as hash keys.
PartSerializer/PartParser classes
have been replaced with the following all located in the new org.apache.juneau.httppart package:
ContextBuilder.property(String,Object) renamed to {@link org.apache.juneau.ContextBuilder#set(String,Object)}.
ResourceFinder class has been replaced with the following:
RestServletDefault renamed to {@link org.apache.juneau.rest.BasicRestServlet}.
RestServletGroupDefault renamed to {@link org.apache.juneau.rest.BasicRestServletGroup}.
HttpServletRequest.getAttribute(String).
RestConfig class into {@link org.apache.juneau.rest.RestContextBuilder}.
RestMatcherReflecting class.
@RestResource.allowMethodParam renamed to {@link org.apache.juneau.rest.annotation.RestResource#allowedMethodParams}.
@RestMethod.serializersInherit and @RestMethod.parsersInherit replaced with
simplified {@link org.apache.juneau.rest.annotation.RestMethod#inherit() @RestMethod.inherit()}.
Map<String,Object> instead of Map<String,String>.
Map<String,Object> instead of Map<String,String>.
Map<String,Object> instead of Map<String,String>.
getResource(String,Locale) renamed to {@link org.apache.juneau.rest.RestContext#getClasspathResource(String,Locale) getClasspathResource(String,Locale)}
getResourceAsString(String,Locale) renamed to {@link org.apache.juneau.rest.RestContext#getClasspathResourceAsString(String,Locale) getClasspathResourceAsString(String,Locale)}
getResource(Class,MediaType,String,Locale) renamed to {@link org.apache.juneau.rest.RestContext#getClasspathResource(Class,MediaType,String,Locale) getClasspathResourceAsString(Class,MediaType,String,Locale)}
Map<String,Object> instead of Map<String,String>.
Map<String,Object> instead of Map<String,String>.
getSupportedMediaTypes() replaced with
{@link org.apache.juneau.rest.RestRequest#getConsumes() getConsumes()} and
{@link org.apache.juneau.rest.RestRequest#getProduces() getProduces()}.
getReaderResource(String,boolean,MediaType) renamed to
{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String,boolean,MediaType) getClasspathReaderResource(String,boolean,MediaType)}
getReaderResource(String,boolean) renamed to
{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String,boolean) getClasspathReaderResource(String,boolean)}
getReaderResource(String) renamed to
{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String) getClasspathReaderResource(String)}
RestCallHandler split up into {@link org.apache.juneau.rest.RestCallHandler} and
{@link org.apache.juneau.rest.BasicRestCallHandler}
RestInfoProvider split up into {@link org.apache.juneau.rest.RestInfoProvider} and
{@link org.apache.juneau.rest.BasicRestInfoProvider}
RestLogger split up into {@link org.apache.juneau.rest.RestLogger},
{@link org.apache.juneau.rest.BasicRestLogger} and {@link org.apache.juneau.rest.NoOpRestLogger}
RestResourceResolverSimple renamed to {@link org.apache.juneau.rest.BasicRestResourceResolver}
@Messages and @Properties REST java method parameter
annotations.
MessageBundle and
RestRequestProperties as unannotated parameters.
finish()
instead of close() on the stream.
Resource class):
PartSerializer with {@link org.apache.juneau.httppart.HttpPartSerializer}.
Closeable interface.
This release is a minor update. It includes the following prereq updates:
create() methods for builders on serializers and parsers.
ConfigFile.create()
Running class 'RestMicroservice' using config file 'examples.cfg'. Server started on port 10000 List of available commands: exit -- Shut down service restart -- Restarts service help -- Commands help echo -- Echo command > help help NAME help -- Commands help SYNOPSIS help [command] DESCRIPTION When called without arguments, prints the descriptions of all available commands. Can also be called with one or more arguments to get detailed information on a command. EXAMPLES List all commands: > help List help on the help command: > help help >
Commands are pluggable and extensible through the config file.
This release ups the Java prerequisite to Java 7.
org.apache.juneau.dto.Link renamed to {@link org.apache.juneau.dto.LinkString}.
Helps avoid confusion since there are other Link classes in the library.
@HtmlDoc (links) renamed to {@link org.apache.juneau.rest.annotation.HtmlDoc#navlinks() navlinks}.
@HtmlDoc (favIcon).
@HtmlDoc (head), you can define them using:
head={
RestResponse/RestConfig/RestContext
classes and moved it into the new {@link org.apache.juneau.rest.HtmlDocBuilder} class.
The major change in this release is the project structure.
The library now consists of the following artifacts found in the Maven group "org.apache.juneau":
| Category | Maven Artifacts | Description | Prereqs |
|---|---|---|---|
| Juneau Core | juneau-marshall | Serializers and parsers for:
|
|
| juneau-marshall-rdf |
Serializers and parsers for:
|
|
|
| juneau-dto |
Data Transfer Objects for:
|
|
|
| juneau-svl | Simple Variable Language API |
|
|
| juneau-config | Configuration file API |
|
|
| Juneau REST | juneau-rest-server | REST Servlet API |
|
| juneau-rest-server-jaxrs | Optional JAX-RS support |
|
|
| juneau-rest-client | REST Client API |
|
|
| Juneau Microservice | juneau-microservice-server | REST Microservice Server API |
|
| juneau-microservice-template | Developer template project |
|
|
| Examples | juneau-examples-core |
Core code examples | |
juneau-examples-rest |
REST code examples | ||
| Juneau All | juneau-all |
Combination of the following:
|
|
@Pojo and @BeanProperty.swap() annotations.
PojoSwaps, this can be used to provide customized
output for specific content types.
SerializeException/ParseException.
getClass() to retrieve the annotation value could not be called before calling
the super () method.
toString() method.
Swagger.toString() produces JSON and the HTML5 Form.toString()
produces HTML.
init(RestConfig)
- Use {@link org.apache.juneau.rest.annotation.HookEvent#INIT} instead.
onSuccess(RestRequest, RestResponse, long)
- Use {@link org.apache.juneau.rest.annotation.HookEvent#END_CALL} instead.
onPreCall(RestRequest)
- Use {@link org.apache.juneau.rest.annotation.HookEvent#PRE_CALL} instead.
onPostCall(RestRequest, RestResponse)
- Use {@link org.apache.juneau.rest.annotation.HookEvent#POST_CALL} instead.
RestContext.REST_allowHeaderParams setting.
RestResource.allowMethodParam() -
RestContext.REST_allowMethodParam setting.
RestContext.REST_allowBodyParam setting.
RestContext.REST_xxx setting.
RestContext.REST_useStackTraceHashes setting.
RestContext.REST_defaultCharset setting.
RestResource.paramFormat() -
RestContext.REST_paramFormat setting.
RestContext.REST_defaultCharset setting.
RestMethod.paramFormat() -
RestContext.REST_paramFormat setting.
?stylesheet query parameter.
RestServletJenaDefault class to remove the Jena dependency class on
the juneau-rest-server artifact.
BasicRestServlet and add the RDF serializers and
parsers.
jetty.xml file
for maximum flexibility instead of the hodge-podge of support in the config file.
jetty.xml file.
Juneau 6.3.1 is a minor release.
HtmlDocSerializerContext:
HTMLDOC_script
HTMLDOC_style - Was HTMLDOC_stylesheet - Was ResourceFinder utility class.
Allows you to search for resources up the parent hierarchy chain.
Also allows you to search for localized resources.
HtmlDocSerializerContext:
PoweredByApacheWidget -> PoweredByApache
PoweredByJuneauWidget -> PoweredByJuneau
css().
cssUrl().
@RestResource.stylesheet() annotation.
It's no longer needed now that you can easily specify styles via title()
description()
branding()
htmldoc=
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=
bpIncludes() and bpExcludes() annotations on $R variable: Juneau 6.3.0 is a major update with significant new functionality for defining proxy interfaces against arbitrary 3rd-party REST interfaces.
2.8 - Virtual Beans
2.13 - Comparison with Jackson
ConfigFile:
ConfigFile.put(String,String,String,boolean)
ConfigFile.put(String,String,Object,Serializer,boolean,boolean)
ConfigFile.getObject(String,Type,Type...)
ConfigFile.getObject(String,Parser,Type,Type...)
ConfigFile.getObject(String,Class)
ConfigFile.getObject(String,Parser,Class)
ConfigFile.getObject(String,String,Type,Type...)
ConfigFile.getObject(String,String,Parser,Type,Type...)
ConfigFile.getObject(String,String,Class)
ConfigFile.getObject(String,String,Parser,Class)
ConfigFile.getObjectWithDefault(String,Object,Type,Type...)
ConfigFile.getObjectWithDefault(String,Parser,Object,Type,Type...)
ConfigFile.getObjectWithDefault(String,Object,Class)
ConfigFile.getObjectWithDefault(String,Parser,Object,Class)
ConfigFile.getSectionAsInterface(String,Class).
Session.getProperty(String)
Session.getProperty(String,String)
Session.getProperty(Class,String)
Session.getProperty(Class,String,Object)
org.apache.juneau.serializer.PartSerializer interface particularly tailored to HTTP
headers, query parameters, form-data parameters, and path variables.
pages=
links=
SerializerContext.SERIALIZER_uriContext
SerializerContext.SERIALIZER_uriRelativity
SerializerContext.SERIALIZER_uriResolution
SerializerContext.SERIALIZER_maxIndent
UonSerializer.UON_paramFormat,
and the UON/URL-Encoding serializers will now always serialize all values as plain text.
RestConfig.serializerListener(Class)
RestConfig.parserListener(Class)
RestClientBuilder.listeners(Class,Class)
ParserSession.getInputAsString() method so that it can be used
in the listeners.
HtmlDocSerializerContext.HTMLDOC_title
HtmlDocSerializerContext.HTMLDOC_description
HtmlDocSerializerContext.HTMLDOC_branding
HtmlDocSerializerContext.HTMLDOC_header
HtmlDocSerializerContext.HTMLDOC_nav
HtmlDocSerializerContext.HTMLDOC_aside
HtmlDocSerializerContext.HTMLDOC_footer
HtmlDocSerializerContext.HTMLDOC_noResultsMessage
HtmlDocSerializerContext.HTMLDOC_cssUrl
HtmlDocSerializerContext.HTMLDOC_css
HtmlDocSerializerContext.HTMLDOC_template
RestRequest.
RestResponse.
@RestMethod (name="*" ))
ConfigFile - The external config file for the resource.
bpIncludes()
bpExcludes()
widgets()
widgets()
RestConfig:
setHtmlTitle(String)
setHtmlDescription(String)
setHtmlBranding(String)
setHtmlHeader(String)
setHtmlLinks(String)
setHtmlNav(String)
setHtmlAside(String)
setHtmlFooter(String)
setHtmlCss(String)
setHtmlCssUrl(String)
setHtmlNoWrap(boolean)
setHtmlNoResultsMessage(String)
setHtmlTemplate(Class)
setHtmlTemplate(HtmlDocTemplate)
addWidget(Class)
setHtmlTitle(Object)
setHtmlDescription(Object)
setHtmlBranding(Object)
setHtmlHeader(Object)
setHtmlLinks(Object)
setHtmlNav(Object)
setHtmlAside(Object)
setHtmlFooter(Object)
setHtmlCss(Object)
setHtmlCssUrl(Object)
setHtmlNoWrap(boolean)
setHtmlNoResultsMessage(Object)
setHtmlTemplate(Class)
setHtmlTemplate(HtmlDocTemplate)
&plainText=true parameter now works on byte-based serializers by converting the output to hex.
PoweredByJuneauWidget
ContentTypeLinksColumnWidget
ContentTypeLinksRowWidget
QueryWidget
devops.css cleaned up.
NameValuePairs and beans as input
when using
Juneau 6.2.0 is a major update.
ConfigFileBuilder.
Lockable interface.
addBeanTypeProperties setting added to serializers to override the
SerializerContext.SERIALIZER_addBeanTypeProperties setting
for individual serializers in a serializer group:
HtmlSerializerContext.HTML_addBeanTypeProperties
JsonSerializerContext.JSON_addBeanTypeProperties
MsgPackSerializerContext.MSGPACK_addBeanTypeProperties
UonSerializerContext.UON_addBeanTypeProperties
XmlSerializerContext.#XML_addBeanTypeProperties
RdfSerializerContext.RDF_addBeanTypeProperties
org.apache.juneau.uon package.
style() override methods to all elements.
here and in the $SWITCH variable for switch block logic.
SerializerContext.SERIALIZER_abridged.
6 - Remoteable Services
6.1 - Interface proxies against 3rd-party REST interfaces
UrlEncodingSerializerContext.URLENC_paramFormat.
UrlEncodingSerializerBuilder.paramFormat(String)
UrlEncodingSerializerBuilder.plainTextParams()
RestServlet
should have an equivalent for non-RestServlet classes.
RestServlet.
Child resources do not.
RestConfig - A modifiable configuration of a resource. Subclasses from {@link javax.servlet.ServletConfig}.
RestServlet.init(RestConfig) - A modifiable configuration of a resource.
RestServlet classes must have one of the following to allow it to be instantiated:
public T(RestConfig) constructor.
public T() constructor.
RestServlet classes can optionally include the following init methods to gain access to the config and context:
public init(RestConfig)
public init(RestContext)
RestServlet
resources to do the same as subclassing directly from RestServlet:
@RestResource.pageTitle()
@RestMethod.pageTitle()
@RestResource.pageText()
@RestMethod.pageText()
@RestResource.pageLinks()
@RestMethod.pageLinks()
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.stylesheet() can now take in a comma-delimited list of stylesheet paths.
byte [] arrays, InputStreams, Files, etc...)
and is now immutable. It also includes a new {@link org.apache.juneau.rest.StreamResourceBuilder} class.
@RestMethod (name="PROXY" ) annotation on REST methods.
Used to expose interface proxies without the need for {@link org.apache.juneau.rest.remoteable.RemoteableServlet}.
RestClient class doX(Object url) methods now handle HttpClient URIBuilder instances.
@RestMethod (name="PROXY" ).
query(String,Object,boolean,PartSerializer)
formData(String,Object,boolean,PartSerializer)
header(String,Object,boolean,PartSerializer)
RestClientBuilder.plainTextParams()
No-Trace: true header on all requests to prevent
the servlet from logging errors.
Debug: true header on all requests.
HttpResponse returned by the inner HttpClient.
append(String,Object,PartSerializer)
0s to try a random port.
Juneau 6.1.0 is a major update.
In particular, this release cleans up the {@link org.apache.juneau.BeanContext} API to match the {@link org.apache.juneau.PropertyStore}/{@link org.apache.juneau.Context}/{@link org.apache.juneau.Session} paradigm previously used in the serializer and parser APIs. It also makes several improvements to the HTML and XML serialization support and introduces HTML5 DTO beans.
XmlContentHandler class.
addJsonTypeAttrs and addJsonStringTypeAttrs settings.
XMLEventReader-based to XMLStreamReader.
SerializerContext and ParserContext
now extend directly from {@link org.apache.juneau.BeanContext}.
parseMap(), parseCollection())
by replacing them with two simple methods:
ClassMeta object.
ClassMeta objects.
parseMap() and parseCollection() methods!
BeanContext.normalizeClassMeta() method.
toObjectMap() and fromObjectMap()/T(ObjectMap) methods with
generalized swap(BeanSession)/unswap(BeanSession,X)/T(BeanSession,X) methods.Swap methods for information.
getMapClassMeta()/getCollectionClassMeta() methods.
Juneau Data Transfer Objects (org.apache.juneau.dto)
UonParser.DEFAULT_WS_AWARE and UrlEncodingParser.DEFAULT_WS_AWARE parsers.
UonParserContext.UON_whitespaceAware configuration setting.
UonSerializer.DEFAULT_SIMPLE , UonSerializer.DEFAULT_SIMPLE_ENCODING
and UrlEncodingSerializer.DEFAULT_SIMPLE
serializers since there is no separate simple mode anymore.
UonParserContext.UON_simpleMode configuration setting.
@Bean (subTypeProperty) and @Bean (subTypes) annotations
and replaced them with the ability to define subtypes using the existing {@link org.apache.juneau.annotation.Bean#beanDictionary() @Bean.beanDictionary()}
annotation on parent classes and interfaces.
SerializerContext.SERIALIZER_addBeanTypeProperties setting is now enabled by default.
SERIALIZER_addIndentation/JSON_addWhitespace/UON_addWhitespace
properties into a single SerializerContext.SERIALIZER_useWhitespace setting.
RestRequest.getTimeZone() method.
ClassMeta
objects and eliminate the need for casts:
RestRequest.getHeader(String,Class)
RestRequest.getHeader(String,Object,Class)
RestRequest.getHeader(String,Type,Type...)
RestRequest.getQueryParameter(String,Class)
RestRequest.getQueryParameter(String,Object,Class)
RestRequest.getQueryParameter(String,Type,Type...)
RestRequest.getQueryParameter(String,Object,Type,Type...)
RestRequest.getQueryParameters(String,Class)
RestRequest.getQueryParameters(String,Type,Type...)
RestRequest.getFormDataParameter(String,Class)
RestRequest.getFormDataParameter(String,Object,Class)
RestRequest.getFormDataParameters(String,Class)
RestRequest.getFormDataParameter(String,Type,Type...)
RestRequest.getFormDataParameters(String,Type,Type...)
RestRequest.getPathParameter(String,Class)
RestRequest.getPathParameter(String,Type,Type...)
RestRequest.getBody(Class)
RestRequest.getBody(Type,Type...)
&plainText=true specified.
Juneau 6.0.1 is a minor update.
ParserContext.
ParserContext.PARSER_strict
ParserContext.PARSER_inputStreamCharset
ParserContext.PARSER_fileCharset
JsonParserContext.JSON_strictMode. Replaced by PARSER_strict.
byte[] arrays can now be passed to {@link org.apache.juneau.parser.Parser#parse(Object,Class)} for reader-based parsers.
Juneau 6.0.0 is a major update.
The major change is rebranding from "Juno" to "Juneau" in preparation for donation to the Apache Foundation.
org.apache.juneau.svl.
SerializerContext.SERIALIZER_addBeanTypeProperties - Controls whether type properties are serialized.
@Xml.name() annotation, and the
BeanFilter class to use final fields.
java.util.Date).
org.apache.juneau.internal package.
These internal utility classes are not meant for consumption outside the Juneau codebase.
org.apache.juneau.parser.Parser.createSession(ObjectMap,Method,Object)
Parser.getMediaRanges()
org.apache.juneau.serializer.Serializer.createSession(ObjectMap,Method)
Serializer.getMediaRanges()
ClassFilter class since it's no longer needed.
BeanContext.convertToType(Object,Class).
HtmlSerializerContext.HTML_detectLinksInStrings - Automatically detect hyperlinks in strings.
HtmlSerializerContext.HTML_lookForLabelParameters - Specify anchor text by appending &label=MyLabel to URL.
HtmlSerializerContext.HTML_labelParameter - Specify what URL parameter to use as the anchor text label.
HtmlSerializerContext.URI_ANCHOR option for HtmlSerializerContext.HTML_uriAnchorText.
@Transform annotation to @Pojo so that it can be used for various POJO-related behavior, not just associating transforms.
ResourceOptions and related code.
@RestResource.termsOfService() / RestInfoProvider.getTermsOfService(RestRequest)
@RestResource.contact() / RestInfoProvider.getContact(RestRequest)
@RestResource.license() / RestInfoProvider.getLicense(RestRequest)
@RestResource.version() / RestInfoProvider.getVersion(RestRequest)
@RestResource.tags() / RestInfoProvider.getTags(RestRequest)
@RestResource.externalDocs() / RestInfoProvidergetExternalDocs(RestRequest)
RestInfoProvider.getMethodSummary(String,RestRequest)
RestInfoProvider.getMethodDescription(String,RestRequest)
@RestMethod.externalDocs()
@RestMethod.tags()
@RestMethod.deprecated()
@RestMethod.parameters()
@RestMethod.responses()
RestServletContext.paramFormat context property.
RestServlet.createProperties()
RestServlet.createBeanContext(ObjectMap,Class[],Class[])
RestServlet.createBeanFilters()
RestServlet.createPojoSwaps()
RestServlet.createParsers(ObjectMap,Class[],Class[])
RestServlet.createUrlEncodingSerializer(ObjectMap,Class[],Class[])
RestServlet.createUrlEncodingParser(ObjectMap,Class[],Class[])
RestServlet.createConverters(ObjectMap)
RestServlet.createDefaultRequestHeaders(ObjectMap)
RestServlet.createDefaultResponseHeaders(ObjectMap)
RestServlet.createEncoders(ObjectMap)
RestServlet.createGuards(ObjectMap)
RestServlet.createMimetypesFileTypeMap(ObjectMap)
RestServlet.createResponseHandlers(ObjectMap)
JazzRestClient class.
RestClient.setClientVersion(String).
Juno 5.2.0.1 is a moderate update.
ObjectList.getAt(Class,String)
ObjectMap.getAt(Class,String)
@ThreadSafe annotation.
ClassFilter class.
ConfigFile.getResolving(StringVarResolver,boolean)ConfigFile.getStringVar()ParserContext.PARSER_trimStrings property.
SerializerContext.SERIALIZER_trimStrings property.
Args.getStringVar()}StringMapVarStringVarsStringVarXmlParserContext.XML_trimWhitespace changed to Juno 5.2.0.0 is a major update. Major changes have been made to the microservice architecture and config INI file APIs.
org.apache.juneau.config API.
ConfigFile:
ConfigFile.getStringArray(String),ConfigFile.getStringArray(String,String[])
ConfigFile.getSectionAsBean(String,Class) - Instantiate a new bean with property values in the specified section..
ConfigFile.writeProperties(String,Object,boolean,Class[]) - Copy the properties in a config file section into properties on an existing bean or POJO.
ConfigFile.getSectionMap(String) - Get all the resolved values in a section.
ConfigFile.containsNonEmptyValue(String)
ConfigFile.isEncoded(String)
ConfigFile.addListener(ConfigFileListener) - Listen for modification events on the config file.
ConfigFile.merge(ConfigFile) - Merge the contents of another config file into this config file.
ConfigFile.getResolving(), ConfigFile.getResolving(StringVarResolver)ConfigFile.toWritable() - Wraps the config file in a {@link org.apache.juneau.Writable} interface so that it can be serialized by the REST interface as a plain-text INI file instead of as a serialized POJO.
ConfigFile.getInt(String) - Now supports ConfigMgr:
ConfigMgr.create(), ConfigMgr.create(Reader), ConfigMgr.create(File)
ConfigMgr.deleteAll()
Section:
Section.setParent(ConfigFileImpl) - Used by parsers to set the config file for this section.
Section.setName(String) - Used by parsers to set the name for this section.
org.apache.juneau.config.ConfigFileListener
org.apache.juneau.config.SectionListener
org.apache.juneau.config.EntryListener
org.apache.juneau.config.Encoder methods have access to field names to use them as salt values.
org.apache.juneau.config.XorEncoder XOR key can be overridden through the fromString(String)
valueOf(String) (e.g. enums)
parse(String) (e.g. logging Level class)
parseString(String)
forName(String) (e.g. Class and Charset classes)
Pair<S,T> and you try to parse into this
class (e.g. parser.parse(in, Pair.class )), the unbound type variables
is interpreted as Object instead of throwing an exception.
AtomicInteger
AtomicLong
BigInteger
BigDecimal
Section class represents a section
in a config file. It needs to know it's own name and have a link to the ConfigFile
that it belongs to. With these new annotations, config files can be reconstructed using any of the parsers.
StringObject class that can be used for delayed object serialization.
StringVarMultipartStringVarWithDefaultPojoRest.get(Class,String,Object)
StringVar.doResolve(String)StringVarResolver.DEFAULTjavax.mail.internet.MimeUtility by implementing our own {@link org.apache.juneau.internal.StringUtils#base64Encode(byte[])} method.
/servletPath/style.css instead of /servletPath/htdocs/juneau.css.
This coincides with enhancements made in the server code for specifying styles.
<div class='outerdata'><div class='data' id='data'>...</div></div>).
Needed for supporting the new devops look-and-feel.
RdfProperties.RDF_looseCollection loose collections.
NoClassDefFoundErrors.
UrlEncodingSerializer.DEFAULT_SIMPLE_EXPANDED serializer.
getMainArg(int) changed to {@link org.apache.juneau.utils.Args#getArg(int)}.
Non-existent arguments are returned as org.apache.juneau.utils.CharsetUtils class.
org.apache.juneau.utils.ConcurrentIdentityList class.
ReaderParser.
Simplifies the API on the class.
ReaderParser.
Simplifies the API on the class.
SafeResourceMultiBundle moved from server component.
StringVarResolverNoClassDefFoundErrors
so that resources that include Jena support can continue to operate even if the Jena libraries are not present.
org.apache.juneau.rest.client.LaxRedirectStrategy. Use HTTP Client equivalent.
RestCall#addInterceptor(RestCallInterceptor)
RestCall#addResponsePattern(ResponsePattern)
execute().
RestClient.setBasicAuth(String,int,String,String)
RestClient.logTo(Level,Logger)
RestClient.setRootUrl(String)
RestClient.enableSSL(SSLOpts)
RestClient.enableLaxSSL()
RestClient.createHttpClientBuilder()
HttpClientBuilder:
RestClient.setRedirectStrategy(RedirectStrategy)
RestClient.setDefaultCookieSpecRegistry(Lookup)
RestClient.setRequestExecutor(HttpRequestExecutor)
RestClient.setSSLHostnameVerifier(HostnameVerifier)
RestClient.setPublicSuffixMatcher(PublicSuffixMatcher)
RestClient.setSSLContext(SSLContext)
RestClient.setSSLSocketFactory(LayeredConnectionSocketFactory)
RestClient.setMaxConnTotal(int)
RestClient.setMaxConnPerRoute(int)
RestClient.setDefaultSocketConfig(SocketConfig)
RestClient.setDefaultConnectionConfig(ConnectionConfig)
RestClient.setConnectionTimeToLive(long,TimeUnit)
RestClient.setConnectionManager(HttpClientConnectionManager)
RestClient.setConnectionManagerShared(boolean)
RestClient.setConnectionReuseStrategy(ConnectionReuseStrategy)
RestClient.setKeepAliveStrategy(ConnectionKeepAliveStrategy)
RestClient.setTargetAuthenticationStrategy(AuthenticationStrategy)
RestClient.setProxyAuthenticationStrategy(AuthenticationStrategy)
RestClient.setUserTokenHandler(UserTokenHandler)
RestClient.disableConnectionState()
RestClient.setSchemePortResolver(SchemePortResolver)
RestClient.setUserAgent(String userAgent)
RestClient.setDefaultHeaders(Collection)
RestClient.addInterceptorFirst(HttpResponseInterceptor)
RestClient.addInterceptorLast(HttpResponseInterceptor)
RestClient.addInterceptorFirst(HttpRequestInterceptor)
RestClient.addInterceptorLast(HttpRequestInterceptor)
RestClient.disableCookieManagement()
RestClient.disableContentCompression()
RestClient.disableAuthCaching()
RestClient.setHttpProcessor(HttpProcessor)
RestClient.setRetryHandler(HttpRequestRetryHandler)
RestClient.disableAutomaticRetries()
RestClient.setProxy(HttpHost)
RestClient.setRoutePlanner(HttpRoutePlanner)
RestClient.disableRedirectHandling()
RestClient.setConnectionBackoffStrategy(ConnectionBackoffStrategy)
RestClient.setBackoffManager(BackoffManager)
RestClient.setServiceUnavailableRetryStrategy(ServiceUnavailableRetryStrategy)
RestClient.setDefaultCookieStore(CookieStore)
RestClient.setDefaultCredentialsProvider(CredentialsProvider)
RestClient.setDefaultAuthSchemeRegistry(Lookup)
RestClient.setContentDecoderRegistry(Map)
RestClient.setDefaultRequestConfig(RequestConfig)
RestClient.useSystemProperties()
RestClient.evictExpiredConnections()
RestClient.evictIdleConnections(long,TimeUnit)
JazzRestClient now supports OIDC authentication.
org.apache.juneau.rest.client.jazz.CertificateStore
org.apache.juneau.rest.client.jazz.ICertificateValidator
org.apache.juneau.rest.client.jazz.ITrustStoreProvider
org.apache.juneau.rest.client.jazz.LenientCertificateValidator
org.apache.juneau.rest.client.jazz.SharedTrustStoreProvider
org.apache.juneau.rest.client.jazz.ValidatingX509TrustManager
StringVarReaders
containing text with StringVarResolverOutputStreams.
RestRequest.getReaderResource(String) - Replaces getVarResource(String).
RestRequest.getReaderResource(String,boolean)
RestRequest.getReaderResource(String,boolean,String)
Content-Encoding: identity when no encoding is used. Some clients don't interpret it correctly.
RestServlet.getChildClasses() - Programmatic equivalent to {@link org.apache.juneau.rest.annotation.RestResource#children() @RestResource.children()} annotation.
RestServlet.shouldLog(HttpServletRequest,HttpServletResponse,RestException)
RestServlet.shouldLogStackTrace(HttpServletRequest,HttpServletResponse,RestException)
RestServlet.logObjects(Level,String,Object[])
RestServlet.resolveStaticFile(String)
RestServlet.createStyleSheet()
RestServlet.createFavIcon()
RestServlet.createStaticFilesMap()
RestServlet.getConfigMgr()
RestServletJenaDefault.
These may represent a security risk if not handled correctly, so removed
them as a precaution.
RestServletProperties.REST_htDocsFolder. Replaced with {@link org.apache.juneau.rest.annotation.RestResource#staticFiles() @RestResource.staticFiles()}.
RestResource.stylesheet()
RestResource.favicon()
org.apache.juneau.rest.jaxrs.JsonProvider class.
Some JAX-RS implementations use code scanning to find providers, so if you were using DefaultJenaProvider, it would
pick up JsonProvider as well. It's easy enough to create your own implementation if needed.
consumes and produces fields instead of accept and contentType which was confusing.
properties from OPTIONS pages.
ResourceLink.ResourceLink(String,RestRequest,String,Object[]) constructor.
org.apache.juneau.microservice.Main class. This is replaced by
the microservice classes defined above.
Resource and ResourceGroup
classes now support the following new string variables:
org.apache.juneau.microservice.RootResource
org.apache.juneau.microservice.SampleResource
StringVarResolverOverview / Samples - New section.
Juno 5.1.0.20 is a moderate update.
The biggest improvement is the ability to associate external INI config files with REST servlets using the functionality.
ConfigFile
org.apache.juneau.config API.
ConfigFile is now thread safe and can be shared across multiple threads.
ConfigMgr class for managing configuration files.
ObjectMap.remove(Class,String,Object) method.
EncoderGroup#append(EncoderGroup) method.
HtmlDocSerializerContext.HTMLDOC_addLinks configuration property.
Parser.createContext(ObjectMap,Method,Object) method.
Outer context objects can be passed in to create instances of non-static inner classes.
RestServlet.getConfig()RestServlet.createConfigFile()
RestServlet.getResource(String)RestServlet.getResourceAsString(String)RestServlet.getResource(Class,String,String)RestServlet.handleNotFound(int,RestRequest,RestResponse) method for customized handling
of when a resource or method was not found.
RestServlet.handleNotFound(int,RestRequest,RestResponse) method.
RestRequest.resolveVars(String)
RestRequest.getVarResource(String)
RestRequest.getConfig()
getWriter() now returns an unnegotiated writer.
getUnbufferedWriter() has been removed.
RestMethod.inheritEncoders() annotations.
Allows encoders to be fine-tuned at the method level.
ConfigFile config files with servlets.
ResourceLink.
org.apache.juneau.rest.matchers package for commonly-used {@link org.apache.juneau.rest.RestMatcher RestMatchers}:
Juno 5.1.0.19 is a minor update in terms of core functionality.
But it introduces a project for building REST microservices and docker containers.
Microservices
StringVarResolverRestResponse.getUnbufferedWriter() method.
x-response-headers parameter from working correctly.
org.apache.juneau.rest.labels so that the order of the bean properties are consistent
on all JVMs. On IBM JVMs this is unnecessary because the order of the properties as defined in the class
are stored in the bytecode. Other JVMs such as OpenJRE do not implement this feature causing the bean
properties to be in random order.
ResourceDescription.ResourceDescription(RestRequest,String,String) constructor.
Juno 5.1.0.18 is a minor update affecting the server component only.
RestMethod.input()RestMethod.responses()
annotations.
These replace the various description annotations added 2 days ago with a simpler design.
RestServlet.getMethodDescription(String,RestRequest) so that subclasses
can override the method description in the OPTIONS page.
RestServlet.createRequestVarResolver(RestRequest)RestServlet.resolveChild(Class) and RestServlet.replaceChild(RestServlet)
classes that allows customized resolution of servlet instances (e.g. if services are defined in OSGi).
MethodDescriptionJuno 5.1.0.17 is a major update.
BeanMap.getFiltered(String)
BeanMap.putFiltered(String,Object)
BeanMapEntry.getFiltered(String)
BeanMapEntry.putFiltered(String,Object)
BeanMapEntry.putFiltered(String,Object)
BeanPropertyMeta.getFiltered()
BeanPropertyMeta.setFiltered(Object)
BeanPropertyMeta.getTransformedClassMeta()
StringVarResolverStringVarResolverRestResource.filters() were being
interpreted as surrogate classes because they have hidden 1-arg constructors due to being inner classes.
RdfProperties.RDF_useXmlNamespaces property.
XmlParserContext.XML_preserveRootElement property.
"[ClassName].ResourceDescription" is now "[ClassName].label".
"[ClassName].MethodDescription.[methodName]" is now "[ClassName].[methodName]".
RestRequest.getQueryParameterMap()
RestRequest.getQueryParameterNames()
RestRequest.getPathInfoUndecoded()
RestRequest.getPathRemainderUndecoded()
RestRequest.getTrimmedRequestURI()
RestRequest.getTrimmedRequestURL()
RestRequest.getServletTitle()
RestRequest.getServletDescription()
RestRequest.getPathRemainder() now automatically decodes the path remainder.
Use RestRequest.getPathRemainderUndecoded() to get the unencoded path remainder.
RestRequest.getRequestParentURI() when servlet is mapped to RestRequest.getServletURI() when servlet is mapped to $R{contextPath} - Returns value from {@link org.apache.juneau.rest.RestRequest#getContextPath()}
$R{methodDescription} - Returns value from {@link org.apache.juneau.rest.RestRequest#getMethodDescription()}
$R{resourceTitle} - Returns value from RestRequest.getServletTitle()
$R{resourceDescription} - Returns value from RestRequest.getServletDescription()
$R{trimmedRequestURI} - Returns value from RestRequest.getTrimmedRequestURI()
$E{var} - Environment variables.
RestServlet.getDescription(RestRequest) and RestServlet.getLabel(RestRequest)RestServletJenaDefault now provide default HTML titles
and descriptions:
RestServletJenaDefault now provide default descriptions and back links:
and descriptions:
RestServletProperties.REST_trimTrailingUriSlashes and RestServletProperties.REST_pathInfoBlankForNull.
RestResource.label()RestMethod#responses()Attr.description()Content.description()HasParam.description()HasQParam.description()Header.description()Param.description()QParam.description()/tempDir/upload showing how to use ServletFileUpload with multipart form posts.
Juno 5.1.0.16 is a moderate update.
ClassMeta.getXmlMeta()ClassMeta.getJsonMeta()ClassMeta.getHtmlMeta()ClassMeta.getUrlEncodingMeta()ClassMeta.getRdfMeta()HtmlDocSerializerContext.HTMLDOC_cssImports property.
SerializerContext.SERIALIZER_sortCollections and
SerializerContext.SERIALIZER_sortMaps properties.
RestRequest.getServletParentURI() method.
$R{servletParentURI} variable.
Juno 5.1.0.15 is a minor update.
SerializerContext:
SerializerContext.SERIALIZER_relativeUriBase
SerializerContext.SERIALIZER_absolutePathUriBase
SERIALIZER_uriAuthority and SERIALIZER_uriContext properties.
RestServletProperties:
REST_defaultCharset
REST_servletURI
REST_relativeServletURI
RestRequest.getHeader(String,Class)
RestRequest.getHeader(String,Object,Class)
RestRequest.getHeader(String,Type,Type...)
RestRequest.getQueryParameter(String,Class)
RestRequest.getQueryParameter(String,Object,Class)
RestRequest.getQueryParameter(String,Type,Type...)
RestRequest.getQueryParameter(String,Object,Type,Type...)
RestRequest.getQueryParameters(String,Class)
RestRequest.getQueryParameters(String,Type,Type...)
RestRequest.getFormDataParameter(String,Class)
RestRequest.getFormDataParameter(String,Object,Class)
RestRequest.getFormDataParameters(String,Class)
RestRequest.getFormDataParameter(String,Type,Type...)
RestRequest.getFormDataParameters(String,Type,Type...)
RestRequest.getPathParameter(String,Class)
RestRequest.getPathParameter(String,Type,Type...)
RestRequest.getBody(Class)
RestRequest.getBody(Type,Type...)
Juno 5.1.0.14 is a moderate update.
The major addition is support for {@link org.apache.juneau.rest.remoteable Remoteable Services}, the ability to invoke server-side POJO methods through client-side proxy interfaces.
RestClient.setRemoteableServletUri(String)
RestServletJenaDefault.
RestServletProperties.REST_allowMethodParam has been enhanced to allow you to
explicitly specify which HTTP methods can be used in the &method parameter.
RestRequest.getParser()
RestRequest.getReaderParser()
Juno 5.1.0.13 is a minor update.
Link are now serialized using {@link org.apache.juneau.urlencoding.UrlEncodingSerializer}, so arbitrary POJOs can now be passed as arguments.
org.apache.juneau.transforms.Datefilter.ISO8601DTZP and org.apache.juneau.transforms.Datefilter.SimpleP.
HtmlDocSerializerContext.HTMLDOC_nowrap setting for {@link org.apache.juneau.html.HtmlDocSerializer} class.
Adds ClassCastException.
New behavior creates an empty array or Collection.
UrlEncodingSerializer.serializeUrlPart(Object)RestServletNls class.
RestCall.setRedirectMaxAttempts(int) method to prevent endless redirection loops.
RestCall#setRetryable(int,long,RetryOn) method to automatically retry on failed connection attempts.
RestCallInterceptor.onRetry(RestCall,int,HttpRequest,HttpResponse) method for listening in on retry attempts.
Juno 5.1.0.12 is a minor update.
ConfigFile.isEmpty() method.
( ) , $ = ~.
RestClientListener class.
Juno 5.1.0.11 is a moderate update.
UonParserContext.UON_whitespaceAware property for controlling whether whitespace is ignored.
UrlEncodingContext.URLENC_expandedParams property for controlling whether arrays/Collections
should be serialized/parsed as multi-part parameters.
&key=val1&key=val2).
JsonSerializerContext.JSON_escapeSolidus property for controlling whether slash characters should be escaped.
BeanPropertyMeta.add(BeanMap,Object) method for adding values to Collection and array properties.
@Param.multipart()@Query.multipart()&Content must now be specified as &content.
&Method must now be specified as &method.
&debug must now be specified as &debug=true.
&plainText must now be specified as &plainText=true.
¬race must now be specified as &noTrace=true.
RestRequest.getParameters(String,Class)RestRequest#getQueryParameters(String,Class)
Content-Type through this method was inconsistent with the behavior in WAS/Tomcat.
&noTrace=true now prevents any errors from being logged in log file.
ServletContext.getContextPath() always ends with RestServletProperties.REST_allowMethodParam is now RestServletJenaDefault.
RestCall.peekInputStream() allows you to read response bodies without interrupting execution flow.
HttpResponse object for easier debugging.
RestClient.addListener(RestClientListener) for registering request/response listeners.
RestClient.setClassLoader(ClassLoader) method.
JazzRestClient.
samples.ear and samples.war projects
have been replaced with an OSGi bundle with activated servlets in juno.samples.
Juno 5.1.0.10 is a moderate update.
BeanRuntimeExceptions weren't being thrown on subsequent calls to {@link org.apache.juneau.BeanContext#getClassMeta(Class)}.
BeanContext.getPrimitiveDefault(Class) to new {@link org.apache.juneau.ClassMeta#getPrimitiveDefault()} method for performance reasons.
BeanContext.addTransforms(Class[])RuntimeExceptions to make the serializer easier to use for debugging.
HttpServlet.getParameter(String)UrlEncodingSerializer
class from being able to parse the content. Updated code no longer inadvertantly calls this method.
RestRequest.getQueryParameter(String), RestRequest.hasQueryParameter(String), and RestRequest.hasAnyQueryParameters(String[])
methods that only look for parameters in the URL query string to prevent loading and parsing of URL-Encoded form posts.
@QParam@HasQParam&plainText parameter can now specify a false value.
RestServlet.onPreCall(RestRequest) and RestServlet#onPostCall(RestRequest,RestResponse) methods
since the properties are already accessible through RestRequest.getProperties().
RestServletJenaDefault.
RestResponseEntity to {@link org.apache.juneau.rest.client.RestRequestEntity}.
RestClient#setProperty(String,Object)
RestClient#setProperties(ObjectMap)
RestClient#addNotBeanClasses(Class[])
RestClient.addTransforms(Class[])RestClient#addImplClass(Class,Class)
RestClient.shutdown() to {@link org.apache.juneau.rest.client.RestClient#close()} to mirror change in Apache API.
CodeFormatterResource for quickly formatting Java and XML code samples in Javadocs.
UrlEncodedFormResource for showing how to work with URL-Encoded form posts.
Juno 5.1.0.9 is a major update. There weren't very many code changes, but the source has been made a part of Jazz Foundation. This required some restructuring of the project. The project on Jazz Hub will eventually be discontinued. However, the libraries on IBM Community Source will continue to be updated regularly.
org.apache.juneau - Core serializers and parsers.
org.apache.juneau.rest - REST server component.
org.apache.juneau.rest.client - REST client component.
org.apache.juneau.rest.labels.Link class moved to Link.
org.apache.juneau.rest.RestException in {@link org.apache.juneau.encoders.Encoder} class changed to IOException.
JazzRestClient to handle introduction of SSO support in v6.
&plainText debug feature was broken.
RestRequest.
Juno 5.1.0.8 is a moderate update, focused primarily on performance improvements.
estimatedSize parameter to the {@link org.apache.juneau.parser.Parser} parse methods to
optimize buffering when the input size is known beforehand.
BeanPropertyStore class that handles creation of {@link org.apache.juneau.BeanContext} objects.
This allows BeanContext objects to be considered immutable, and therefore cacheable/reusable by the framework.
While this was technically possible to cache these objects beforehand, it relied on a locking mechanism to prevent bean contexts
from being modified after being created. The new mechanism is much more straightforward.
RestClient#createHttpClient() to allow customized subclasses to construct customized HTTP clients.
DefaultRestClient class since it's now fully redundant with RestClient.
RestClient.shutdown() method for cleaning up the internal HTTP client when you're done using a REST client.
Juno 5.1.0.7 is a moderate update.
ParserContext.PARSER_debug and SerializerContext.SERIALIZER_debug.
settings for logging additional information for debugging problems.
StackOverflowErrors. When SerializerContext.getProperties() and
ParserContext.getProperties().
SerializerContext and ParserContext
since these are now available through context properties, and are typically not used.
application/xml.
Juno 5.1.0.6 is a moderate update.
beanContext parameter was replaced with a PojoSwap#getBeanContext()Img';' characters in input so that it can
parse strings of the form TumblrParserResource in the samples war file showing how to combine the REST client and server APIs into a single
resource in order to download Tumblr blogs and convert the response into any supported response content type.
Juno 5.1.0.5 is a moderate update.
UrlEncodingSerializer.serializeUrlPart(Object)RestRequest.getServletURIBuilder() for construcing servlet-based URLs more efficiently.
CoreObject.setProperties(ObjectMap)
on serializer and parser subclasses.
Content-Encoding andCharacter-Encoding headers were being set when calling {@link org.apache.juneau.rest.RestResponse#getOutputStream()}.
These should not be set if interacting with the output streams at a low level.
RestResponse.sendRedirect(...) methods due to the introduction of the {@link org.apache.juneau.rest.Redirect} class.
Juno 5.1.0.4 is a minor update.
RestServlet.getPath() method.
SerializerContext.getJavaMethod() and ParserContext.getJavaMethod()
to allow access to REST methods that invoked the serializers or parsers.
For example, can be used to access additional annotations on REST methods to perform special handing
during serialization or parsing.
BeanContext.addTransforms(Class[]).
Previously, adding multiple conflicting filters resulted in random behavior.
Now filters are overridden when multiple matching filters are applied.
HtmlDocSerializerContext properties to be set via Serializer.setProperty(String,Object).
Previously, these could only be defined through override properties (e.g. through REST class and method annotations).
Juno 5.1.0.3 is a moderate update.
BeanContext.INCLUDE_BEAN_FIELD_PROPERTIES and BeanContext.INCLUDE_BEAN_METHOD_PROPERTIES properties, since ignoring fields and methods
can be accomplished by setting the appropriate properties above to {@link org.apache.juneau.Visibility#NONE NONE}.
Also, the {@link org.apache.juneau.annotation.BeanProperty @BeanProperty} annotation can now be used on non-public fields/getters/setters to override
the default behavior defined by the VISIBILITY properties identified above. This is a convenient way of identifying protected or
private fields or methods as bean properties. Previously, you could only identify public fields/getters/setters using this annotation.
Introspector
class to determine bean properties. In the previous release, the method for determining bean properties was a mixture of Juno-based and Introspector-based.
Now it's either pure Juno-based or pure Introspector-based. The result is considerably cleaner code and consistent behavior.
@BeanProperty (hidden=true ) annotation
for ignoring bean properties. Can also be used on classes that look like beans so that they're not treated as beans.
Bean.subTypeProperty() annotation.
The previous behavior was not strictly JSON-compliant since JSON objects are supposed to consist of unordered lists of key/value pairs.
While targeted for JSON, the restriction is also lifted for all other parsers.
<div id ='data' > element to make it easier to extract the data portion of the page in Javascript in browsers.
$A{...}$P{...}RestServlet.createRequestVarResolver(RestRequest).
Juno 5.1.0.2 is a minor update.
&Accept-Language from being used as a GET parameter.
RestServletProperties.REST_allowMethodParam to be disabled by default.
Juno 5.1.0.1 is a minor update.
pathInfo on child resources.
Juno 5.1.0.0 is a major update.
HttpClient that performs
serialization and parsing using Juno parsers, but leaves all the details of the HTTP connection
to the Apache code. org.apache.juneau.rest.client.jazz package and org.apache.juneau.rest.client.jazz.JazzRestClient class
for performing REST operations against Jazz servers.ExtendedReaderParser abstract class and moved methods into
{@link org.apache.juneau.parser.ReaderParser} class.
DataFormat class from API since it was no longer necessary
due to API change above.
ParserStringReader class.String input.String input, and tests show no significant performance differences.
org.apache.juneau.parser.Parser.parse(Object,int,ClassMeta) convenience method added.
BeanContext.getClassMetaFromString(String)."long[]", and so forth.
http://host/contextRoot/foo%2Fbar).
BeanContext.setDefaultParser(ReaderParser) method added for specifying
a default parser to use in a bean context (used when converting beans to Strings using
BeanContext.convertToType(Object,Class).
Old behavior simply used the default JSON serializer in these cases.
RestRequest#getParameter(String,Class)RestRequest.getMapParameter(String,Class,Class,Class) and
RestRequest.getCollectionParameter(String,Class,Class)} methods.
Juno 5.0.0.36 is a minor update.
org.apache.juneau.urlencoding.UrlEncodingParser.parseArgs(Reader,int,ClassMeta[]).
name parameter of ResourceDescription#ResourceDescription(String,String,String).
is now automatically URL-encoded so that the name can contain special characters (e.g. BeanContext.getClassMetaFromString(String).
Now supports primitive arrays such as Juno 5.0.0.35 is a minor update.
Juno 5.0.0.34 is a moderate update.
RestServlet.createRequestVarResolver(RestRequest) for more information.
RestRequest.getVarResolver()RestRequest.getServletURI()RestRequest.getRequestParentURI()RestResponse.sendRedirect(CharSequence)
RestServlet.createConfigFactory()RestServlet.createConverters()RestServlet.createDefaultRequestHeaders()RestServlet.createDefaultResponseHeaders()RestServlet.createEncoders()RestServlet.createFilters()RestServlet.createGuards()RestServlet.createMimetypesFileTypeMap()RestServlet.createParsers()RestServlet.createProperties()RestServlet.createRequestProperties(ObjectMap,RestRequest)RestServlet.createRequestVarResolver(RestRequest)RestServlet.createSerializers()RestServlet.createUrlEncodingParser()RestServletNls to use ResourceDescription/MethodDescription
instead of RestResource/RestMethod
RestServletProperties.REST_htDocsFolder.BeanFilter.setStopClass(Class)ResultSetList.handleBlob(Blob)ResultSetList.handleClob(Clob)Juno 5.0.0.33 is a moderate update.
WriterSerializer s = new JsonSerializer();addNotBeanClassPatterns(String...) methods throughout API since these are now controlled by {@link org.apache.juneau.BeanContext#BEAN_notBeanPackages_add} / {@link org.apache.juneau.BeanContext#BEAN_notBeanPackages_remove} properties.
RestServletProperties.
RestServletProperties.REST_trimTrailingUriSlashesRestRequest.getRequestURI(boolean trimTrailingSlashes) method which is now redundant with this property.
RestServletProperties.REST_pathInfoBlankForNullRestRequest.getPathInfo(boolean returnBlankForNull) method which is now redundant with this property.
maxDepth setting is reached, and will instead simply ignore content below the specified depth.?x-response-headers={Refresh=1}
HtmlDocSerializerContext.HTML_REFRESH setting that added a Refresh meta tag to HTML documents, since this can now be controlled through X-Response-Headers.
PhotosResource now includes a default entry.
Juno 5.0.0.32 is a moderate update.
org.apache.juneau.parser.Parser.parseMap(Object,int,Class,Class,Class)org.apache.juneau.parser.Parser.parseCollection(Object,int,Class,Class)Enums through overriding toString() and fromString() on the enum class.Enum.valueOf() to convert strings back into Enums.Object when the type is erased.
setFoo(Foo f), setFoo(Bar b)), the {@link org.apache.juneau.BeanMap} API would sometime choose the wrong setter as the bean property setter. Accept GET parameters with &Accept=text/json+simple) wasn't working anymore.Accept parameter is supposed to interpret spaces as &Accept=text/json%2Bsimple.
Juno 5.0.0.31 is a moderate update.
Juno 5.0.0.30 is a minor update.
Bean.subTypes() annotation in addition to subTypes property.
Juno 5.0.0.29 is a moderate update.
Bean.subTypeProperty() subtypes. @Bean (filter=xxx) with new @Transformorg.apache.juneau.transforms.DateSwap.ISO8601DTPorg.apache.juneau.transforms.DateSwap.ISO8601DTZPJuno 5.0.0.28 is a moderate update.
OutOfMemoryError and performance issue caused by incorrect caching of class metadata.
WriterSerializer.serialize(Object,Writer) convenience method for serializing directly to a writer.Juno 5.0.0.27 is a moderate update.
OPTIONS pages through new method ResourceOptions.getChildren()Juno 5.0.0.26 is a minor update.
@RestMethod .pattern() to {@link org.apache.juneau.rest.annotation.RestMethod#path() @RestMethod.path()} for naming consistency.
Juno 5.0.0.25 is a minor update.
SqlQueryResource class in the sample war for demonstrating the ResultSetList DTO.
Servlet.init() so that getProperties() can be called during servlet initialization.
@Property .type annotation with support for using system properties as resource properties.
Juno 5.0.0.24 is a major update.
AtomFeedResource class added to sample war.
XmlFormat.CONTENT enum value.XmlContentHandler class and @Xml.contentHandler annotation.@Xml .valAttr annotation since it's now redundant with @Xml (format=CONTENT ).
Serializer.serialize(Object,Object,SerializerContext) method.
Juno 5.0.0.23 is a minor update.
@Xml annotation was not being inherited by inner classes.
Juno 5.0.0.22 is a minor update.
@Property .nls() annotation for specifying localized property values.AddressBookResource class for an example.
&Content query parameter was not always parsed correctly.Juno 5.0.0.21 is a minor update.
HtmlDocSerializerContext.HTMLDOC_navlinks annotation for addint links to HTML page views.
HtmlDocSerializerContext for clarity.
RestServlet.addDefaultProperties(ObjectMap,RestRequest) method for programatically adding properties to the property map per request.
SerializerContext.SERIALIZER_uriAuthority and SerializerContext.SERIALIZER_uriContext properties were previously available.
RestServletProperties.REST_servletPathRestServletProperties.REST_pathInfoRestServletProperties.REST_method@AttrJuno 5.0.0.20 is a major update.
XmlSerializerContext.XML_autoDetectNamespaces default changed to XmlSerializerContext.XML_namespaces annotation.RestMethod.filters() annotation for defining POJO filters at the method level.
RestMethod.serializersInherit() and RestMethod.parsersInherit() annotations for controlling how serializers and parsers (and associated filters and properties) are inherited from the class.addSerializers and addParsers annotations.
RestServletJenaDefault servlet that includes serialization/parsing support for all Jena-based serializers and parsers.
DefaultJenaProvider JAX-RS provider that includes serialization/parsing support for all Jena-based serializers and parsers.
RestServletChild class.RestServlet.createConfigFactory()RestServlet.createSerializers()RestServlet.createParsers()getBeanContext() / getSerializers() / getParsers() methods.
RestCall.setDateHeader(String,Object) method for setting ISO8601 datetime headers.
Juno 5.0.0.19 is a minor update.
RestServlet.onPreCall(RestRequest)RestServlet.onPostCall(RestRequest,RestResponse)SerializerContext.SERIALIZER_trimNullProperties.Juno 5.0.0.18 is a moderate update.
The biggest change is the introduction of the {@link org.apache.juneau.jena.RdfSerializer} class that uses Jena to generate RDF/XML, RDF/XML-ABBREV, N-Tuple, N3, and Turtle output.
This code should be considered prototype-quality, and subject to change in the future.
There are plans of adding an equivalent RdfParser class in the future, so the serializer logic may need to be tweaked to allow POJOs to be reconstituted correctly in the parser.
The RdfXmlSerializer class should be considered deprecated for now.
However, I'm keeping it around, since it's considerably faster and uses far less memory than the Jena-based serializer since it serializes directly from POJOs to RDF/XML.
It may or may not be removed in the future depending on demand.
Juno 5.0.0.17 is a minor update.
IOutputStreamSerializer.serialize() and IInputStreamParser.parse().
Juno 5.0.0.16 is a minor update.
@Properties REST method parameter annotation that can be used to get the runtime properties map through a parameter instead of through {@link org.apache.juneau.rest.RestResponse}.
Juno 5.0.0.15 is a moderate update.
@Produces annotation in place of ISerializer.getMediaTypes() for specifying what media types a serializer produces.@Consumes annotation in place of IParser.getMediaTypes() for specifying what media types a parser consumes.Juno 5.0.0.14 is a major update.
The biggest change is that the RestSerializer, RestParser, RestSerializerGroup, and RestParserGroup classes have been eliminated entirely.
Instead, the existing {@link org.apache.juneau.serializer.Serializer}, {@link org.apache.juneau.parser.Parser}, {@link org.apache.juneau.serializer.SerializerGroup}, and {@link org.apache.juneau.parser.ParserGroup} classes of the core API have been augmented to replace them.
Adoptions will be required if you have previously used these classes.
org.apache.juneau.serializer package.
Accept-Content headers.org.apache.juneau.parser package.
org.apache.juneau.transform package.
ObjectFilter).org.apache.juneau.encoders package.
Accept-Encoding header values.org.apache.juneau.plaintext package.
org.apache.juneau.jso package.
application/x-java-serialized-object content.org.apache.juneau.soap package.
text/xml+soap content.JsonMap and JsonList changed to {@link org.apache.juneau.ObjectMap} and {@link org.apache.juneau.ObjectList} to better reflect that they're not limited to just JSON support.
PojoSwap to {@link org.apache.juneau.utils.PojoQuery} to not confuse it with the new Filter API.
org.apache.juneau.rest.serializers and org.apache.juneau.rest.parsers packages.
RestCmdLine (since it's essentially redundant with CURL).
Juno 5.0.0.13 is a minor update.
SerializerContext.SERIALIZER_uriContext and SerializerContext.SERIALIZER_uriAuthority serializer properties for specifying values for relative URIs.
java.net.URI or java.net.URL.
BeanProperty#uri annotation to BeanProperty#beanUri to make it clear that this property represents the URI of the bean itself instead of an arbitrary property containing a URI.
BeanProperty#id annotation.
SerializerContext.SERIALIZER_uriContext property set by default to web app context root.SerializerContext.SERIALIZER_uriAuthority property set by default to the request scheme+hostname+port.Accept-Charset header in Chrome that prevented HTML output from rendering correctly in that browser.Accept-Charset handling should now be fully W3C compliant.
Juno 5.0.0.12 is a minor update.
BeanProperty.method annotation, since it's now unnecessary.
PlainTextRestSerializer class for serializing Readers and InputStreams can now be passed in as @Content?debug parameter.Juno 5.0.0.11 is a moderate update.
UrlEncodingRestSerializer and UrlEncodingRestParser classes.Accept and Content-Type RestServlet.renderError(HttpServletRequest,HttpServletResponse,RestException) method to allow customized handling of response errors.
Juno 5.0.0.10 is a minor update.
RestServletProperties class that defines all the class-level properties that can be set on the servlet.RestServlet.setProperty(String,Object) method.RestServletProperties.REST_useStackTraceHashes property to prevent the same stack trace from being logged multiple times.RestServletProperties.REST_renderResponseStackTraces property for preventing stack traces in responses for security reasons.RestServlet.onError(HttpServletRequest,HttpServletResponse,RestException,boolean) and RestServlet.onSuccess(RestRequest,RestResponse,long) methods for plugging in your own logging and peformance monitoring.RestServlet.getInitParams() method, since it's now redundant with {@link org.apache.juneau.rest.RestServlet#getProperties()}.Juno 5.0.0.9 is a moderate update.
ObjectMaps directly to beans.OPTIONS pages.Readers and InputStreams can be specified on @Content@HasParamAccept headers to serializers.Juno 5.0.0.8 is a minor update.
Juno 5.0.0.7 is a major update.
@Xml.namespaces annotation.@Xml.nsUri annotation.@Xml.valAttr annotation.SerializerContextParserContext@BeanProperty.hidden() so that they don't get serialized.
ClassType {@link org.apache.juneau.ClassMeta} API.@Bean.filter@BeanProperty.filterBeanContext.addTransforms(Class[]).
@BeanProperty.beanUri@BeanProperty.idrdf:resource attributes.
RestResponse.setProperty(String,Object) method.@RestResource.filters() - Associate post-formatting filters on a resource level.@RestMethod.filters() - Associate post-formatting filters on a method level.@Attr@Param@ContentJuno 5.0.0.6 is a minor update that fixes a small bug in 5.0.0.5.
Juno 5.0.0.5 is a major update.
@RestChild annotation for identifying child resources.traversable and filterable attributes added to {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod} annotation.PojoResource and FilteredRestResource classes.
resourceUri attributed added to RdfXmlSerializer.Juno 5.0.0.4 is a minor update.
BeanContext.convertToType(Object,Class) to be able to convert Strings to classes with
fromString(String)/valueOf(String) static methods or T(String) constructors.
Juno 5.0.0.3 is a minor update.
Juno 5.0.0.2 is a minor update.
org.apache.juneau.json).
Enum keys, and parsing Enum strings.ObjectList.toXArray() methods with a new elements(Class<T> type) method that's more efficient and avoids creating an unnecessary array.
Juno 5.0.0.1 is a moderate update.
Version 5.0 marks a major release milestone for the Juno/JJSON library. It is now available for download from iRAM under the name "Juno (previously JJSON)". The Juno Starters Guide has been updated to reflect new functionality in this release.
TransformBeanContext class (and thus the Serializer and Parser classes too) through the BeanContext.addTransforms(Class[]) method.TransformCast and BeanFilter APIs which were considerably more complicated and puts them under a common API.
_class attributes in parsable output.BeanMap API.BeanMap API code.
Reflection is used to determine the class types of property values on beans.
This information is now cached and persisted so that the reflection API calls to determine class types are only performed the first time a bean type is encountered.
RestServlets.Accept-Encoding: gzip) and charsets (e.g Accept-Charset: SJIS) on both incoming and outgoing data.
It's all transparent from a developers perspective.
The developer simply working with POJOs, and all details about content types, encoding, charsets, and so forth are handled by the framework.
OPTIONS pages for resources.
RestServlet.
Enum.
MyBeanList extends LinkedList<MyBean>).