Skip to main content

Release 8.2.0

Date: Oct 14, 2020

Juneau 8.2.0 is a major release.

The most significant change is the addition of an entirely new RestClient API build from scratch with near 100% unit test coverage.

The new API is located in the org.apache.juneau.rest.client2 package and will replace the old API in 9.0.

juneau-marshall

  • @Bean and @BeanIgnore annotations can alternately occur in parent class hierarchy. The first one found dictates whether a class is ignored as a bean or not.

  • Applying the @Bean annotation on a class will now force non-public classes to be interpreted as beans. For example, applying @Bean to a private class will force it to be treated as a bean. Also, if a public bean constructor cannot be found, the default constructor will be used regardless of it's visibility if the @Bean annotation is on the class.

  • The @Beanc annotation can now be recognized and used on non-public constructors.

  • Annotations are now aggregated across the entire class hierarchy instead of simply being overridden.

    The following is an example.

    // Parent class with properties a,b,c
    @Bean(bpi="a,b,c")
    public class MyClass {
    public int a, b, c, d;
    }

    // New behavior: Child class with properties a,c because @Beans are aggregated.
    // Old behavior: Child class with properties a,c,d because @Bean is overridden.
    @Bean(bpx="b")
    public class MyChildClass extends MyClass {
    public int a, b, c, d;
    }
  • Include/exclude/read-only/write-only properties defined on the bean context now override those defined on annotations of the class itself. For example, the following methods override the @Bean annotations on classes:

    BeanContext.Builder bpi(Class,String) bpi(String,String) bpx(Class,String) bpx(String,String) bpro(Class,String) bpro(String,String) bpwo(Class,String) bpwo(String,String)
  • Config annotations now override class-level annotations. For example, only the 'a' and 'b' properties get serialized on the bean below:

    // Parent class with properties a,b,c
    @Bean(bpi="a,b,c")
    public class MyClass {
    public int a, b, c, d;
    }

    @RestMethod
    @BeanConfig(beanApply={@Bean(on="MyClass",bpi="a,b")}
    public MyClass getMyClass() {...}
  • The following concrete annotation implementation classes are now provided that can be used with the BeanContext.Builder.annotations(Annotation...) method:

    BeanAnnotation implements @BeanBeancAnnotation implements @BeancBeanIgnoreAnnotation implements @BeanIgnoreBeanpAnnotation implements @BeanpExampleAnnotation implements @ExampleNamePropertyAnnotation implements @NamePropertyParentPropertyAnnotation implements @ParentPropertySwapAnnotation implements @SwapUriAnnotation implements @URICsvAnnotation implements @CsvHtmlAnnotation implements @Html JsoAnnotation implements @JsoJsonAnnotation implements @Json SchemaAnnotation implements @SchemaMsgPackAnnotation implements @MsgPackOpenApiAnnotation implements @OpenApiPlainTextAnnotation implements @PlainTextSoapXmlAnnotation implements @SoapXmlUonAnnotation implements @UonUrlEncodingAnnotation implements @UrlEncodingXmlAnnotation implements @Xml

    Example:

    @Bean(bpi="street,city") // Will be overridden
    public class AddressBean {...}

    Bean ba = new BeanAnnotation("AddressBean").bpi("street,city,state");
    WriterSerializer ws = JsonSerializer.create().annotations(ba).build();
    String json = ws.toString(addressBean); // Will print street,city,state

    Plus similar annotation classes for other serializer/parser annotations.

  • The BeanContext.Builder.annotations(Annotation...) method can be used to apply annotations to classes during runtime.

  • Bean maps now have the concept of "hidden" properties (properties that aren't serialized but otherwise accessible). For example, the @Html.link can now reference hidden properties:

    @Bean(bpi="a") // Will be overridden
    public class MyBean {

    @Html(link="servlet:/{b}")
    public String a;

    public String b; // Not serialized but referenced in link on a.

    }

    The general rule for the BeanMap class is that get(), put(), and containsKey() will work against hidden properties but keySet() and entrySet() will skip them.

  • Several bug fixes in the HtmlSerializer and HtmlParser classes around the handling of collections and arrays of beans with @Bean(typeName) annotations.

  • New swaps auto-added to all serializers/parsers:

    MatchResultSwap StackTraceElementSwap
  • @Html.noTableHeaders now can be applied to collections of beans.

  • New @HtmlDocConfig.asideFloat setting so that you can position the contents of the aside section on the page.

  • Various minor fixes surrounding HTML serialization:

    • Collections of beans that were supposed to be serialized as tables were being serialized as lists.
    • Collections of beans with @Bean(bpi) were not being serialized in the correct column order.
  • Fixed a bug where a copy constructor can erroneously be recognized as a builder constructor if the class also has a static create method. Net effect was that the copy constructor would needlessly be called during parsing.

  • New org.apache.juneau.collections package containing various convenience fluent-style collection classes:

    AList ASet ASortedSet AMap ASortedMap OMap OList
  • ObjectMap is being deprecated and replaced with OMap.

  • ObjectList is being deprecated and replaced with OList.

  • All classes in the org.apache.juneau.http.response and exception now have header(String,Object) methods for adding response headers.

    // Method that performs a BASIC Auth handshake.
    @RestMethod
    public Ok checkBasicAuth(@Header("Authorization") String auth) throws Unauthorized {
    if (auth == null)
    throw new Unauthorized().header("WWW-Authenticate", "BASIC realm=\"foo\"");
    return Ok.OK;
    }
  • New annotations for multi-part support:

    Header.multi() Query.multi() FormData.multi()
  • BeanTraverseContext.BEANTRAVERSE_ignoreRecursions setting no longer requires BeanTraverseContext.BEANTRAVERSE_detectRecursions to be enabled.

  • Fixed bug in JSON/UON/URL-Encoding serializers where indentation was not correct of first line when BeanTraverseContext.BEANTRAVERSE_initialDepth used.

  • Fixed bug in JSON/UON/URL-Encoding serializers where properties past the max depth were being serialized as null instead of being treated as null and not being serialized at all.

  • Fixed bug in HTML serializer where tables of maps were not sorted if SERIALIZER_sortMaps was specified.

  • SERIALIZER_trimNullProperties has been replaced with Serializer.SERIALIZER_keepNullProperties SERIALIZER_keepNullProperties.

  • Improvements to OpenAPI serializer and parser:

    • Collection format can now be specified on OBJECTs to allow key/value pairs to be delimited with the same support as ARRAYs.
    • New OpenApiCommon.OAPI_format OAPI_format and OpenApiCommon.OAPI_collectionFormat OAPI_collectionFormat properties.
  • Convenience methods added to HttpPartSchema and related classes to simplify schema definitions:

    import static org.apache.juneau.httppart.HttpPartSchema.*;

    // Old
    HttpPartSchema s = schema("object")
    .property("f01", schema("array").collectionFormat("pipes").items(schema("string")))
    .property("f02", schema("array").collectionFormat("pipes").items(schema("string", "byte")))
    .property("f03", schema("array").collectionFormat("pipes").items(schema("string", "date-time")))
    .build();

    // New
    HttpPartSchema s = tObject()
    .p("f01", tArray(tString()))
    .p("f02", tArray(tByte()))
    .p("f03", tArray(tDateTime()))
    .build();
  • Fixes where the bean method/constructor visibility wasn't being used when finding swap methods and constructors.

  • HTML-Schema support is being deprecated due to low-use and difficulty in maintaining. It will be removed in 9.0.

  • JuneauLogger class is being deprecated. Improvements in logging in Java 8 make it obsolete.

  • Bean filters can now be specified programmatically through a builder API.

    // Create a JSON serializer that only includes specified fields on a specific class.
    WriterSerializer s = JsonSerializer
    .create()
    .beanFilters(BeanFilter.create(MyBean.class).bpi("foo,bar,baz").build())
    .build();
  • BeanContext.REST_pojoSwaps replaced with BeanContext.BEAN_swaps (and builder methods as well).

  • New RootBeanPropertyMeta class added for when you need BeanPropertyMeta from somewhere and all you have is a Class.

  • New Bean Property Interceptor API for intercepting calls to bean getters/setters.

    BeanInterceptor@Bean.interceptorBeanContext.Builder.beanInterceptor(Class,Class)
  • Fluent setters that follow the withX convention are now automatically detected by all parsers.

    // A bean with a fluent setter.
    public class MyBean {
    public MyBean withFoo(String foo) {
    this.foo = foo;
    return this;
    }
    }

    Note you could previously use the @BeanProperty annotation to identify these setters.

juneau-rest-server

  • New RestContext.REST_context REST_context/Rest.context() @Rest(context) setting to allow you to extend the RestContext class.

  • @Rest-annotated classes can now implement the following interfaces directly instead of having to define secondary classes and hook them up through annotations:

    RestCallHandler - Normally defined through @Rest.callHandler() RestInfoProvider - Normally defined through @Rest.infoProvider() RestCallLogger - Normally defined through @Rest.callLogger() ClasspathResourceFinder - Normally defined through @Rest.classpathResourceFinder()

    The methods added for RestInfoProvider are:

    RestServlet getSwagger(RestRequest) getSiteName(RestRequest) getTitle(RestRequest) getDescription(RestRequest) getMethodSummary(Method,RestRequest) getMethodDescription(Method,RestRequest) BasicRest getSwagger(RestRequest) getSiteName(RestRequest) getTitle(RestRequest) getDescription(RestRequest) getMethodSummary(Method,RestRequest) getMethodDescription(Method,RestRequest)

    The methods added for RestCallLogger are:

    RestServlet RestServlet.log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse) log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse) BasicRest BasicRest.log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse) log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse)

    The methods added for ClasspathResourceFinder are:

    RestServlet RestServlet.findResource(Class,String,Locale) findResource(Class,String,Locale) BasicRest BasicRest.findResource(Class,String,Locale) findResource(Class,String,Locale)

    The methods added for RestResourceResolver are:

    RestServlet oajr.RestServlet.resolve(Object,Class,RestContext.Builder,Object...) resolve(Object,Class,RestContext.Builder,Object...) BasicRest
  • Added the following convenience hook methods on the RestServlet and BasicRest classes:

    RestServlet oajr.RestServlet.onInit(RestContext.Builder) onInit(RestContext.Builder) RestServlet.onPostInit(RestContext) onPostInit(RestContext) RestServlet.onPostInitChildFirst(RestContext) onPostInitChildFirst(RestContext) RestServlet.onDestroy(RestContext) onDestroy(RestContext) RestServlet.onStartCall(HttpServletRequest,HttpServletResponse) onStartCall(HttpServletRequest,HttpServletResponse) RestServlet.onPreCall(RestRequest,RestResponse) onPreCall(RestRequest,RestResponse) RestServlet.onPostCall(RestRequest,RestResponse) onPostCall(RestRequest,RestResponse) RestServlet.onEndCall(HttpServletRequest,HttpServletResponse) onEndCall(HttpServletRequest,HttpServletResponse) BasicRest oajr.BasicRest.onInit(RestContext.Builder) onInit(RestContext.Builder) BasicRest.onPostInit(RestContext) onPostInit(RestContext) BasicRest.onPostInitChildFirst(RestContext) onPostInitChildFirst(RestContext) BasicRest.onDestroy(RestContext) onDestroy(RestContext) BasicRest.onStartCall(HttpServletRequest,HttpServletResponse) onStartCall(HttpServletRequest,HttpServletResponse) BasicRest.onPreCall(RestRequest,RestResponse) onPreCall(RestRequest,RestResponse) BasicRest.onPostCall(RestRequest,RestResponse) onPostCall(RestRequest,RestResponse) BasicRest.onEndCall(HttpServletRequest,HttpServletResponse) onEndCall(HttpServletRequest,HttpServletResponse)
  • New @Rest.debugOn annotation for turning on debug mode using class/method identifiers:

    // Turn on debug per-request on the class and always on the doX() method.
    @Rest(
    debugOn="MyResource=per-request,Mysource.doX=true" // Typically defined via system or env property.
    )
    public class MyResource {

    @RestMethod
    public void String doX() {
    ...
    }
    }
  • BasicRestConfig has been broken up into BasicRestConfig and BasicRestMethods so that you're not forced to implement methods such as getOptions() and getStats() if you're implementing the interface to configure your REST class.

  • Any of the following classes can now be instantiated with public static create() methods:

    RestCallHandler RestCallLogger RestInfoProvider ClasspathResourceFinder RestResourceResolver RestGuard ResponseHandler
  • New Path.required() @Path(required) annotation support. A path can be marked as not-required when the path variable is resolved by a parent resource like so:

    @Rest(path="/parent/{p1}",children=Child.class)
    public class Parent {
    ...
    }

    @Rest(path="/child")
    public class Child {

    @RestMethod(path="/")
    public String doGet(@Path(name="p1",required=false) String p1) {
    // p1 will be null when accessed via "/child"
    // p1 will be non-null when accessed via "/parent/p1/child".
    }
    ...
    }

    This allows the child resource to be mapped to multiple parents that may resolve various different path variables.

  • New RestMethod.paths() @RestMethod(paths) annotation that allows you to map multiple paths to the same Java method.

    Example:

    @RestMethod(
    name=GET,
    paths={"/","/{foo}"}
    )
    public String doGet(@Path(name="foo",required=false) String foo) {...}
  • The RestMethod @RestMethod annotation is now implied on all unannotated methods of a @Rest @Rest-annotated interface.

    @Rest
    public interface MyRest {
    String getFoo(); // @RestMethod(name=GET,path="/foo") is implied.
    }
  • Improved RestContext.REST_messages REST_messages support (mostly bug fixes).

juneau-rest-server-springboot

  • JuneauRestInitializer now provides a no-arg constructor so that it can be used in the @ConfigurationContext(initializers=JuneauRestInitializer.class) when unit testing using @SpringBootTest.

  • New ResourceDescription.ResourceDescription(String,String,String) constructor and ResourceDescriptions.append(String,String,String) method.

  • New Hyperlink class.

juneau-rest-client

  • Completely revamped RestClient API.

    • All APIs now extend from HttpClient interfaces.
    • Better integration with HttpClient.
    • New fluent-style methods with many new convenience methods.
    • Updated juneau-rest-client.
  • @RemoteMethod-annotated methods can now return Future and CompletableFuture for concurrent processing of requests.

    Example:

    @Remote
    public interface MyInterface {
    public Future<String> doGet();
    }

    MyInterface i = client.getRemote(MyInterface.class, "http://localhost:12345/myInterface");
    Future<String> f = i.doGet();
    // Do other stuff.
    String result = f.get();
  • Additions to @Remote annotation:

    • @Remote.version - Adds a client version header to all requests.
    • @Remote.headers - Adds a set of headers to all requests.
    • headerSupplier - Adds a dynamic supplier of headers to all requests.

juneau-rest-mock

  • The MockRest and MockRemote classes have been remove entirely and all existing functions have been moved into the improved MockRestClient class. All REST test mocking can be done through this single class.