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 @HtmlJsoAnnotation@JsoJsonAnnotation implements @JsonSchemaAnnotation@SchemaMsgPackAnnotation implements @MsgPackOpenApiAnnotation implements @OpenApiPlainTextAnnotation implements @PlainTextSoapXmlAnnotation implements @SoapXmlUonAnnotation implements @UonUrlEncodingAnnotation implements @UrlEncodingXmlAnnotation implements @XmlExample:
@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,statePlus 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()
, andcontainsKey()
will work against hidden properties butkeySet()
andentrySet()
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:
MatchResultSwapStackTraceElementSwap -
@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:
AListASetASortedSetAMapASortedMapOMapOList -
ObjectMapis being deprecated and replaced withOMap. -
ObjectListis being deprecated and replaced withOList. -
All classes in the org.apache.juneau.http.response and
exceptionnow haveheader(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_ignoreRecursionssetting no longer requiresBeanTraverseContext.BEANTRAVERSE_detectRecursionsto be enabled. -
Fixed bug in JSON/UON/URL-Encoding serializers where indentation was not correct of first line when
BeanTraverseContext.BEANTRAVERSE_initialDepthused. -
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 withSerializer.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_formatandOpenApiCommon.OAPI_collectionFormat OAPI_collectionFormatproperties.
-
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 withBeanContext.BEAN_swaps(and builder methods as well). -
New
RootBeanPropertyMetaclass added for when you needBeanPropertyMeta
from somewhere and all you have is a Class. -
New Bean Property Interceptor API for intercepting calls to bean getters/setters.
BeanInterceptor@Bean.interceptor BeanContext.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@Rest.callHandler()RestInfoProvider@Rest.infoProvider()RestCallLogger@Rest.callLogger()ClasspathResourceFinder@Rest.classpathResourceFinder()The methods added for
RestInfoProviderare:RestServletgetSwagger(RestRequest)getSiteName(RestRequest)getTitle(RestRequest)getDescription(RestRequest)getMethodSummary(Method,RestRequest)getMethodDescription(Method,RestRequest)BasicRestgetSwagger(RestRequest)getSiteName(RestRequest)getTitle(RestRequest)getDescription(RestRequest)getMethodSummary(Method,RestRequest)getMethodDescription(Method,RestRequest)The methods added for
RestCallLoggerare:RestServletRestServlet.log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse) log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse)BasicRestBasicRest.log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse) log(RestCallLoggerConfig,HttpServletRequest,HttpServletResponse)The methods added for
ClasspathResourceFinderare:RestServletRestServlet.findResource(Class,String,Locale) findResource(Class,String,Locale)BasicRestBasicRest.findResource(Class,String,Locale) findResource(Class,String,Locale)The methods added for
RestResourceResolverare:RestServletoajr.RestServlet.resolve(Object,Class,RestContext.Builder,Object...) resolve(Object,Class,RestContext.Builder,Object...)BasicRest -
Added the following convenience hook methods on the
RestServletandBasicRestclasses:RestServletoajr.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)BasicRestoajr.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() {
...
}
} -
BasicRestConfighas been broken up intoBasicRestConfigandBasicRestMethodsso that you're not forced to implement methods such asgetOptions()
andgetStats()
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:RestCallHandlerRestCallLoggerRestInfoProviderClasspathResourceFinderRestResourceResolverRestGuardResponseHandler -
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 @RestMethodannotation 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_messagessupport (mostly bug fixes).
juneau-rest-server-springboot
-
JuneauRestInitializernow 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 andResourceDescriptions.append(String,String,String)method. -
New
Hyperlinkclass.
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
andMockRemote
classes have been remove entirely and all existing functions have been moved into the improvedMockRestClientclass. All REST test mocking can be done through this single class.