RESTX 0.35
Today we are very happy to announce release 0.35 of RESTX, the lightweight, modular, feature rich, blazing fast and open source Java REST framework.
New and Noteworthy
Better cold classes management (PR #175)
Several new things have been added about cold classes :
- It permits to add inherited classes of
coldcomponents (components being loaded in the main factory, such asAutoStartableones) in cold classes list. - It adds a way to declare
cold classesusing a property:restx.cold.classes. The property value is a list of fqcn separated by,. - It adds a way to declare
cold classesusing a resource file:META-INF/cold-classes.list. Resources will be loaded from the classloader, and every classes listed will be added to the cold classes list. The file must contains a list of fqcn, one per line. - It provides a way to fulfil the resource file using a new annotation:
@Cold. So every classes annotated with@Coldwill be added to the resource file.
[breaking] Security roles are now interpolated (PR #223)
Security roles used in @RolesAllowed annotation can now be interpolated with query parameters and path parameters.
For example :
@GET("/security/{companyId}/{subCompanyId}")
@RolesAllowed("EDIT_COMPANY_{companyId}_{subCompanyId}")
public String editSubCompany(String companyId, String subCompanyId){
// ....
}
Also, you can add wildcarded roles to your principal, such as EDIT_COMPANY_1234_* : the special * in role name
will match any role parameter value meaning users having role EDIT_COMPANY_1234_* will be able to call any
/security/1234/* url without hitting any 403 FORBIDDEN response.
This feature may be particularly of interest if you are able to generate the whole security roles attached to a user
when he authenticates.
An example usage of such role definition & usage may be found in the samplest’s
CompanyAndSubCompanyRoles
enum, SecuredResource
and principals declarations.
Unified and improved Query, Path and Body params handling (PR #177)
Query & Path parameters are now both handled through MainStringConverter, itself based on Jackson
registered deserializers.
It means you can now use the same deserializer for every types of parameters (initially, for instance, you were not able
to use DateTime in PATH parameters .. now you can).
Also, Aggregated types are now handled in such parameters, like List<BaseType>, Iterable<BaseType> or BaseType[]
(as soon as SimpleType is what we call a BaseType, that is to say a type which would represent a “single” value :
an Integer, a String, a Date etc. which could be handled by MainStringConverter component)
Parameterized types handling (based on generics) in every types of parameters (path, query, body) have been
greatly improved as well, supporting any level of generics.
For instance something like
Map<Boolean, Map<Tuple<String,Tuple<Integer,Float>,String>,String>>
would not generate a compilation error during annotation processing.
Optional support has been improved on parameters :
- allowing to take generics parameterized types (like
Optional<List<Long>>) Bodycontent andPathparameters can now beOptional- as before, non-
Optionalparameters are implicitely mandatory, no matter its parameter type
For the internals, parameters deserialization are now handled by dedicated @Components which implement the
EndpointParameterMapper
interface.
A factory component (EndpointParameterMapperFactory
with DefaultEndpointParameterMapperFactory
default implementation) is responsible to guess the appropriate EndpointParameterMapper which will be used for
deserialization depending on target type to deserialize.
This guessing is made only once during Route construction (so that there is no performance impact during request processing).
Currently, 3 EndpointParameterMapper are provided by DefaultEndpointParameterMapperFactory :
BaseTypeEndpointParameterMapper: mapper used to handleBaseTypewhich may be handled byMainStringConverter(jackson-based) componentBaseTypeAggregateEndpointParameterMapper: mapper used to handle anAggregateofBaseTypes. SupportedAggregates for this release areIterable,List,Set,CollectionandArrayComplexTypeEndpointParameterMapper: mapper used to handle complex (POJO) types. However, this component is not implemented yet (we’ll keep this implementation for next RestX release, see #248)
Also, if you want to recover old RestX 0.34 behaviour, we provided a LegacyEndpointParameterMapperFactory and a
LegacyEndpointParameterMapper which are not taken into account by default (due to their priority compared to above component).
If you want to re-enable it, simply change their priority and you will get back 0.34 parameters deserialization handling.
Because of those important changes, if you implemented your own StdEntityRoutes, you will likely have to change
a lot of stuff :
- you will have to pass a
EndpointParameterMapperRegistryand declare an array ofParamDefs inStdEntityRoute’s constructor thoseParamDefattributes represent parameter metadata used byEndpointParameterMapperFactoryto guessEndpointParameterMapper. - you will have to resolve input endpoint parameter differently: have a look at a generated
ResourceRouterclass taking the same parameters in order to know how to handle those input endpoint parameters.
Request Header params and annotation aliases (PR #277)
A new @Param annotation kind has been introduced : Kind.HEADER allowing to inject request headers into your @RestxResource’s
endpoints.
As other @Param annotations, you can either use @Param’s value field for header name
(@Param(value="X-My-Header", kind=Kind.HEADER)) or implicitely use parameter variable name, even if it is unlikely to
work properly : header names start with an uppercase which is not fitting Java variable naming best practices, and dashes
are used as word separator whereas dashes are forbidden in Java variable names.
New annotation have been introduced aliasing different types of common @Param annotation kinds :
@HeaderParam("foo"), aliasing@Param(value="foo", kind=Kind.HEADER)@QueryParam("foo"), aliasing@Param(value="foo", kind=Kind.QUERY)@PathParam("foo"), aliasing@Param(value="foo", kind=Kind.PATH)@ContextParam("request"), aliasing@Param(value="request", kind=Kind.CONTEXT)
Producing endpoint annotations metadata and making it available at runtime
Annotations attached to any @RestxResource endpoint will be transposed to OperationDescription.annotations new field
attached to target endpoint.
This opens a lot of possibilities as the OperationDescription.annotations will be retrievable at runtime as soon as
you have an StdEntityRoute instance in hand, typically in RestxFilters.
It would allow to create any custom endpoint annotation, specific to your project, and implement your own custom behaviour
around this custom annotation in a custom RestxFilter.
An EntityRelatedFilter useful superclass has been provided to help implementing such RestxFilter with some
commodity. You can have a look at ExpiresHeaderFilter
or LocationHeaderFilter
for examples on such Filter implementations.
@ExpiresAfter and @LocationHeader new annotations, and injecting RestxResponse
2 new annotations have been added to manage some frequently used response headers.
Those annotations handling are using the new OperationDescription.annotations field we talked about above and are aimed
at giving you some examples if you decide to implement your own Response Headers management.
@ExpiresAfter annotation allows to generate an Expires response header. It can be used this way :
@GET("/expires")
@ExpiresAfter("2d 4h")
public String expireHeader() {
return "hello";
}
@LocationHeader annotation allows to generate a Location response header. It can interpolate fields from entity
returned by your endpoint, and can use special _baseUri_ and _currentUri_ variables.
It can be used this way :
@POST("/foos")
@LocationHeader("{_currentUri_}/{id}") // Resolved to /api/foos/{id}
public Foo locationHeader(Foo foo) {
foo.setId("123456");
return foo;
}
@POST("/foos2")
@LocationHeader("{_baseUri_}/headers/foos2/{id}") // Resolved to /api/headers/foos2/{id}
public Foo locationHeader2(Foo foo) {
foo.setId("123456");
return foo;
}
In the end, for easy custom response header management, you will be able to inject RestxResponse into your enpoints
by using @Param(value="response", kind=Kind.CONTEXT) special annotation.
This behaviour is clearly discouraged for several reasons :
- you’re tainting your endpoint with Restx specific API (like you would do with
RestxRequest) - things you will do with
RestxResponseinstance will remain undocumented in api-docs - with great powers comes great responsibilities : if you use
RestxResponseAPI to writeresponsebody too early, it may lead to unwanted/unpredictable behaviour.
CORE
- 52c625f improved
ConfigLoaderwhich can now load settings from a file on the filesystem (see documentation). - 2994692 introduced
CurrentLocaleResolvercomponent used to provide your own locale guessing inMessagesRouter, particularly in cases when locale is part of User’s data - ba28876 introduced
PermissionFactorycomponent allowing to provide your ownhasRole()implementation, and replacingPermissionsutility class. - 316c3f4 introduced
SessionInvalidercomponent providing extension point to custom logout behaviours - 99acd3d introduced
CurrentSessionResolvercomponent allowing to provide your own current session resolution onGET /sessions/currentcalls - 46f8b58 principal cache is cleared upon logout, thus allowing to refresh principal roles on his next connection
- e6e5edd better
ResourcesRouteexample in doc as the previous one was suggesting a security flaw - 6529fad introduced
domain&secureflags onRestxSessionCookieDescriptorallowing to further customize generated cookies; old behaviour (no domain, secure=false) is kept by default. - 4c139a7 allowing underscores in path param names
- 6ce644f showing explicit error log when detecting DI cycle (see 682fb8a)
- e61bcf2 endpoints can now throw checked exceptions not extending
IOException.
VALIDATION
- bb91412 introduced MethodArgumentNotValidException wrapping bean-validation violations, useful if you want to send it to the client.
I18N
- 0576682 caching resolved
Messageskey for a givenLocale
MONGO
- e980981 introduced new
restx-jongo-java8artefact forjava8datetime serialization support withjongo.
BUILD
- 3421e31 on srv/ui projects, not having dependency from srv to ui
anymore, except during
releaseprofile - e85b0f6 introduced
!optionalflag inmd.restx.jsondescriptor allowing to declare some dependencies as optional
REFACTORS
- 2b3dc2a make RestxAnnotationProcessor reusable for different annotations
- 424bedc 34822ee
7389683 16a4951
better
ResourcesRouteextensibility
SHELL
- 15e874d falling back on maven deps installation when no md.restx.json is found in current module
- 95d5e6c falling back on ivy deps installation when no md.restx.json file nor pom.xml file is found in current module
- e1d2202 allowing to generate md.restx.json only, pom.xml only or
module.ivy only when calling
restx app new - dc2e0f2 fixing pom.xml parsing when some artefact GAV properties are inherited from parent artefact
- ef85173 keeping parsed representation of module descriptors (
pom.xml,restx.md.jsonetc..) in order to use those parsed representations when writing updated representation of the descriptor - dca208d chrooting on
srv/sub-directory whenrestx app runcommand is launched from a directory not containing anymd.restx.jsonfile - 85539e4 returning back on initial shell location after
restx app run - 6b1334d falling back on ivy-based
pom.xmldependency resolution when we detectmvncommand is not installed on current machine - 19c1aef moved
restx shellmodules into a new dedicatedrestx-shellrepository asrestxandrestx-shellshould not have the same lifecycle
API Docs
- fcb821d removing api-docs
relatedOperationswhen targettingStringtype as it was leading to a lot of useless related operations.
SERVERS
- e77f848 replaced
restx-server-simplebyrestx-server-jetty8insamplest, making debugging easier asrestx-server-simpledoesn’t propagate exceptions occuring during route processing. - 934f931 95ed631 introduced
new
restx-server-jetty7artefact forservlet 2.5-compatible embedded jetty server - 6b20ac6 introduced
WebServerBasesuperclass intended to share commonWebServercode - ad67870 allowing to specify bind interface on
SimpleWebServer’s builder
MINOR
- b54562c Introduced
MoreClasses.getInheritedClasses()utility method - c41aeda Added example of i18n-admin module in samplest
- dee37c8 adds toString on generated ParameterizedType to ease debugging
- 6a56329 lowered factory log level from INFO to DEBUG for less verbose output in factories
- 98d8528 introduced
MoreAnnotationsutility class
BUG FIXES
- c41aeda i18n admin module doesn’t give access to messages (Fixes #179)
- b5bbb99 make MongoClient an AutoCloseable component (Fixes #193)
- be01892 fix: exception when watcher services are closed
- 51982bb fix: two generated ParameterizedTypes were not equals
- 8a75daa considering restx-server dependency as
optionalon new restx projects to remove it (and its dependencies) from packaging (Fixes #220) - 8cbcaaf mark servlet-api dependency as
provided - 418811f e0e01e5
(security) all requests to admin endpoints needs
restx-adminrole - fce9d8d (security) 404 response should not list every endpoints in
prodmode - 449b870
DELETEendpoint parameters should be looked up inQUERYparam instead ofBODYcontent when no@Paramis provided (default behaviour) - b4d8650 fixing int underflow issue when comparing engines or names
having priority set to
Integer.MAX_VALUE(Fixes #242) - 877744c allowing backslashes in restx configs, allowing multiline property value (Fixes #196)
- b9d5e2b fix specs recording on root url endpoint (
/) (Fixes #176) - f061e73 handling EOF (
ctrl+D) in restx shell (Fixes #200) - 55226db when provided, query/path param name defined in annotation value should prevail over variable name in resource
- 6e337b4 fixed type descriptions in api docs on complex parameterized types (generics)
- 8c3b781 PATH parameters are not url-encoded anymore in restx console (Fixes #257)
Getting started / Upgrading
Want to get started now? Check out the related doc.
Upgrading from an earlier version?
- in your projects you just need to update
restx.versionto 0.35 in your dependency descriptor - in your code you might have to adapt to some breaking changes (see below)
- in the shell, run
shell upgradeto upgrade your shell and plugins.
MAJOR BREAKING CHANGES
Those breaking are likely to be hit by any existing RestX project. Consider those as a “migration guide” to apply on your project :
- 9a93edf
restx-server-jettyartefact has been renamed torestx-server-jetty8 - 8475ee5 renamed
JettyWebServertoJetty8WebServer, same for module and properties (for instance,restx.server.jetty.webxml.default.location=>restx.server.jetty8.webxml.default.location) - ba28876
Permissionsutility class has been replaced byPermissionFactorycomponent - ba28876
StdRestxSecurityManagernow takes aPermissionFactoryin its constructor, if you subclassed it, you will need to provide this component during construction (simply inject it in your constructor). - ebac25e
PATHparams are url-decoded by default; if you want to keep old behaviour, simply@Provide @Named("restx.http.decode.url.path.params")component valued tofalse - Some libraries have evolved :
- 2bab182 upgraded guava from 17.0 to 18.0. See guava 18 release note.
- 9e56b1f upgraded jongo from 1.0 to 1.3.0. See
jongo release note.
Worth noting in this upgrade is the compatibility with
mongo-java-driver 3.0and the rename of some frequently used annotations :@Id => @MongoIdand@ObjectId => @MongoObjectId
Important : upgrade has been rolled back to jongo 1.1 in 0.35.1, upgrade to jongo 1.4.0 has been postponed to 0.36. - 1c07f87 b1c4dd5 following jongo upgrade to 1.3.0,
mongo-java-driverhas been upgraded to3.4(see compatibility matrix) andbson4jacksonto 2.8.0.
Important : those upgrades have been rolled back in 0.35.1, upgrade to mongo-java-driver 3.4.0 & bson4jackson 2.9.0 have been postponed to 0.36. - 515d8e8 upgraded jackson from 2.3.3 to 2.8.10
(latest
2.8.Xversion). See jackson release notes.
- If you implemented your own routes :
- 58f190a
RestxRequestMatchershould be passed toRestxSecurityManager - 4f61fd2 considering a
StdEntityRouteshould always bring apermissionFactoryat construction time (simply inject it in your route and pass it to thesuperconstructor) - PR #177
StdEntityRouteconstructor and input parameters mapping have evolved (have a look at theUnified and improved Query, Path and Body params handlingsection)
- 58f190a
- If you implemented your own
WebServer: - 46f8b58 principal cached roles are now cleared upon logout; if you already
were cleaning the roles, don’t forget to remove this behaviour or implement your own
SessionInvalidercomponent for this purpose - 8c14dff
GET /sessions/currentreturns404 Not foundinstead of200 OKwhen no session is defined for current request - 3db7d18 every graphite settings are now prefixed with
restx.to avoid collisions with existing graphite properties potentially defined on your app server
MINOR BREAKING CHANGES
Those breaking changes are unlikely to happen as it is happening on very rare/specific cases.
Anyway, this is worth noting it in case you would be in those particular scenario :
- 460715b
Nameare aString+Typeinstead of aString+Class - ceb7a5b
FactoryMachine.nameBuildableComponentsusesType(instead ofClass) - 58f190a if you implemented your own
RestxSecurityManager, you will have to updatecheck()prototype to take aRestxRequestMatcher - f3e51cf if you implemented your own
Permissionimplementation, you will have to updatehas()prototype to take aMap<String, String> roleInterpolationMapparameter - f3e51cf if you relied on
Permissionsutility class, you will have to pass an additionnalMap<String, String> roleInterpolationMapparameter to method calls - 44e142c if you were using braces (
{}) in your roles, those will now be interpolated - 2afa00b if you provided your own
Messagesimplementation, you will have to provide anIterable<String> keys(Locale)with same impl thanIterable<String> keys() - 0576682 if you provided your own
MutableMessagesimplementation, don’t forget to invalidate cached keys when you mutate yourMutableMessagesinstance (most of the time insetMessageTemplate()) - 9effdfd
ResourcesRoutedoesn’t allow to serve resources from root classpath anymore, as it is considered a security flaw - 489961d using static classes for shell’s
depscommand’s subcommands instead of instance classes - 449b870
DELETEendpoint parameters should be looked up inQUERYparam instead ofBODYcontent when no@Paramis provided (default behaviour)
Contributions
Thanks a lot to the community who made this possible, especially the contributors to this release:
- Xavier Hanin (committer),
- Frédéric Camblor (committer)
- Augustin Peyrard (committer)
- Cedric Gatay
- Thomas Zayouna
- David Pilato
- Julien Legras & Synacktiv for their security advisory