Blog

New and Improved RestClient

It's been a while since I've made any updates and wanted to let the community know what I've been working on in 8.1.4.  Currently in the snapshot release is an entirely new RestClient API!

The old RestClient API sort of grew organically as a 2nd-class citizen to the server-side API.  As such, it wasn't well tested and didn't fully take advantage of the existing Apache HttpClient APIs.  I was often finding bugs and functionality often duplicated what already existed in HttpClient.

The new API includes all the same functionality of the old, but with the following advantages:

  • Extends directly from the Apache HttpComponents and Apache HttpClient APIs instead of merely using them.
  • APIs are written for easy extension.
  • Adds fluent-style coding to HTTP calls including easy-to-use fluent assertions.
  • Adds support for multiple simultaneous languages (including universal language support).
  • Is nearly 100% unit tested.

Here's an example of a fluent call from client creation to HTTP request and handling:

Constructing clients for supporting multiple languages is now as easy as:

Parsers and serializers can be easily configured via convenience builder methods like so:

HTTP parts (headers, query/form-data parameters) now support dynamically changing values through Suppliers:

Full support for OpenAPI part schema serialization is provided on all HTTP parts using a simple syntax on requests:

...and responses:

Response bodies can now be processed multiple times:

This combined with a new powerful assertions API allows you to easily perform complex fluent calls:

For example, it's even possible to do complex assertions that involve parsing and serialization:

The new API still supports Remote proxy interfaces (but with some added new features):

Logging and debugging has been simplified:

...which produces the following console output:

The RestClient class extends directly from Apache HttpClient and so inherits the same functionality.  Fluent setters have been provided on the builder class to make using these existing features easy:

The RestClient class (and other classes) can be extended as well to provide any sort of customization needed:

Additionally, the two separate MockRest (for server side testing) and MockRemote (for remote interface testing) have been replaced with a single MockRestClient class that extends directly from RestClient which allows you to take full advantage of the new assertions APIs as part of your unit tests:

The MockRestClient class can also wrap instantiated beans which is particularly useful if you're using Spring Boot for deployment of your REST servlets:

The following shows how to test remote interfaces using the new unified API:

See the updated Javadocs for more information:




Added in 8.0.1 is a simplified approach for customizing serializers and parsers in REST interfaces using annotations.

The following example shows the old approach of using a generic @RestResource(properties) annotations, and the new approach of using specialized annotations:

Annotations are provided for all serializers and parsers:

Features:

  • Annotations can be applied to classes and methods.
  • Annotations can also be applied to parent classes and methods and are combinable and overridable, applied in parent-to-child order.
  • All annotations support SVL variables (e.g. "$C{myConfigVar}").
  • Default values for all annotations can be set as system properties.
  • Default values for all annotations can also be set in the main configuration file or application.properties file.
  • Annotations can be applied to serializers and parsers directly using new applyAnnotations(Class) and applyAnnotations(Method) defined on the serializer and parser builder and group builder classes.


Support for import statements in configuration files has just been added:

This is still a work-in-progress.  The most difficult aspect was correctly handling listener events for changes made in imported configurations, including changes due to dynamically added or removed import statements.  I'm still not certain I've got all the concurrency aspects worked out correctly yet and there's still more testing to be done.  

More information can be found in the docs:

http://juneau.apache.org/site/apidocs-8.0.1/overview-summary.html#juneau-config.Imports

Source javadoc tag

I've added a Javadoc taglet for quickly linking to source code on GitHub:  "{@source}" or "{@source label}"

It can be added to class-level javadocs like so:

Based on the file location in the source tree, it will calculate the GitHub link:

I think this will be particularly useful if you want to provide source links in example code javadocs.

Spring Boot Integration

Hi all,

I've made some modifications to the work that Marcelo contributed for the Spring Boot integration.  I still consider this in flux though and suggestions are welcome.

Here's the updated project layout:

Here's what it looks like to start up a Spring app with Juneau Examples REST resources:

Another option is to add the @JuneauRest annotation on your configuration bean method:

The root resource will be initialized with the SpringRestResourceResolver which allows for child resources to be defined as injectable Spring beans.

The app can be launched from Eclipse using the juneau-examples-rest-springboot.launch file.  It will bring up the REST examples on port 5000.


In 8.0, I'll be adding the concept of a default system configuration.  One of the annoyances of setting up the Juneau REST resources to work with Spring Boot is that you have to manually set the "juneau.configFile" system property so that our servlets know where to look for configuration.  With a default system configuration, this requirement goes away.

Being added is a Config.getSystemDefault() static method that returns the system default configuration.

If "juneau.configFile" is set, it will continue to look for a configuration file with that name in either the home directory or classpath.  If not, then it will look for the following:

  • In the home directory:
    • <jar-name>.cfg
    • Any files that end with .cfg in the JVM home directory.
  • In the classpath (as part of the jar):
    • <jar-name>.cfg
    • juneau.cfg
    • default.cfg

Note that by placing it in your jar, you gain having everything packaged as a single uber-jar, but lose persistence (since it's not writeable).

Also being added:

  • ConfigClasspathStore - A ConfigStore for reading configs from the context classpath.  Note that this is a read-only store.
  • ConfigStore.exists(name) - New method on interface for checking for the existence of a configuration.

Your REST servlets can refer to the system default configuration with the special keyword "SYSTEM_DEFAULT".

For example:

// Always use system default
@RestResource(config="SYSTEM_DEFAULT")
// Use system property if set or the system default if not.
@RestResource(config="$S{juneau.configFile,SYSTEM_DEFAULT}")


There is a corresponding Config.setSystemDefault(Config) for overriding the system default configuration.   

The Pet Store application has been upgraded to use JPA for persistence.  It's now possible to marshall JPA beans using Juneau serializers and parsers.

For example, the Pet bean below combines JPA and Juneau annotations:

One noted enhancements is that you can now define bean-property annotations (e.g. @BeanProperty, @Html, @Schema, ...) on private bean fields just like JPA annotations.

Also, the @Schema annotation has been enhanced to provide more information for bean properties in the auto-generated Swagger:

New in Juneau 7.2.1: 

Method and argument annotations such as @RestMethod, @Path, etc..., are now inheritable from parent classes and interfaces.  

This means you can now define the same Java interface for both your server and client side APIs.  

For example, the Pet Store application now defines a top-level PetStore interface:

The PetStoreResource class implements this interface using the normal RestServlet API.

In this particular case, the @RestMethod annotations are specified in the implementation class, although they could be located in the interface as well.

The PetStore interface can be used as the remote proxy interface like so:

The advantages to this design approach are:

  • It's much easier to keep server and client side APIs in sync since they're working off the same interface.
  • The annotations can be moved into your interface where they won't interfere with the readability of your servlet code.


There's a behavior change being made to the default value on @RestMethod(path).  If not specified, the value is now inferred from the Java method name.

This can result in cleaner-looking code.

The previous behavior was to default to the value "/*".

More information can be found here:

http://juneau.apache.org/site/apidocs_preview/overview-summary.html#juneau-rest-server.RestMethod

Documentation reorg

FYI....I've broken up the overview.html file into individual topics:  

The overview document was just getting too unwieldy (the Eclipse HTML editor struggled with it).  The smaller parts should be easier to work with, and reorganizing pages should now be much easier.  Also, broken links should now be fewer in number.

The DocGenerator class will take all the individual pages and combine them into the same overview.html page as before.

The generator is not currently part of the build process so it has to be executed manually to generate the overview.   

In 7.2, we're introducing auto-validation of Swagger annotations.  What this means is that the various Swagger annotations are not just used for populating the Swagger JSON / UI, but are actively used in serializing/parsing/validating the HTTP parts.

For example:

This example shows a parameter of type PetStatus[] (which happens to be enums, but could also be POJOs as well).  The type and collectionFormat attributes tell the framework to parse the incoming value as a comma-delimited list.  The _enum shows the possible valid values.  A BadRequest is thrown if any values don't match.  

Part of this change includes combining the client-side and server-side annotations into a single set of annotations (no more confusing org.apache.juneau.remoteable.Query with org.apache.juneau.rest.annotation.Query).

Features include:

  • Support for all of Swagger 2.0.
  • Auto-validation for:
    • Numeric values (minimummaximumexclusiveMinimumexclusiveMaximummultipleOf).
    • String values (minLengthmaxLengthenum).
    • Collection values (itemsminItemsmaxItemsuniqueItems).
    • Object values (propertiesmaxPropertiesminPropertiesadditionalProperties).
    • Existence of values (requiredallowEmptyValue).
  • Support for both client-side and server-side annotations.
  • Works on the Body annotation as well.  If the media-type of the body does not match an existing serializer/parser, then the Swagger rules are used for marshalling.
  • UON notation is still supported, so you can still represent arbitrary POJOs as any of the HTTP parts.  However, you have to explicitly specify format="uon".

Juneau 7.2.0 is close to release but there is still a considerable amount of documentation to be written.  The Javadocs on the classes themselves should be mostly complete, but much remains to be written in the overview document.

I've uploaded a preview of the Javadocs so far here:
http://juneau.apache.org/site/apidocs_preview/index.html

To help identify new and in-progress documentation, I've added temporary color coding to new and modified sections...

If there is any documentation lacking, now would be a good time to point it out (smile)

In 7.2.0, I'm adding support for POJO REST requests that don't include Accept and Media-Type headers.

Previously, if your requests did not contain Accept or Content-Type headers, you had to use Readers and Writers to work with the HTTP request and response bodies.  Otherwise you would get Not Acceptable (406) and Unsupported Media Type (415) response codes.  

This behavior is now being relaxed.  If your request does not contain media-type headers, then you can still used POJOs for requests and responses.

For example, this is a snippet from the Javadoc on the Body annotation describing the types of objects you can use in REST Java methods to represent the body of the request:

JUnit Test Results

FYI....JUnit testcase results have been added to the Jenkins builds...