# SmallRye > SmallRye is a project to share and collaborate on implementing specifications that are part of Eclipse MicroProfile. ## Posts ### [Fault Tolerance 7.0.0](/blog/fault-tolerance-7-0-0/) Today, we announce the release of SmallRye Fault Tolerance 7.0.0. This is a major release that bumps the minimum Java version, removes several deprecated features, fixes multiple bugs and updates significant dependencies. The new minimum Java version is 17. This is long overdue, there’s probably no user out there still on Java 8 or 11. The following deprecated features were removed: support for @Blocking and @NonBlocking use @Asynchronous and @AsynchronousNonBlocking instead the old programmatic API: FaultTolerance, @ApplyFaultTolerance use the new programmatic API: Guard, TypedGuard, @ApplyGuard support for MicroProfile Metrics use Micrometer or OpenTelemetry Metrics the integration of OpenTracing with MicroProfile Context Propegation use OpenTelemetry Tracing support for Security Manager The dependencies on the following libraries were updated: Jakarta EE: we now use Jakarta EE 11 Vert.x: we now use Vert.x 5 Micrometer: we were stuck on Micrometer 1.12 due to a breaking change in the Prometheus client, but we’re on the latest release now many others (Mutiny 3, JUnit Jupiter 6, etc.) The fixed issues are: fault tolerance annotations (@Fallback etc.) present on a stereotype that is present on the guarded class are now correctly applied thanks Teles Nascimento for the issue report and the fix! memory leak in metrics when @ApplyGuard is used thanks Zaiqi Yang for the issue report and the fix! multiple concurrency issues (AI assisted) As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.6.0](/blog/jandex-3-6-0/) Today, we announce the release of Jandex 3.6.0. This release contains a number of improvements and bug fixes. The following methods: IndexView.getAnnotationsWithRepeatable() AnnotationTarget.annotationsWithRepeatable() AnnotationTarget.declaredAnnotationsWithRepeatable() Type.annotationsWithRepeatable() require an annotation name on the input, together with an index that is used to obtain the annotation class. The annotation class is used to figure out if the annotation is repeatable and if so, to obtain the name of the container annotation. Very often, when these methods are called, the user knows that the annotation is repeatable and has access to the name of the container annotation. For these cases, this release adds overloads that, instead of an index, accept a name of the container annotation directly. BREAKING CHANGE: This change adds one method to the IndexView interface, which is sometimes implemented by user code. It should be relatively straightforward to implement, similarly to the existing implementation of getAnnotationsWithRepeatable(). A class JandexKotlin was added that contains a small number of helper methods that are common when working with Kotlin code. The ClassInfo class intentionally doesn’t provide equality (as in, doesn’t override equals()). While this seems questionable, there is a good reason for it: if you have a composite index representing multiple JARs (each sub-index of the composite corresponding to one JAR), those JARs may contain duplicate classes. To be able to faithfully represent such case, equality cannot be based just on a class name, and ClassInfo currently doesn’t contain any other information that would help distinguish classes with the same name but coming from different JARs. Hence, equality of ClassInfo is just identity. However, ClassInfo didn’t override hashCode() either. The default hashCode() implementation is not deterministic, which is bad for various reproducibility efforts (including CompositeIndex). Therefore, since this release, ClassInfo does override hashCode() (but not equals()!). The hash code is based on the class name, which leads to collisions in case of duplicate classes, but those are relatively rare, so this shouldn’t be an issue. Creating an EquivalenceKey for array types was fixed in case the array type contained type annotations on the array dimensions. One more case of invalid type annotation paths generated by the Kotlin compiler was found, and this release adds a workaround. Thanks Liam Miller-Cushon for the bug report! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.11.1](/blog/fault-tolerance-6-11-1/) Today, we announce the release of SmallRye Fault Tolerance 6.11.1. This release contains one small bugfix. The Micrometer integration registers all metrics early. During that registration, incorrect tags were used for rate limit metrics. The actual collection of rate limit metrics is correct, but the disparity between initial registration and actual collection may lead to failures with certain observability systems, such as Prometheus. Initial registration uses correct tags now, so the issue is fixed. As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.11.0](/blog/fault-tolerance-6-11-0/) Today, we announce the release of SmallRye Fault Tolerance 6.11.0. This release contains one small improvement. Previous versions of SmallRye Fault Tolerance did not support Java modularity (JPMS) at all. With this version, automatic module names are provided for all useful modules. The test suite modules do not have automatic module names, because they are never supposed to be used publicly. The OpenTracing Context Propagation module is obsolete and should not be used these days, so it does not have an automatic module name either. (Among other deprecated things, it will be removed in SmallRye Fault Tolerance 7.0.) Note that to improve internal consistency and make sure that the module name is the same as a top-level package name of all classes in the module, a small number of internal classes were moved in this release. Advanced integrators (such as Quarkus) need to take care, but this should be an invisible change for users. We intend to provide full module descriptors in the future, but cannot do that at the moment. This is because certain dependencies, notably the MicroProfile Fault Tolerance API JAR, do not provide either automatic module names or module descriptors. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.5.3](/blog/jandex-3-5-3/) Today, we announce the release of Jandex 3.5.3. This release contains a few small improvements. EquivalenceKey performance was improved, thanks to some wonderful ideas of Francesco Nigro. Notably, caching of ClassTypeEquivalenceKey was improved, and the exact same caching approach was added to ClassEquivalenceKey, which previously had no caching at all. Also, all equals() and hashCode() methods were improved to avoid null-safe calls (Objects.equals(), Objects.hashCode()), because all fields in these classes are never null. The StringBuilderGen implementation (in the gizmo2 module) was updated to latest improvements in Gizmo 2. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.10.0](/blog/fault-tolerance-6-10-0/) Today, we announce the release of SmallRye Fault Tolerance 6.10.0. This release contains one improvement and one bug fix. Previous versions of SmallRye Fault Tolerance included support libraries for async types from Mutiny (Uni) and RxJava 3 (Single, Maybe and Completable). In this release, the Vert.x support library, which previously only included support for the Vert.x event loop, also includes support for the Vert.x Future type. All guarded asynchronous methods may now return io.vertx.core.Future and if the Vert.x support library is present, it will all work. Also, the previous SmallRye Fault Tolerance versions supported @Fallback methods on interfaces where the fallback method is a default method in the interface. As it turned out, this only worked when the interface was public. This release fixes the issue. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.5.2](/blog/jandex-3-5-2/) Today, we announce the release of Jandex 3.5.2. This release contains a few small improvements and new features. A method ClassInfo.method(MethodInfo) was added that allows finding a method declared in a given class based on a signature of the given method (which is supposedly declared in another class). This has already been possible using other overloads of method(), but if you already have a MethodInfo based on which you want to search, the new method allows that directly. Thanks Michael Edgar for the pull request! A method DotName.startsWith(DotName) was added that allows figuring out if a dotted name starts with another dotted name. Note that the prefix determination is not analogous to String.startsWith(); instead, it works on the dotted name structure level. For example, com.example.FooBar starts with com, com.example and com.example.FooBar, but it does not start with com.exam or com.example.Foo. Thanks Michael Edgar for the issue! Finally, searching for annotations (internally, AnnotationInstance.binarySearch()) was optimized slightly. If the annotation array is empty or contains just one element, the code answers directly instead of starting the search process. Thanks Michael Edgar for the issue! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.5.1](/blog/jandex-3-5-1/) Today, we announce the release of Jandex 3.5.1. This release contains one small improvement (which may be seen as a bug fix by some) and one small new feature. The Gizmo 2 integration module now includes a StringBuilderGen class. This is a replacement for the StringBuilderOps class that was removed in Gizmo 2.0.0.Beta8 due to unresolved disputes over the API design, particularly around reusability. It is highly likely that StringBuilderOps are coming back to Gizmo 2 in some shape, likely different to the previous version. In the meantime, you can use StringBuilderGen from Jandex. Certain well-known class types (as in, instances of ClassType) are now guaranteed singletons (if they have no type annotations). This applies for example to java.lang.Object, which has a nice side effect: all unbounded wildcards are now guaranteed to be represented as ? and never as ? extends java.lang.Object. Thanks Robert Stupp for the pull request! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.9.3](/blog/fault-tolerance-6-9-3/) Today, we announce the release of SmallRye Fault Tolerance 6.9.3. This release contains one small improvement. SmallRye Fault Tolerance is not a tiny project anymore; these days, it consists of roughly 15 subprojects. Therefore, starting with this release, we provide a BOM: io.smallrye:smallrye-fault-tolerance-bom. Use this BOM to manage version numbers of all SmallRye Fault Tolerance modules. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.5.0](/blog/jandex-3-5-0/) Today, we announce the release of Jandex 3.5.0. This release contains multiple optizations, bug fixes and and small new features. Class MethodSignatureKey was added, together with MethodInfo.signatureKey(). A method signature key implements equals() and hashCode() according to the method signature (that is, method name, parameter types, return type). This allows skipping methods during processing of an inheritance hierarchy if another method with the same signature has already been processed. The concept has already existed in Quarkus, but the implementation added in Jandex is slightly more optimized. Method MethodParameterInfo.nameOrDefault() was added. As opposed to MethodParameterInfo.name(), this method never returns null; instead, when the parameter name is not known, it returns argN, where N is a zero-based parameter index. Methods copyModifiers() and constOfEnum() were added to Jandex2Gizmo, simplifying the Gizmo 2 integration in certain cases. Index reproducibility was fixed in case of type annotations. Jandex has been trying to produce reproducible output since version 3.1.0, but since that version, several bugs have been found. This time, a bug was found in case type annotations were used. This bug was fixed, leading to reproducible output in even more cases. Thanks Robert Stupp for the issue report, reproducer and an attempt to fix! Finally, several optimizations were performed especially to reduce allocations. Thanks Guillaume Smet for issues and fixes! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.9.2](/blog/fault-tolerance-6-9-2/) Today, we announce the release of SmallRye Fault Tolerance 6.9.2. This release contains an important bugfix. Since the 6.7.2 and 6.7.3 releases, Vert.x worker threads are treated as event loops as well. In case of a worker thread execution from an event loop context, the event loop integration code used to use Context.executeBlocking() in an ordered fashion. This may lead to a deadlock-like situation in case the original call also occurs in an ordered executeBlocking() situation, because: the original handler that called a guarded method may wait for it to complete, the newly scheduled handler comes after the original handler, so has to wait for it to complete. In this release, the issue is fixed: the event loop integration code no longer requires ordering. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.4.0](/blog/jandex-3-4-0/) Today, we announce the release of Jandex 3.4.0. This release contains one bugfix and one new feature. Type annotations were not parsed correctly in certain situations involving nested types. This bug is fixed in this release. Jandex now also includes integration with Gizmo 2. Gizmo 2 is an evolution of Gizmo, the bytecode generation framework used in Quarkus. Gizmo version 1 used Jandex in its core, but Gizmo version 2 does not. Therefore, an integration package is needed. This version of Jandex includes a new module, io.smallrye:jandex-gizmo2, which contains a class called Jandex2Gizmo with these static methods: classDescOf() to create java.lang.constant.ClassDesc fieldDescOf() to create io.quarkus.gizmo2.desc.FieldDesc methodDescOf() to create io.quarkus.gizmo2.desc.MethodDesc constructorDescOf() to create io.quarkus.gizmo2.desc.ConstructorDesc genericTypeOf*() to create io.quarkus.gizmo2.GenericType and its subtypes typeArgumentOf() to create io.quarkus.gizmo2.TypeArgument copyTypeParameters() and addTypeParameter() copyAnnotations() and addAnnotation() If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.3.2](/blog/jandex-3-3-2/) Today, we announce the release of Jandex 3.3.2. This release contains a few small improvements. The possible existence of an implicit Object bound of a type variable has never been a public API on TypeVariable. That changes now: the hasImplicitObjectBound() method becomes public. Also, the TypeVariable.Builder API now has a method implicitObjectBound() to declare that the type variable has an implicit Object bound. This happens when all bounds of a type variable are interface types. EquivalenceKeys for primitive types and java.* class types are now interned. Together with other improvements, this should lower allocation rate significantly when working with equivalence keys (for example, when using the AnnotationOverlay). Thanks Guillaume Smet for the initial pull request! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.3.1](/blog/jandex-3-3-1/) Today, we announce the release of Jandex 3.3.1. This release contains a few small improvements and bugfixes. The MethodInfo.isAbstract() method was added. It is a simple shortcut for Modifier.isAbstract(method.flags()). The PrimitiveType.isBox() method was added. It returns whether the given Type is a class that is a wrapper type of a primitive type (or, in other words, possible result of a boxing conversion). The ClassInfo.simpleName() method was fixed in case of top-level classes with dollar $ in their names. Thanks Martin Kouba for the bug report! The module descriptor (module-info.class) was added. Since Jandex is still a Java 8 project, the module-info.java class is not compiled by javac; instead, it is present outside of src/main/java and is turned into the .class file by Moditect. Missing deprecation notices (missing @deprecated javadoc tags for @Deprecated methods) were added. Thanks Martin Panzer for the bug report! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.9.1](/blog/fault-tolerance-6-9-1/) Today, we announce the release of SmallRye Fault Tolerance 6.9.1. This release contains an important bugfix. After the big async rewrite, the retry strategy used recursion to implement a loop even in the synchronous case. That is wrong, because it may easily lead to a stack overflow error in case of a high number of retry attempts. This bug is now fixed. The internal Future type has gained a dedicated loop() method to implement while loops. The implementation is structured so that recursion is used for asynchronous iterations, while classic loop is used for synchronous iterations. In other words, it is a "just enough" implementation of trampolines. Thanks Maxuel Macavilca Montjoy for the issue report! Also, with this release, the portable extension in SmallRye Fault Tolerance ignores synthetic methods. This means they are not intercepted anymore by the fault tolerance interceptor. The Quarkus extension for SmallRye Fault Tolerance has already been ignoring synthetic methods for a long time; now all the other CDI Full based implementations work similarly. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.3.0](/blog/jandex-3-3-0/) Today, we announce the release of Jandex 3.3.0. This release contains two improvements. The ClassInfo.enclosingClassAlways() method was added. Contrary to enclosingClass(), which only returns the enclosing class for member classes, this method returns the enclosing class in case of all classes: member, local and anonymous, regardless of their declaration site. Notably, in case of local and anonymous classes, they can also occur in static initializers, instance initializers and field initializers. In this case, it wasn’t possible to determine the enclosing class before. The IndexView.getKnownDirectImplementations() and getAllKnownImplementations() methods were added. The getKnownDirectImplementations() differs from the existing getKnownDirectImplementors() method in that it doesn’t return direct subinterfaces, which is most likely what users expect. The getAllKnownImplementations() is not different to getAllKnownImplementors() at all, it exists just for symmetry. Also, the getKnownDirectImplementors() and getAllKnownImplementors() methods are now deprecated. Use the get*Implementations() methods instead; pay attention to the difference mentioned above, but it shouldn’t affect most of the code out there. BREAKING CHANGE: This Jandex release increments the persistent format version. This means that indices generated by Jandex 3.3.0 are not readable by previous Jandex versions. Since the only change in the persistent index is the addition of enclosing class information for the initializer case, it is recommended to stay on the previous format version for most users for a while. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.9.0](/blog/fault-tolerance-6-9-0/) Today, we announce the release of SmallRye Fault Tolerance 6.9.0. This release contains an important bugfix. Upgrade is strongly recommended. Starting with the 6.3.0 release, SmallRye Fault Tolerance emits metrics even when using the programmatic API. If there is no description set on the Guard / TypedGuard / FaultTolerance object, a UUID was used as the value of the method tag. However, at least in some metrics implementations, the keys and values of all tags are retained in memory. If a Guard / TypedGuard / FaultTolerance object is created for each action (which is relatively easy to achieve without even knowing), a fresh UUID is generated for each object. Since those UUIDs are stored in memory indefinitely, this basically amounts to a memory leak. In this release, this memory leak is fixed. If there is no description set on the Guard / TypedGuard / FaultTolerance object, metrics are simply not emitted. This is technically speaking a breaking change, but we feel it is very much warranted. Noone likes memory leaks and OOMs happening in production. The bug is also fixed in the 6.4.2 release, which doesn’t have an announcement. More backports might be coming. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.2.7](/blog/jandex-3-2-7/) Today, we announce the release of Jandex 3.2.7. This release contains one bugfix. An annotation overlay configured to include inherited annotations didn’t necessarily work correctly when asked for annotations on the Object class, depending on the underlying IndexView implementation. That was fixed in this release: when the passed class does not have a superclass (which means it is Object), the index is not queried at all. Thanks Matěj Novotný for the issue and pull request! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.2.6](/blog/jandex-3-2-6/) Today, we announce the release of Jandex 3.2.6. This release contains one improvement. Performance of the immutable annotation overlay (AnnotationOverlay) was significantly improved, especially in the most common case of no annotation transformation. That improvement consists of caching the result of annotation transformations for all declarations, even for those where no transformation applied. This was originall omitted, but it turns out that the memory overhead is very small, because most objects already exist. There are other small improvements too, including significant shrinking of allocation rate. Thanks Martin Panzer for the original pull request! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.2.5](/blog/jandex-3-2-5/) Today, we announce the release of Jandex 3.2.5. This release contains two bugfixes. The ClassInfo.canonicalRecordConstructor() method had two issues. If the record only had 1 component, it didn’t work at all. It also didn’t work properly when javac emitted type annotations on the record components differently from the canonical constructor parameters. That in theory shouldn’t happen, but in practice, there are cases like that. Both of these issues are fixed. Further, certain type annotations were sometimes forgotten. This happened when one target (such as a MethodInfo) had both class-retained and runtime-retained type annotations. In this case, only one kind would survive; type annotations of the other kind would be lost. This bug is fixed now and all type annotations are now present in the index. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.8.0](/blog/fault-tolerance-6-8-0/) Today, we announce the release of SmallRye Fault Tolerance 6.8.0. This release contains one new feature. In SmallRye Fault Tolerance 6.7.0, we introduced a new programmatic API, together with an annotation to use the programmatically created Guard / TypedGuard objects declaratively: @ApplyGuard. In this release, we add support for configuration for @ApplyGuard using MicroProfile Config. Note that Guard and TypedGuard themselves still do not support configuration, only @ApplyGuard does. This means that if you want to configure the Guard/TypedGuard used declaratively via @ApplyGuard, you should NEVER use those objects programmatically. Configuration is applied on creation, which happens lazily, on the first use. This first use must be through @ApplyGuard, otherwise configuration would be ignored. Configuration keys are still the same, except you use the @Identifier value instead of a <classname> or <classname>/<methodname>. For example, let’s assume the following Guard declaration: @ApplicationScoped public class PreconfiguredFaultTolerance { @Produces @Identifier("my-fault-tolerance") public static final Guard GUARD = Guard.create() .withRetry().maxRetries(2).done() .build(); } Then, to configure the maximum number of retries, one can use the following configuration keys: SmallRye Fault Tolerance specific: smallrye.faulttolerance."my-fault-tolerance".retry.max-retries specification defined: my-fault-tolerance/Retry/maxRetries Global configuration also applies to @ApplyGuard. In this case, the keys are: SmallRye Fault Tolerance specific: smallrye.faulttolerance.global.retry.max-retries specification defined: Retry/maxRetries Enablement configuration also applies. Note however that if the Guard or TypedGuard is created without certain fault tolerance strategy, no amount of configuration can add it. Configuration only applies to strategies that were added in the builder. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.2.4](/blog/jandex-3-2-4/) Today, we announce the release of Jandex 3.2.4. This release contains one small improvement. The JandexReflection.loadType() method was added. This method accepts a Jandex Type and returns a corresponding Reflection Type. The result is equal to the reflectively obtained Type and has the same hash code, as long as there are no type variables. The JDK implementation of TypeVariable.equals() checks for a specific implementation class, so proper equality is impossible to achieve in this case. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.7.3](/blog/fault-tolerance-6-7-3/) Today, we announce the release of SmallRye Fault Tolerance 6.7.3. This release contains one bugfix. In the previous release, the event loop integration was significantly improved. That improvement, alas, contains a bug in the Vert.x integration. We assumed that a Vert.x thread is always associated with a current Vert.x context, but that doesn’t have to be the case. Especially in case of a worker thread pool, which can be (in Quarkus, for example) used as a classic thread pool as well and tasks can be submitted to it outside of a Vert.x context. This wrong assumption lead to a NPE, which is fixed now. As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.7.2](/blog/fault-tolerance-6-7-2/) Today, we announce the release of SmallRye Fault Tolerance 6.7.2. This release contains one bugfix and one improvement. The event loop integration was significantly improved. In case the original invocation happened on an event loop thread, it is now guaranteed that the asynchronous completion also happens on the same event loop, even if the method completed on a different thread. Timeouts are now also signalled on the event loop. In case of the Vert.x integration in SmallRye Fault Tolerance (and therefore Quarkus), Vert.x worker threads are now also treated as event loops (although the guarantee of "the same event loop" is not as strict). The capacity of a bulkhead is a sum of the bulkhead limit and the bulkhead queue size. That sum could overflow, which wasn’t detected before. In this release, an overflow is a validation error which fails the deployment (in case of the @Bulkhead annotation; when using the programmatic API, the BulkheadBuilder.done() method will throw an exception). Thanks Sayra Gmelig Meyling for the issue report! As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.7.1](/blog/fault-tolerance-6-7-1/) Today, we announce the release of SmallRye Fault Tolerance 6.7.1. This release contains one bugfix. The new programmatic API (Guard, TypedGuard) introduced in SmallRye Fault Tolerance 6.7.0 allows guarding multiple kinds of actions, both synchronous and asynchronous. To do that, all implementations of fault tolerance strategies were unified. This unification introduced a bug in the implementation of synchronous bulkhead, where acquiring the capacity semaphore was skipped before acquiring the work semaphore. This bug would only appear when the same bulkhead is used to guard both synchronous and asynchronous actions, which wasn’t possible until recently, but it’s still a significant issue. This release fixes it. Further, the documentation index page was updated to show a programmatic API example using TypedGuard, instead of the obsolete FaultTolerance. As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.7.0](/blog/fault-tolerance-6-7-0/) Today, we announce the release of SmallRye Fault Tolerance 6.7.0. This release contains several big improvements and refactorings. Big Internal Refactoring The internal implementations of all fault tolerance strategies up until now had 2 copies: one synchronous and one asynchronous (based on CompletionStage). This changes now: all strategies are unified on an asynchronous implementation (based on an internal async type), with a few adjustments for sychronous invocations to support thread interrupts. This has been done especially for the next feature, which is…​ New Programmatic API The first version of the programmatic API (FaultTolerance, @ApplyFaultTolerance) was deprecated and scheduled for removal in SmallRye Fault Tolerance 7.0. The second version (Guard, TypedGuard, @ApplyGuard) is fairly similar, but has some important differences too. Comparison of FaultTolerance, Guard and TypedGuard: FaultTolerance TypedGuard Guard typed typed not typed allows fallback allows fallback does not allow fallback allows casting, but only if there is no fallback does not allow casting no casting is necessary, target type has to be specified for each call does not allow using synchronous FaultTolerance to guard asynchonous actions et vice versa does not allow casting allows guarding any type created using create() or createAsync() only create(), but it needs the target type (which may be sync or async) only create(); the call() method needs the target type (which may be sync or async) Comparison of @ApplyFaultTolerance and @ApplyGuard: @ApplyFaultTolerance @ApplyGuard the value() points to a bean of type FaultTolerance the value() points to a bean of type Guard or TypedGuard ignores all other fault tolerance annotations supports @Fallback and thread offload (@Asynchronous, @AsynchronousNonBlocking) does not support Kotlin suspend functions supports Kotlin suspend functions For more information about migrating to the new programmatic API, see the migration guides: Migration from FaultTolerance Migration from @ApplyFaultTolerance Further, the MutinyFaultTolerance API has no replacement. The Guard and TypedGuard APIs support Uni out of the box, if the Mutiny support library is present. New Configuration Properties Support for new configuration properties was added. The existing, MicroProfile Fault Tolerance-defined configuration still works, but the new configuration is properly scoped and looks more natural: Existing config property New config property <classname>/<methodname>/<annotation>/<member> smallrye.faulttolerance."<classname>/<methodname>".<annotation>.<member> <classname>/<annotation>/<member> smallrye.faulttolerance."<classname>".<annotation>.<member> <annotation>/<member> smallrye.faulttolerance.global.<annotation>.<member> MP_Fault_Tolerance_NonFallback_Enabled smallrye.faulttolerance.enabled MP_Fault_Tolerance_Metrics_Enabled smallrye.faulttolerance.metrics.enabled All the <annotation> and <member> parts are changed from camel case (BeforeRetry, methodName) to kebab case (before-retry, method-name). Two annotation members are special cased to improve consistency: Retry/durationUnit moves to retry.max-duration-unit Retry/jitterDelayUnit moves to retry.jitter-unit These new configuration properties exist especially for Quarkus, where they will look Quarkus-native: instead of the smallrye.faulttolerance prefix, they will start with quarkus.fault-tolerance. Conclusion Nothing should change externally, this release should be fully backward compatible. But please do pay extra attention. And as usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.6.3](/blog/fault-tolerance-6-6-3/) Today, we announce the release of SmallRye Fault Tolerance 6.6.3. This release contains one small improvement. Individual metric providers can now be disabled. To do that, set the following configuration properties (as in MicroProfile Config) to true: smallrye.faulttolerance.mpmetrics.disabled to disable MicroProfile Metrics smallrye.faulttolerance.opentelemetry.disabled to disable OpenTelemetry Metrics smallrye.faulttolerance.micrometer.disabled to disable Micrometer These properties complement the global MP_Fault_Tolerance_Metrics_Enabled property, which can be set to false to disable metrics altogether. Note that setting smallrye.faulttolerance.*.disabled to false does not mean the provider is enabled unconditionally. When that provider is not discovered or selected by the integrator, it cannot be enabled in any way. These properties are only meant for disabling an otherwise enabled metrics provider; not the other way around. As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.6.2](/blog/fault-tolerance-6-6-2/) Today, we announce the release of SmallRye Fault Tolerance 6.6.2. This release contains two small bugfixes. The @BeforeRetry annotation didn’t work correctly when guarding asynchronous actions (returning CompletionStage, Uni etc.). This bug has been fixed in this release. The support for multiple metric providers was fixed to work properly in EE environments like WildFly. As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.6.1](/blog/fault-tolerance-6-6-1/) Today, we announce the release of SmallRye Fault Tolerance 6.6.1. This release contains one small bugfix. The CDI extension in SmallRye Fault Tolerance (FaultToleranceExtension) was changed in SmallRye Fault Tolerance 6.5.0 to support multiple metric providers at the same time. This support wasn’t functioning properly in case the metrics classes for given provider were present, but the dependencies on required beans were not satisfied. In this release, all the metric providers now depend on the required beans lazily (by injecting Provider of given class, instead of the class directly). This, together with some refactoring from field injection to constructor injection for simplification, fixes the issue. As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.6.0](/blog/fault-tolerance-6-6-0/) Today, we announce the release of SmallRye Fault Tolerance 6.6.0. This release contains two small improvements. Until now, all @ApplyFaultTolerance methods that used the same identifier were collapsed into the same metrics, using the FaultTolerance description as the method tag. With this release, @ApplyFaultTolerance methods have split metrics, where the method tag is the classic <fully qualified class name>.<method name> format, even though they still share the same FaultTolerance object and therefore the bulkhead / circuit breaker / rate limit state. The FaultTolerance.BulkheadBuilder.enableVirtualThreadsQueueing() method was added. With this method, it is possible to use bulkhead queueing even with synchronous bulkhead, but there’s an important limitation: the FaultTolerance guard must be executed on virtual threads. This is not checked; it is something you have to provide yourself. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.2.3](/blog/jandex-3-2-3/) Today, we announce the release of Jandex 3.2.3. This release contains one small bugfix and one small improvement. The Type.parse() method was added. This method parses a string (according to a documented grammar) and produces a Jandex Type. The Index.singleClass() method now works properly when the passed class object in fact represents a module descriptor. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.5.0](/blog/fault-tolerance-6-5-0/) Today, we announce the release of SmallRye Fault Tolerance 6.5.0. This release implements MicroProfile Fault Tolerance 4.1 and contains several new features. The only new feature of MicroProfile Fault Tolerance 4.1 is support for OpenTelemetry / MicroProfile Telemetry, specifically for exposing metrics. Since SmallRye Fault Tolerance has already included support for MicroProfile Metrics and Micrometer, adding a third implementation was a no-brainer. In addition to that, SmallRye Fault Tolerance 6.5.0 resolves fallback methods (@Fallback.fallbackMethod()) and before-retry methods (@BeforeRetry.methodName()) statically. That is, instead of resolving the methods when the fault tolerance operation is being constructed, the methods are resolved during deployment. This makes no difference in regular environments like WildFly, but in Quarkus, where deployment happens at build time, this is a significant change. It allows proper native image compilation, and it is also a breaking change on the configuration front. The configuration of fallback methods and before-retry methods is now build-time only, and cannot be changed at runtime. Finally, in this version, the FaultTolerance.cast() and castAsync() methods were added. These methods return the same instance of FaultTolerance, but casted to guard a different type. This is often safe, but cannot happen when fallback is defined; in that case, these methods throw an exception. As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.4.1](/blog/fault-tolerance-6-4-1/) Today, we announce the release of SmallRye Fault Tolerance 6.4.1. This release contains two bugfixes. In SmallRye Fault Tolerance 6.3.0, the ThreadTimer internal class was made a singleton. That was a mistake, because that prevents 2 deployments using SmallRye Fault Tolerance in the same application server (such as WildFly). The second deployment would get an IllegalStateException with the message of Timer already exists. The mistake was fixed and there can be multiple instances of the timer once again. The instances of the timer are distinguished by an opaque identifier, which is also exposed via metrics. Further, the search for fallback methods (@Fallback.fallbackMethod()), as well as before-retry methods (@BeforeRetry.methodName()), was fixed to also include methods from inherited interfaces. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.2.2](/blog/jandex-3-2-2/) Today, we announce the release of Jandex 3.2.2. This release contains several small improvements. The ClassInfo.canonicalRecordConstructor() method was added. This method returns a canonical constructor for records as a MethodInfo. For other kinds of classes, it returns null. Further, the ClassInfo.unsorted* methods were renamed, because the old name is not exactly intuitive. The old methods still exist, but are deprecated. The new methods are: Old method New method unsortedFields() fieldsInDeclarationOrder() unsortedMethods() methodsInDeclarationOrder() unsortedRecordComponents() recordComponentsInDeclarationOrder() The javadoc of the fields(), methods() and recordComponents() methods was improved to point out that there is no guaranteed order in their return values. There is also a link to the *InDeclarationOrder() methods. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.2.1](/blog/jandex-3-2-1/) Today, we announce the release of Jandex 3.2.1. This release contains several small improvements and bug fixes. All annotations in the annotation overlay (introduced in Jandex 3.2.0) are now guaranteed to have a target. This was previously not the case for annotations added by the user, but with this release, all annotations added by the user that don’t have a target yet are assigned a target automatically. Also, the AnnotationOverlay javadoc was improved slightly. The ClassInfo class will no longer hold an empty or single-element HashMap. Instead, a Collections.emptyMap() or Collections.singletonMap() are used, making Jandex memory consumption better. Thanks Guillaume Smet for the pull request! The jandex-jar goal of the Jandex Maven plugin has gained an indexVersion parameter. This parameter was already present on the jandex goal, so this increases feature parity. Thanks Martin Hickson for the pull request! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.4.0](/blog/fault-tolerance-6-4-0/) Today, we announce the release of SmallRye Fault Tolerance 6.4.0. This release contains one new feature and one bugfix. The @BeforeRetry annotation was added, together with the corresponding methods in the programmatic API. The annotation allows defining an action that should happen before each retry, but not before the initial attempt. See the documentation for more information. Further, the synchronized keyword was replaced on one place with a ReentrantLock, making the programmatic API more friendly with virtual threads. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.2.0](/blog/jandex-3-2-0/) Today, we announce the release of Jandex 3.2.0. This release contains a number of improvements. BREAKING CHANGE: This Jandex version increases the persistent format version. Therefore, persistent indexes produced by this version will not be readable by previous Jandex releases. Annotation overlay An annotation overlay was added to Jandex. This is a layer on top of core Jandex that allows overriding annotations. This is useful when Jandex is used as a language model and annotations are used directly as framework metadata. In fact, there are two annotation overlays: a default AnnotationOverlay, which is immutable, and a MutableAnnotationOverlay. The default annotation overlay accepts an IndexView and a collection of AnnotationTransformations. These transformations are applied lazily, whenever the annotation overlay is first asked for annotation information of any particular declaration. The mutable annotation overlay only accepts an IndexView and annotations may be added and removed freely, until the overlay is frozen. When it’s frozen, a list of annotation transformations is returned so that a corresponding immutable annotation overlay may be constructed. In case you’re familiar with the AnnotationStore from from ArC or from RESTEasy Reactive, this is the very same concept, but the implementation is improved. Other improvements Support for sealed classes was added. This includes two methods: ClassInfo.isSealed() and ClassInfo.permittedSubclasses(). If a class is declared sealed, the isSealed() method returns true and the permittedSubclasses() method returns the names of permitted subclasses. To inspect them further, they must be looked up from the index. Together with this, the ClassInfo.isFinal() and ClassInfo.isAbstract() methods were also added, as a shortcut for the corresponding Modifier methods called on ClassInfo.flags(). An empty index (EmptyIndex.INSTANCE or IndexView.empty()) was added. This is a very lightweight implementation of the IndexView interface that always returns null or an empty collection. Further, a StackedIndex was also added. This is a new implementation of a composite index, which actually has well defined semantics in case the same class is present in the index multiple times (unlike CompositeIndex, which didn’t define this situation at all). In a stacked index, if a class is seen in one of the indexes, it is completely ignored in other indexes below the first one. The behavior of Index.getKnownUsers() was improved. Previously, this method only considered a class as a user of another class when a reference to the other class was listed in the constant pool. Since this Jandex version, a class is also considered as a user of another class when the other class is present in the signature of the class or any of its members. By default, the Jandex Maven plugin will not produce an index for a module with the POM packaging. This is a tiny breaking change that shouldn’t affect anyone, but in case it does, the <skipForPomPackaging> configuration option may be set to false to revert to the previous behavior. And last but not least, hash table collisions were significantly reduced when interning type variable references. This should make indexing a lot faster in certain cases. Thanks Patrick Reinhart for the issue! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.1.8](/blog/jandex-3-1-8/) Today, we announce the release of Jandex 3.1.8. This release contains two small improvements. To locate a method from a ClassInfo, one had to use the ClassInfo.method(String, Type...) method. With this release, one can also use ClassInfo.method(String, List<Type>). Thanks Guillaume Smet for the issue! Also, in this release, the runtime memory consumption of Jandex was significantly improved. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.3.0](/blog/fault-tolerance-6-3-0/) Today, we announce the release of SmallRye Fault Tolerance 6.3.0. This release contains many fixes and improvements. The @RetryWhen annotation was added, together with the corresponding methods in the programmatic API. The annotation allows defining predicate-based retries, where a predicate can be provided not only for the exception, but also for the result. This means that it is finally possible to retry on an undesirable result (such as null). The RateLimitException gained a new method getRetryAfterMillis(). It returns the number of milliseconds after which retry is possible. Retrying sooner is guaranteed to be rate limited again. Cause chain inspection was improved. Previously, when the @CircuitBreaker.failOn, @Fallback.applyOn or @Retry.retryOn annotation members were not specified, the cause chain inspection was useless, because these annotation members default to Throwable (or Exception in case of @Retry). In this release, when these annotation members have a default value, we skip the check and move straight to inspecting cause chains. The FaultTolerance.Builder gained a new method withThreadOffloadExecutor(). It can be used to configure an executor for thread offloads. If not set, the default executor, as provided by the integrator, is used. The programmatic API is now integrated with metrics, both in the CDI and in the standalone implementation. The number of tasks currently scheduled for future execution by the timer is now also exposed via metrics. The standalone implementation of the programmatic API has gained an integration API: StandaloneFaultTolerance.configure(). This is only useful for people who use the smallrye-fault-tolerance-standalone artifact. Finally, many microoptimizations in various parts of the core implementation were made. Thanks Andrej Fink for the issues and pull requests! As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.1.7](/blog/jandex-3-1-7/) Today, we announce the release of Jandex 3.1.7. This release contains several small fixes and improvements. A few utility methods are added to improve quality of life: Type.create(Class) to create a Type object from java.lang.Class PrimitiveType.box() and unbox() static methods for converting between primitive types and primitive wrapper classes Two bugs were fixed in AnnotationInstanceBuilder when adding class-valued members: if given a Class object, it was always assumed that it represents a class type; the void pseudo-type, primitive types and array types were not handled correctly if given a Type object that represents a multi-dimensional array, it was incorrectly rejected A bug was fixed in sorting classes during type annotation propagation. Similar problem was already fixed before, but it turned out that with bytecode obfuscation, the previous fix was not effective. Finally, some dependencies of the Jandex Maven plugin were updated, mainly to fix a possible issue with indexing reproducibility. Thanks Jorge Solórzano for the pull request! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.1.6](/blog/jandex-3-1-6/) Today, we announce the release of Jandex 3.1.6. This release contains several small fixes and improvements. Jandex 3.1.3 introduced the notion of annotation equivalence in the form of the AnnotationInstance.equivalentTo() method. This method is like equals(), except it ignores the annotation target. In this release, annotation equivalence is expanded with the introduction of equivalenceHashCode(), a hashCode()-like method that is consistent with equivalentTo(). Further, AnnotationInstance also gains a method createEquivalenceProxy() which returns an AnnotationInstanceEquivalenceProxy. An equivalence proxy is an object whose equals() and hashCode() implement equivalence (instead of equality) by delegating to equivalentTo() and equivalenceHashCode(). As opposed to an equivalence key, an equivalence proxy also provides access to the delegate AnnotationInstance. This release also fixes a NPE that could be observed when indexing certain classes that include the Signature attribute on fields. The JVM Specification says that field signatures are always reference type signatures, which is what the signature parser in Jandex assumed. As it turns out, there are classes out there, in the wild, that use a primitive type signature as a field signature. That would manifest as a NPE in previous Jandex releases, but this release accomodates this possibility. Thanks Václav Muzikář for the issue report and reproducer! Finally, in this release, Jandex provides somewhat nicer error message in case the parsed .class file is not in fact a valid JVM class file and does not begin with the expected magic value. Previously, the error message was just Invalid Magic, which is funny but not very informative. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.1.5](/blog/jandex-3-1-5/) Today, we announce the release of Jandex 3.1.5. This release contains two small fixes. Jandex heavily relies on interning (structural sharing) of objects for memory and storage efficiency. If there’s a lot of elements (such as fields) in the index that look basically the same (have the same name and type), you can be fairly sure that there will be just one instance representing them all. When those elements are annotated and all the annotations also look basically the same, one might expect that the objects will still be shared. Alas, that is not the case. The AnnotationInstance representation of annotations includes the annotation target (the element that is annotated) and that target is considered for annotation equality (AnnotationInstance.equals()). Since interning is implemented using a hash table, objects that are "basically the same" but are not equal better have different hash codes, otherwise hash collisions will slow down indexing fairly significantly if there are many such objects. Unfortunately, even though AnnotationInstance.equals() considers the target for equality, AnnotationInstance.hashCode() simply ignores it. This means that the significant indexing slowdowns actually may easily happen in practice. This releases fixes that by including the annotation target in the AnnotationInstance hash code, making collisions a lot less likely. Thanks Aaron Ogburn for finding the issue! In this release, the Maven plugin configuration option <indexName> also accepts (relative) paths instead of just file names. This was supported in previous versions of the Jandex Maven plugin, but was dropped in Jandex 3.0.0 with the introduction of <indexDir>. Thanks Ryan Lubke for the report! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.1.3](/blog/jandex-3-1-3/) Today, we announce the release of Jandex 3.1.3. This release contains several small fixes and improvements. The AnnotationInstance.equivalentTo() method was added that establishes the notion of annotation equivalence. Two annotation instances are equivalent if they have the same name (that is, the same annotation interface) and the same members. The target of the annotation is ignored (unlike the equals() method). The MethodInfo.isStaticInitializer() method was added to distinguish the special <clinit> methods (similarly to existing isConstructor(), which distinguishes the special <init> methods). Serialization compatibility with Jandex 2 was restored. Jandex 3 added a new kind of types, type variable references, and at that time, the index serialization code was not adjusted properly. Therefore, if Jandex 3 was asked to write an index of an older version, for consumption by Jandex 2, the result in fact was not readable by Jandex 2. The fix is fortunately simple, because what Jandex 3 represents as a type variable reference, Jandex 2 always represents as an unresolved type variable. So when emitting an index for Jandex 2, Jandex 3 can just serialize type variable references as unresolved type variables. (Note that Jandex 3 may still produce unresolved type variables, for example when indexing an incomplete class path.) Thanks Andrey Manzharov for the reproducer! The Jandex Maven plugin now supports setting the index version that should be produced. That way, you can upgrade your Jandex version yet keep the persistent index readable by older Jandex versions. Of course, if the upgraded Jandex has a newer persistent index format that includes more information, the older version will not contain the new information. Thanks Andrey Manzharov for the pull request! The jandex-jar goal of the Jandex Maven plugin was improved to not omit directory entries in the resulting JAR. Thanks Hui Wang for the pull request! Finally, multiple places in Jandex were changed to slightly reduce allocations. Instead of allocating a regular java.util.ArrayList and then an immutable wrapper, an immutable array-backed List implementation is used directly. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.2.6](/blog/fault-tolerance-6-2-6/) Today, we announce the release of SmallRye Fault Tolerance 6.2.6. This is a tiny release with one fix for Maven users that enable strict checksum validation. SmallRye Fault Tolerance uses Arquillian to run the MicroProfile Fault Tolerance TCK. To do that, it imports the Arquillian BOM for managing dependency versions. Arquillian 1.7.0 has unfortunately made a mistake in deploying checksums to Maven Central, and since SmallRye Fault Tolerance imports the Arquillian BOM in its root POM, all Maven users that enable strict checksum validation and depend on SmallRye Fault Tolerance directly or transitively will observe checksum validation failures. In this release, the problem is fixed by no longer importing the Arquillian BOM in the root POM; instead, all the Arquillian dependency versions are managed by the TCK module. The TCK module is not something people can depend on; for a while, we haven’t even been releasing its binary to Maven Central. Therefore, the scope of checksum validation failures is greatly reduced — they can only happen in the SmallRye Fault Tolerance project itself. A small fix for the circuit breaker state diagram in the documentation is also included. As usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.2.4](/blog/fault-tolerance-6-2-4/) Today, we announce the release of SmallRye Fault Tolerance 6.2.4. This is a tiny release with one bugfix for Micrometer integration. When a gauge is registered with Micrometer, a state object is passed to Micrometer along with a value extraction function. That value extraction function is supposed to extract the actual gauge value from the state object. In SmallRye Fault Tolerance, the state object is a Supplier and the value extraction function just calls the get method on the Supplier. The issue is that Micrometer only holds onto the state object weakly (using WeakReference). If the state object is GC-ed, Micrometer will report NaN as the gauge value. Since the Supplier in SmallRye Fault Tolerance is not used anywhere else, gauges typically don’t report the proper value. In this release, we make sure that the Suppliers do not become garbage, so gauges work correctly. Additionally, a test for fault tolerance on interface-based beans was simplified, together with the implementation of RestClient interface-based beans in RESTEasy MicroProfile (which is what this test mimics). Thanks Matěj Novotný for the PR! As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.1.2](/blog/jandex-3-1-2/) Today, we announce the release of Jandex 3.1.2. It includes a significant internal refactoring of method parameter names and synthetic parameters handling, as well as one small API improvement. JDK 18 and JDK 21 made some changes in javac that required refactoring of how synthetic/mandated parameters and parameters names are handled: https://bugs.openjdk.org/browse/JDK-8271623 https://bugs.openjdk.org/browse/JDK-8292275 With this release, method parameter handling is more robust. Thanks Christian Beikov for the bug report and reproducer! The MethodInfo class now exposes the isDefault() and isBridge() methods: isDefault() returns whether the method is a default method declared on an interface isBridge() returns whether the method is a synthetic bridge method Thanks Martin Kouba for the pull request! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.2.3](/blog/fault-tolerance-6-2-3/) Today, we announce the release of SmallRye Fault Tolerance 6.2.3. This is a tiny release with one bugfix for Kotlin users. The @Fallback annotation allows specifying 2 kinds of fallbacks: fallback methods and fallback handlers. Fallback method, as defined by MicroProfile Fault Tolerance, must have the same parameters as the guarded method. SmallRye Fault Tolerance has an improvement: the fallback method may declare an additional parameter of an exception type, which must be present at the very end of the parameter list. This doesn’t work correctly for Kotlin suspend functions, because suspend functions always have a Continuation parameter at the end of the parameter list. Therefore, a fallback method with an additional exception parameter, which is also a Kotlin suspend function, isn’t found correctly. This release fixes the bug and suspend functions may be used as fallback methods just fine. Additionally, with this release, we made a small reordering of sections in the reference guides. The section on interactions with other strategies is now always present right after the description section, so that it’s more visible. As usual, if you have any ideas for improvements, please file an issue! ### [Jandex 3.1.1](/blog/jandex-3-1-1/) Today, we announce the release of Jandex 3.1.1. It includes one small improvement and one small bug fix. As part of the effort to make creating instances of Type easier for Jandex users, this release makes the VoidType.VOID constant public. To obtain an instance of VoidType, it is no longer necessary to use Type.create(). Previous release attempted to make the indexing process reproducible, but didn’t succeed entirely. In case an indexed class contains a recursive type parameter, which is relatively common, indexing in fact wasn’t reproducible due to the unnecessary usage of System.identityHashCode(). This release fixes that. Thanks Alexey Loubyansky for providing a reproducer! If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.1.0](/blog/jandex-3-1-0/) Today, we announce the release of Jandex 3.1.0. It includes several improvements and bug fixes. Declarations The top-level interface in the Jandex object model has always been an AnnotationTarget: something that can be annotated. There are generally two kinds of things that can be annotated, speaking in Java terms: declarations and types (or type usages, to be more precise). This distinction hasn’t been reflected in the Jandex object model hierarchy, until now. Jandex 3.1 adds the Declaration interface, which directly extends AnnotationTarget. All classes that represent declarations now implement Declaration: ClassInfo FieldInfo MethodInfo MethodParameterInfo RecordComponentInfo The only AnnotationTarget that isn’t Declaration is: TypeTarget The EquivalenceKey hierarchy also has a DeclarationEquivalenceKey, so that it corresponds to the AnnotationTarget hierarchy. This is a small change that should significantly improve usage of Jandex as a language model. It is very common to only care about annotated declarations, but for now, there hasn’t been a way to distinguish them from annotated type usages. The Declaration interface serves this very purpose. Factories and builders for types There are different ways to instantiate a Jandex Type. The Type.create() static method is not very easy to use, and the concrete subclasses of Type over time accumulated different static factory methods as well. Jandex 3.1 adds a comprehensive set of static factory methods and builders to all complex Types: ClassType ArrayType ParameterizedType TypeVariable WildcardType All these classes have a set of static factory methods called create(), sufficient for the most common cases. They also have a static method called builder() that returns a builder, usable for the less common cases, including type annotations. Array types representation The ArrayType class in Jandex models Java array types. The Jandex representation, incidentally, is very different from the Java language representation, yet has always used the same terminology. Quick refresher: in Java, array types have a component type and an element type. For example, in case of int[][], the element type is int, while the component type is int[] (whose component type is int). In Jandex, int[][] has always been represented as a tuple: { componentType = int, dimensions = 2 }. This shows the first issue: conflicting terminology. The term component type in Jandex has always meant something else than in Java. That’s not everything, though. To faithfully represent type annotations on the dimensions of the array, Jandex sometimes has to use an array type as the component type of an array type. For example, the type String[] @Ann [] has to be represented as an array with 1 dimension, whose component type is an array type String @Ann []. The component type of that, in turn, is String. As you can see, this is completely different from the Java representation. This is usually not a big deal, because annotations on array dimensions are rare and multi-dimensional arrays are significantly less common than single-dimensional, but it still causes confusion. With the release of Jandex 3.1, this is no more. What Jandex used to call component type of an array is now named constituent type. To access the Jandex representation, the following methods exist: constituent(): this method is new dimensions(): this method has existed before and hasn’t been changed to avoid breaking compatibility Methods to access the Java representation of array types are added: elementType() componentType() deepDimensions() One method has been deprecated: component(): this method has existed before and hasn’t been changed to avoid breaking compatibility Reconstructing descriptors and generic signatures Advanced users of Jandex, such as Quarkus, sometimes have to reconstruct a descriptor or a generic signature of some Jandex object. In this release, Jandex has this functionality built-in, accessible through two interfaces: Descriptor and GenericSignature. Jandex classes that implement the Descriptor interface are able to reconstruct their bytecode descriptor. Similarly, Jandex classes that implement the GenericSignature interface are able to reconstruct their generic signature and also return whether a generic signature is actually required. Both descriptor and signature reconstruction can optionally perform type variable substitution. That is, if a type variable occurs when reconstructing the descriptor, the corresponding part of the descriptor may instead describe another type returned by a given substitution function (same for signatures). Other Previously, Jandex used to fail when invalid generic signature occured in the indexed bytecode. It turns out that ECJ may produce invalid generic signature on pretty basic code (synthetic static method generated for a lambda), so with Jandex 3.1, invalid signatures are simply ignored. Thanks Hélios Gilles for providing a reproducer! With great help from Francesco Nigro, a lot of performance improvements to the indexing process were made. On large JARs, we’ve seen roughly 20% improvements in indexing speed and 50% improvements in allocation rate. Thank you! Finally, Brian Demers and Guillaume Nodet provided fixes for build reproducibility. (Note that this is not an intentionally supported feature and it’s only maintained on a best effort basis.) Thanks! Summary This release brings a lot of changes, but none of them break backward compatibility. The persistent format of Jandex has not changed either, so upgrade should be safe for everyone. If you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 6.2.2](/blog/fault-tolerance-6-2-2/) Today, we announce the release of SmallRye Fault Tolerance 6.2.2. This is a tiny release with one bugfix for programmatic API usage. There are 2 variants of the SmallRye Fault Tolerance programmatic API: standalone and CDI. At runtime, only one of them should typically be present, but if there are both, a priority mechanism exists to disambiguate. This priority mechanism had a bug which could lead to incorrect variant being selected. The bug is now fixed and the programmatic API should work as expected. And as usual, if you have any ideas for improvements, please file an issue! ### [Fault Tolerance 6.2.1](/blog/fault-tolerance-6-2-1/) Today, we announce the release of SmallRye Fault Tolerance 6.2.1. This is a small release with one tiny feature useful for application server integrators. SmallRye Fault Tolerance has included support for Micrometer since version 5.5, but integrators had to fiddle with type discovery to get it working. In this release, for integrators that use the CDI Portable Extension present in SmallRye Fault Tolerance, we provide a direct way to select which metrics integration should be used. The FaultToleranceExtension class now has an additional constructor that takes a MetricsIntegration parameter. The MetricsIntegration is an enum with these values: MICROPROFILE_METRICS: use MicroProfile Metrics integration MICROMETER: use Micrometer integration NOOP: no metrics Since this is a constructor parameter, it is only useful for integrators that instantiate the Portable Extension themselves. If the integrator relies on the CDI container to discover and instantiate Portable Extensions, this mechanism is useless and they still need to alter the set of discovered types when they want a different metrics integration. We’d like to provide a different mechanism in the future, though it is not clear how that could look like. If you have any ideas, please file an issue! ### [Fault Tolerance 6.2.0](/blog/fault-tolerance-6-2-0/) Today, we announce the release of SmallRye Fault Tolerance 6.2.0. As described in the previous announcement, this release marks the end of life of SmallRye Fault Tolerance 5. There will be no more releases in the 5.x stream. This also means there will be no more Java 8 support. This release also upgrades to the Jakarta EE 10 dependencies. Documentation Previously, the documentation contained numerous references to the MicroProfile Fault Tolerance specification, and all SmallRye Fault Tolerance improvements on top of the specification were described in a single, long, hard to read document. In SmallRye Fault Tolerance 6.2.0, the documentation has been thoroughly restructured and revised. It should contain all the necessary information, so that you no longer have to refer to the specification for pretty basic stuff. The improvements on top of the specification are now placed in the same guide that describes the basic feature. Overall, the documentation now contains more information and yet should be much easier to navigate and read. It is divided into 2 major sections: How-to Guides: task-oriented guides that let you quickly start using some feature. They provide a short overview, but not many details. References: detailed guides that let you understand some feature in depth. They also provide information about more advanced options or features. There are 2 other sections (Integration, Internals), but those are not terribly useful for application developers. Circuit breaker state metric This release also adds one small feature: current state of circuit breakers is now exposed through metrics. A new metric called ft.circuitbreaker.state.current is added. It has the following tags: method: the fully qualified method name, like in all other fault tolerance metrics state = [open|closed|halfOpen]: the circuit breaker state This metric is a gauge with a value of 0 or 1. The value of 1 means that the circuit breaker currently is in given state, while 0 means that it is not. ### [Jandex 3.0.5](/blog/jandex-3-0-5/) Today, we announce the release of Jandex 3.0.5. It includes one bug fix and a few javadoc improvements. This release fixes a bug in index post-processing. When Indexer.complete() is called, Jandex does some post-processing that can’t happen when individual classes are indexed. This makes sure type annotations are correctly propagated across nested classes. To propagate type annotations from enclosing classes to enclosed classes, they must be processed in certain order. That order is partial, because we don’t really care about processing order between classes that are not enclosed in one another. However, Jandex used to use the JDK method for sorting the collection of classes, and that requires establishing a total order. Alas, the Comparator that Jandex used to use did not establish a total order. In other words, it was written incorrectly, which sometimes manifested as the [in]famous Comparison method violates its general contract! exception. The Comparator is fixed in this release. Thanks Matthias Villiger for the report! Additionally, javadoc for some methods was improved, especially for Type.name(). This is a good reminder for all Jandex users out there: if you use Type.toString() to obtain a class name, please don’t! Use Type.name() instead. Type.toString() is a human-readable representation of the type and should only be used for constructing human-readable messages. As usual, if you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.0.4](/blog/jandex-3-0-4/) Today, we announce the release of Jandex 3.0.4. It includes one bug fix and a few tiny API improvements. The most important change in this release is a workaround for wrong type paths on type annotations emitted by the Kotlin JVM bytecode compiler. If a Kotlin type that uses variance is present in a method signature, for example as a parameter, the Kotlin compiler emits a generic signature that may include a wildcard type. That happens for types such as List (which is covariant in its type parameter in Kotlin) or Continuation (which is used to compile suspend functions, and its type parameter is contravariant). When that type includes type annotations, such as List<List<@NotNull String>>, the type path emitted by the compiler for this type may end up inconsistent with the generic signature. For more details about the issue, see KT-55128. Jandex used to throw an exception when stumbling upon a type annotation with wrong type path. That’s not very nice — Jandex should be able to consume bytecode that exists in the wild. The fix simply somewhat degrades Jandex functionality to be able to survive the inconsistency. Specifically, the type annotation with wrong type path is ignored. As a small quality of life improvement, the method ClassType.create() was added to create instances of ClassType. This has already been possible using Type.create(), but the new method is more convenient in a lot of cases. Finally, the documentation for classes ParameterizedType and ClassSummary was improved. As usual, if you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.0.3](/blog/jandex-3-0-3/) Today, we announce the release of Jandex 3.0.3. It includes one small bug fix. It turns out some JVM languages (e.g. Groovy) may generate inner classes where the constructor doesn’t take an enclosing instance as a parameter. Jandex since version 3.0.0 assumed that inner classes always have such constructor parameter. This release relaxes this assumption so that Groovy classes can be indexed correctly. Thanks Emond Papegaaij for the report! As usual, if you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Jandex 3.0.2](/blog/jandex-3-0-2/) Today, we announce the release of Jandex 3.0.2. It includes a small bug fix, together with a tiny API improvement, and also some infrastructure work. A method was added to determine if a method is in fact a constructor: MethodInfo.isConstructor(). A bug in parsing type annotations on constructors of inner classes was fixed. Thanks Falko Modler for the report! Finally, the build process was refactored to avoid downloading a second JDK when the build JDK is >= 17. This should significantly improve the workflow for downstream, air-gapped rebuilds of Jandex. Also, some community standards were adopted: code of conduct, contributing and security documents are now present in the repository. Thanks Jeff Mesnil for driving that! As usual, if you experience any troubles, or if you have any ideas for Jandex improvements, please file an issue. ### [Fault Tolerance 5.6.0 and 6.1.0](/blog/fault-tolerance-5-6-0-and-6-1-0/) Today, we announce the release of SmallRye Fault Tolerance 5.6.0. This release includes several new features, one important deprecation and one important bug fix. Rate limiting SmallRye Fault Tolerance adds a new fault tolerance strategy: @RateLimit. Rate limit enforces a maximum number of permitted invocations in a time window of some length. For example, with a rate limit, one can make sure that a method may only be called 50 times per minute. Invocations that would exceed the limit are rejected with an exception of type RateLimitException. Rate limit is superficially similar to a bulkhead (concurrency limit), but is in fact quite different. Bulkhead limits the number of executions happening concurrently at any point in time. Rate limit limits the number of executions in a time window of some length, without considering concurrency. For example: @RateLimit(value = 50, window = 1, windowUnit = ChronoUnit.MINUTES) public void doSomething() { ... } This makes sure that doSomething may only be called 50 times per minute. There are 3 kinds of rate limiting that can be configured using @RateLimit(type = ...). They correspond to the most common rate limiting algorithms: RateLimitType.FIXED: a fixed window kind of rate limiting; this is the default RateLimitType.ROLLING: a sliding log kind of rate limiting RateLimitType.SMOOTH: a token bucket kind of rate limiting (could also be called rate shaping or rate smoothing) Additionally, it is possible to define minimum spacing between invocations. For example, with minimum spacing of 1 second, if a second invocation happens 500 millis after the first, it is rejected even if the limit wouldn’t be exceeded yet. Lifecycle Since rate limit is a stateful fault tolerance strategy, it is important to consider its lifecycle. Currently, rate limit is a global singleton, just like circuit breaker or bulkhead. SmallRye Fault Tolerance doesn’t allow changing it at the moment, so e.g. rate limit per user is currently impossible to implement. This is something we plan to address in the future, so feedback is welcome! Other annotations @RateLimit can be used together with all other fault tolerance annotations, as usual. If a method would hypothetically declare all fault tolerance annotations, the fault tolerance strategies would be nested like this: Fallback( Retry( CircuitBreaker( RateLimit( Timeout( Bulkhead( ... the guarded method ... ) ) ) ) ) ) A lot more information about rate limiting can be found in the documentation. New annotation for asynchronous non-blocking methods SmallRye Fault Tolerance used to discourage @Asynchronous and recommend @Blocking and @NonBlocking instead. This is problematic, because the @Blocking and @NonBlocking annotations are used by various containers to affect how the container invokes the method. If a container executes a @Blocking method on another thread, and that method applies some fault tolerance strategy, then SmallRye Fault Tolerance would execute it on yet another thread. This is hardly optimal. For that reason, starting with SmallRye Fault Tolerance 5.6.0 / 6.1.0, the usage of @Blocking and @NonBlocking for fault tolerance purposes is deprecated. The recommendation is to use @Asynchronous for methods that require offloading execution to another thread. For asynchronous methods that do not require thread offload and return CompletionStage (or some other async type such as Uni), the recommendation is: in non-compatible mode, no additional annotation is necessary, it is detected automatically; in fully compatible mode, use @AsynchronousNonBlocking. @AsynchronousNonBlocking is a new annotation introduced by SmallRye Fault Tolerance in this version. The relevant section in the documentation was thoroughly revised and contains all the details. Compatibility SmallRye Fault Tolerance will recognize and support the @Blocking and @NonBlocking annotations for the entire lifecycle of 5.x and 6.x. Support for these annotations will be removed in SmallRye Fault Tolerance 7.0.0. This does not imply that these annotations should be avoided for other purposes. This change only affects SmallRye Fault Tolerance. Fallback methods with exception parameter In the non-compatible mode, SmallRye Fault Tolerance supports access to the causing exception in a @Fallback method. A fallback method, as defind by the MicroProfile Fault Tolerance specification, must have the same parameters as the guarded method. SmallRye Fault Tolerance permits defining one additional parameter, at the end of the parameter list, which must be of an exception type. If such parameter is defined, the exception that caused the fallback will be supplied in it. For example: @ApplicationScoped public class MyService { @Fallback(fallbackMethod = "fallback") public String doSomething(String param) { ... } public String fallback(String param, IllegalArgumentException cause) { ... } } It is possible to declare multiple overloads of the fallback method, each having different type of the exception parameter. It is also possible to declare fallback method(s) with an exception parameter together with a fallback method without an exception parameter. As usual, see the documentation for more information. Circuit breaker state transitions The circuit breaker implementation in SmallRye Fault Tolerance used to perform state transitions only during invocations (that is, synchronously). This is easy to implement and doesn’t affect correctness of the circuit breaker algorithm, so there’s nothing wrong with it. However, SmallRye Fault Tolerance also allows external observation of the circuit breaker state. With the existing implementation of state transitions only during invocations, such external observations would be correct when moving from closed to open and from half-open to closed (because these transitions are defined to happen as a result of an invocation), but would not necessarily be correct when moving from open to half-open (which is defined to happen after certain amount of time, regardless of invocations). For example, if the circuit breaker is configured to transition from open to half-open after 5 seconds, but there are no invocations for 10 seconds, then external observers would see the circuit breaker staying open for twice the time it should be. With this release, the circuit breaker will perform transitions from open to half-open asynchronously, using a timer. This means that external observers of the circuit breaker state will always be correct. SmallRye Fault Tolerance 6.1.0 Coming together with SmallRye Fault Tolerance 5.6.0 is the release of SmallRye Fault Tolerance 6.1.0. SmallRye Fault Tolerance 6.1.0 is the 6.x release corresponding to 5.6.0. That is, it has all the features of 5.6.0, but requires Java 11 at minimum and uses the Jakarta EE 9 and MicroProfile 5.0 APIs. See the previous announcement for more details about the correspondence between 5.x and 6.x. ### [Jandex 3.0.1](/blog/jandex-3-0-1/) A few weeks after releasing Jandex 3.0.0, we’re back with a fresh new bugfix release: 3.0.1. It includes a small number of bug fixes and API improvements. Methods for accessing enum constants were added: ClassInfo.enumConstants() and FieldInfo.enumConstantOrdinal(). Shortcut methods for annotation access were added to AnnotationTarget, so that you no longer have to manually construct an annotation DotName. All annotation-accessing methods now have an overload that takes a String and also Class<? extends Annotation>. Note that if you use those methods frequently, it is still recommended to create constant DotNames and use them. Additionally, DotName.createSimple() has a variant that takes Class<?>. This shortens the common style of invocation from DotName.createSimple(MyClass.class.getName()) to DotName.createSimple(MyClass.class). The TypeVariable.hashCode() method used to have a serious bitmasking issue ever since the cached hash field was repurposed to also store one bit of extra information (whether there’s an implicit Object bound). This bug caused the hashCode() method to return different values over time. That is fixed now. A bug in propagating type variable annotations led to an exception when indexing certain classes, including the Guava JAR. This is fixed in 3.0.1. Thanks Mike Edgar for the report! The introduction of TypeVariableReferences in 3.0.0 caused a problem in Type equality and hash code. This is now fixed and all Types have proper structural equality and hash code again. And finally, the javadoc was improved on many places. As usual, if you experience any troubles, or if you have any exciting ideas for Jandex, please file an issue. ### [Fault Tolerance 6.0.0](/blog/fault-tolerance-6-0-0/) Today, we announce the release of SmallRye Fault Tolerance 6.0.0. This release implements MicroProfile Fault Tolerance 4.0 and therefore supports Jakarta EE 9 / MicroProfile 5.0. Implementation-wise, the 6.0.0 release corresponds to SmallRye Fault Tolerance 5.5.0. Additionally, SmallRye Fault Tolerance 6.0.0 requires Java 11 at minimum; it is no longer compatible with Java 8. For the time being, we will produce releases both in the 5.x and 6.x streams. There will always be a direct correspondence between a 5.x and a 6.x release: 5.x release Corresponding 6.x release 5.4.0 6.0.0-RC2 5.4.1 6.0.0-RC3 5.5.0 6.0.0-RC4 5.5.0 6.0.0 5.5.1 (hypothetically) 6.0.1 (hypothetically) 5.6.0 (hypothetically) 6.1.0 (hypothetically) 5.6.1 (hypothetically) 6.1.1 (hypothetically) 5.7.0 (hypothetically) 6.2.0 (hypothetically) At some point, we’ll stop producing releases in the 5.x stream. Shortly after that, we’ll upgrade the basic dependencies (Jakarta CDI etc.) to their Jakarta EE 10 versions. Since Jakarta EE 9 is mostly a transition release and runtimes we’re aware of target Jakarta EE 10 anyway, we likely won’t bump a major version for that. In other words, the upgrade to Jakarta EE 10 base will happen in the 6.x stream and will not require a 7.0 release. As usual, if you have any problems or ideas, including objections to the plan stated above, please file an issue! ### [Jandex 3.0.0](/blog/jandex-3-0-0/) Jandex is a space efficient Java class file indexer and offline reflection library. For many years, it lived in the WildFly GitHub organization, as it was originally written for WildFly (actually for JBoss AS 7, WildFly’s predecessor). Recently, Quarkus accelerated Jandex usage outside of WildFly, prompting for higher pace of bug fixes and new features, and we felt that WildFly is no longer the best home for Jandex. With a hint of sadness, we bid farewell to WildFly (you’ve been the best for long!) and are proud to announce that we settle comfortably in the SmallRye space. SmallRye started as a set of implementations of MicroProfile specifications that could be shared among various runtimes, but it has long been way more than that. Importantly, both WildFly and Quarkus use SmallRye components, so Jandex is certainly no stranger here. To highlight that, without further ado, we announce the first release of Jandex in SmallRye, version 3.0.0! Jandex 3.0.0 contains many bug fixes and features and, given the major version bump, also some breaking changes. But fear not — upgrading is still pretty easy. The full list of changes can be found in the Jandex issue tracker (which, by the way, moved to GitHub Issues a while ago). Here, we’ll highlight all the important ones and describe how to migrate. Note that the following text is pretty long and detailed. If you want a TLDR, feel free to skip to the summary. Move to SmallRye As mentioned, Jandex is now a SmallRye project. As part of that, we’ve consolidated all the Jandex projects into a single repository: https://github.com/smallrye/jandex/. This means that the Jandex Maven plugin is released together with Jandex core, and if you contribute, you no longer have to add test classes to a dedicated typeannotation-test project. This also entails a change in Maven coordinates. Old coordinates New coordinates org.jboss:jandex io.smallrye:jandex org.jboss.jandex:jandex-maven-plugin io.smallrye:jandex-maven-plugin Recommendation: if you use the Maven Enforcer plugin, configure it to ban any dependencies on org.jboss:jandex. Similar plugin exists for Gradle. Move to Java 8 Jandex 2.x is a Java 6 project. That has never been a problem, but Java 6 is just too old these days. However, Jandex has always been and continues to be conservative. Even though the major Jandex consumers we know of require Java 11 now, Jandex only bumps to Java 8. Nothing changes on the ability to parse new Java bytecode. Jandex running on Java 8 can still parse Java 17 bytecode just fine. Recommendation: if you are not on Java 8+ yet, you really should be. Uniform annotation access Accessing annotations has been the original primary use case for Jandex. However, it has never been very uniform. The ClassInfo type has different methods to access annotations than MethodInfo or FieldInfo. The AnnotationTarget interface, which all "annotated things" implement, has no annotation-related methods. With Jandex 3.0.0, this changes. The AnnotationTarget interface gains a slew of method for accessing annotations. There are 2 kinds of them, actually: methods that access annotations directly on the target; methods that access annotations on the target and all nested annotation targets. The 2nd is how Jandex used to always operate, but the 1st is often what you need. Now, both options are available. Purpose Directly on the target On the target and nested targets Has annotation of given type? hasDeclaredAnnotation(DotName) hasAnnotation(DotName) Get single annotation of given type declaredAnnotation(DotName) annotation(DotName) Get all annotations of given type (not repeatable) doesn’t make sense, there may only be one annotations(DotName) Get all annotations of given type, including repeatable declaredAnnotationsWithRepeatable(DotName, IndexView) annotationsWithRepeatable(DotName, IndexView) Get all annotations declaredAnnotations() annotations() BREAKING CHANGE: there used to be a ClassInfo.annotations() method returning a Map. That method is renamed to ClassInfo.annotationsMap(). The ClassInfo.annotations() method returns a List now. Recommendation: if you call the Map-returning annotations() method on ClassInfo, move to annotationsMap(). Note that callers of this method compiled against Jandex 2.x will continue running correctly, because Jandex 3.0.0 includes a synthetic bridge method for binary compatibility. The classAnnotation(), classAnnotationsWithRepeatable() and classAnnotations() methods on ClassInfo are now deprecated, with the corresponding declaredAnnotation* methods being the suggested replacement. Recommendation: if you call any of the classAnnotation* methods on ClassInfo, move to declaredAnnotation*. Recommendation: if you call the existing methods that access annotations both on the target and nested annotation targets, and then filter them out to retain only the annotations declared directly on the target, use the declaredAnnotation* methods. Uniform method parameter access Jandex uses the MethodInfo class to represent methods and MethodParameterInfo to represent method parameters. However, MethodInfo used to never expose any access to MethodParameterInfo. You could only access parameters from MethodInfo through the parameterName(int) and parameters() methods, where the parameterName() returned the name of given parameter, while parameters() returned the list of parameter types. The MethodParameterInfo class was only used to represent a target of AnnotationInstances. This is not very convenient. In Jandex 3.0.0, MethodInfo has several methods to access parameters: parametersCount(): returns the number of parameters parameterTypes(): returns the list of parameter types parameterName(int): returns the name of given parameter parameterType(int): returns the type of given parameter parameters(): returns the list of parameters as MethodParameterInfo BREAKING CHANGE: there used to be a MethodInfo.parameters() method returning a List<Type>. That method is renamed to MethodInfo.parameterTypes(). The MethodInfo.parameters() method returns List<MethodParameterInfo> now. Recommendation: inspect your code that accesses method parameters. It can usually be simplified using the newly introduced methods. Synthetic and mandated parameters In addition to parameters explicitly declared in the source code, bytecode generators (such as javac) sometimes have to emit additional parameters. When these parameters are prescribed by the Java Language Specification (JLS), they are called implicitly declared or mandated. Otherwise, they are an unspecified artifact of compiler implementation and are called synthetic. Jandex used to pretty much not care. Sometimes, you would see these extra parameters, while sometimes, you would not. In Jandex 3.0.0, the parameter accessing methods mentioned above never return synthetic and mandated parameters. (At least in the vast majority of cases. Jandex uses the Signature bytecode attribute and a few simple heuristics to figure out the list of explicitly declared parameters. It seems javac emits the Signature attribute for all methods that have synthetic/mandated parameters, even if it wouldn’t have to, so classes compiled with javac should be fine. There are rare cases, involving constructors of local/anonymous classes that capture lexically enclosing variables, where Jandex will return synthetic/mandated parameters for classes compiled with ECJ.) For special occasions where access to the full list of method parameters (based on the method descriptor) is required, there are 2 more methods: descriptorParametersCount(): returns the number of parameters including synthetic/mandated descriptorParameterTypes(): returns the list of parameter types including synthetic/mandated The parameter types obtained from method descriptor are never annotated and their position in the list cannot be used to obtain a parameter name. Recommendation: in most cases, you don’t need these methods. Use the parameter* methods by default and only resort to descriptorParameter* when you need to. Proper representation of recursive type parameters Jandex includes a faithful representation of the Java type system, including generic types. Type parameters, and type variables in general, used to be represented by one of the following 2 classes: TypeVariable UnresolvedTypeVariable A type variable can be unresolved for example when you’re indexing an incomplete classpath. However, with Jandex 2.x, a type variable may also be unresolved when it occurs in its own definition. For example, one often defines type parameters like <T extends Comparable<T>>. This type parameter definition is recursive in T. Since Jandex types generally do not form cycles, the first occurence of T is represented as TypeVariable, but the second occurence as UnresolvedTypeVariable. To become more faithful yet still avoid cycles in the object model, Jandex 3.0.0 includes an additional representation of type variables occuring in their own definition: TypeVariableReference With Jandex 3.0.0, the second occurence of T in the example above is represented as TypeVariableReference. A reference may be follow()-ed to obtain the type variable it points to. Recommendation: if your code has special cases for handling UnresolvedTypeVariable or Type.Kind.UNRESOLVED_TYPE_VARIABLE, it is a good sign that it needs to be updated to deal with TypeVariableReference or Type.Kind.TYPE_VARIABLE_REFERENCE. And even if not, it is a good idea to test your code with some recursively defined type parameters. Recommendation: if your code processes types in a recursive manner, you need to take care to avoid infinite regress. follow()-ing a TypeVariableReference and processing the resulting TypeVariable recursively is most likely not what you want. Changed Indexer.index() return type The Indexer.index(InputStream) method, as well as the indexClass(Class<?>) method, used to return ClassInfo of the just-indexed class. This is convenient, but prevents additional post-processing during Indexer.complete(). In Jandex 2.x, there was no such post-processing, but Jandex 3.0.0 adds some. Notably, post-processing is required for propagating type annotations on type variables across nested classes, as well as resolving unresolved type variables across nested classes and patching the resulting type variable references. BREAKING CHANGE: the Indexer.index(InputStream) and indexClass(Class<?>) methods now have a return type of void. You have to build a complete Index to be able to obtain a ClassInfo. Recommendation: if you create a one-off Indexer to index a single class, you can simplify your code using Index.singleClass(). Note that callers of Indexer.index() / indexClass() compiled against Jandex 2.x will continue running, because Jandex 3.0.0 includes a synthetic bridge method for binary compatibility. That bridge method always returns null though. If you want to keep compiling against Jandex 2.x and add compatibility with Jandex 3.0.0, you need to ignore the return value of Indexer.index() / indexClass(), or at least handle null result gracefully. Class-retained annotations Jandex 2.x only indexes annotations with @Retention of RUNTIME. With Jandex 3.0.0, annotations with retention of CLASS are indexed as well. BREAKING CHANGE: this is technically a breaking change, but shouldn’t really affect anyone. Recommendation: you can distinguish class-retained annotations from runtime-retained by calling AnnotationInstance.runtimeVisible(). Navigation for interfaces and packages Some methods were added to Index, and actually to IndexView, to navigate the interface hierarchy and package structure: getKnownDirectSubinterfaces(): returns all known direct subinterfaces of the specified interface getAllKnownSubinterfaces(): returns all known interfaces that extend the given interface, directly and indirectly getClassesInPackage(): returns all classes present in given package (but not in subpackages) getSubpackages(): returns direct subpackages of given package (but not indirect subpackages) BREAKING CHANGE: this is a breaking change if you implement the IndexView interface. Such implementations typically delegate to some other IndexView, in which case, adaptation should be straightforward. Otherwise, consult the javadoc of these methods for more precise description. Jandex 3.0.0 doesn’t break the behavior of getKnownDirectImplementors() and getAllKnownImplementors(). These methods are still inconsistent in that getKnownDirectImplementors() returns subinterfaces and classes implementing the interface, while getAllKnownImplementors() only returns classes implementing the interface. It was tempting to fix this inconsistency, but in the end, we decided it was not worth the potential trouble. Added AnnotationInstance builder To make life of Quarkus extension authors that create their own AnnotationInstances easier, we introduced a builder. The previously existing AnnotationInstance.create() methods are not going away, they are not even deprecated, they are just more difficult to use. Recommendation: use AnnotationInstance.builder() instead of AnnotationInstance.create(). Maven plugin changes As mentioned above, the Jandex Maven plugin has been merged into the Jandex codebase. Moving forward, you won’t have to track which Jandex Maven plugin version corresponds to which Jandex release: they are released together now and always have the same version number. There are some changes and improvements in the Maven plugin, too. First of all, one execution of the Jandex Maven plugin now always produces a single index. Previously, each file set configured in the Jandex Maven plugin execution produced its own index. This is counter-intuitive and usually not what you need. BREAKING CHANGE: this is a breaking change, but shouldn’t hopefully affect anyone. Recommendation: use multiple executions of the Jandex Maven plugin if you need to produce multiple Jandex indices during Maven build. Further, the file set configuration allows configuring a dependency in addition to a directory. This is useful if your artifact should carry an index including not only its own classes, but also classes from some of its dependencies. And lastly, a new goal jandex-jar was added to the Maven plugin to allow reindexing an already existing JAR. This is useful for example in combination with shading. Recommendation: the Maven plugin is described pretty well in the Jandex documentation. Other smaller changes There’s a few more changes, but those are smaller and less impactful, so we’ll just describe them briefly here. BREAKING CHANGE: the IndexReader.getDataVersion() method was removed. To the best of our knowledge, noone has actually ever used it, and the return value was wrong (didn’t conform to the contract stated in the javadoc). The getIndexVersion() method remains intact. A notion of equivalence of Jandex objects was added. This is useful when building more advanced layers on top of Jandex that deal with annotation overlays and similar things. If you’re interested, see the EquivalenceKey class. The methods on IndexView that accept a class name as a DotName now have more convenient overloads that accept a String and even Class<?>. If you search the index for classes that you have on your classpath, using these new methods can simplify your code. For example, instead of index.getClassByName(DotName.createSimple(MyClass.class.getName())), you can call index.getClassByName(MyClass.class). The method ClassInfo.isInterface() was added. It can be used to determine whether given ClassInfo actually represents an interface. The ClassInfo.memberClasses() was added, which returns a set of DotNames of member classes of given class. To inspect those member classes more deeply, you need to look them up in an Index. The class JandexReflection was added, containing some utility methods to load classes corresponding to Jandex ClassInfo or Type. The classes are by default loaded from TCCL, but if there’s none, the class loader that loaded JandexReflection itself is used. Summary Jandex 3.0.0 contains many interesting features and improvements. This unfortunately required a few breaking changes. Here’s the recommended migration path: Upgrade to Jandex 2.4.3.Final. This release deprecates some of the methods that are changed in Jandex 3.0.0 and offers replacements. Notably, this includes ClassInfo.annotations() (use annotationsMap() instead) and MethodInfo.parameters() (use parameterTypes() instead). Make sure you don’t use any deprecated Jandex methods. Make sure you don’t use Indexer.index()'s or indexClass()'s return value. At this point, if you compile your code against Jandex 2.4.3.Final, it will most likely run just fine against both 2.4.3.Final and 3.0.0. Exceptions include: if you implement IndexView (there are new methods) or if you use the Jandex Type hierarchy extensively (you’ll need to handle TypeVariableReference). Upgrade to Jandex 3.0.0. Configure Maven Enforcer plugin to ban org.jboss:jandex from getting into your dependency tree. With the exception of situations listed in the previous item, your code should compile and run without an issue. Profit! With this release, Jandex also has a new documentation site. It is currently rather incomplete, but that will hopefully improve over time. Jandex javadoc was also improved on many places, and remains the go-to reference. If you experience any troubles, or if you have any exciting ideas for Jandex, please file an issue. ### [Fault Tolerance 5.5](/blog/fault-tolerance-5-5/) Today, we announce the release of SmallRye Fault Tolerance 5.5.0. This release includes one new feature: support for Micrometer. It is a safe upgrade for everyone using SmallRye Fault Tolerance 5.4.x, but note that transitive dependencies have changed a little. See below for more information. Micrometer SmallRye Fault Tolerance has always supported MicroProfile Metrics. In this version, we add support for Micrometer. The set of metrics emitted to Micrometer is the same as the set of metrics emitted to MicroProfile Metrics, using the same metric names and tags. Metric types are also mapped as closely as possible. More information about that can be found in the documentation. Support for Micrometer is added mainly for Quarkus, which strives to replace MicroProfile Metrics with Micrometer. Note that Quarkus does its own integration of SmallRye Fault Tolerance. The CDI Portable Extension present in SmallRye Fault Tolerance, which other integrators use, still assumes usage of MicroProfile Metrics, and does the integration accordingly. That is, if you integrate SmallRye Fault Tolerance and are fine with using MicroProfile Metrics, you don’t have to do anything (except managing dependencies correctly, see below). More information about metrics integration is available in the documentation. Transitive dependencies Note that in previous versions, depending on SmallRye Fault Tolerance brought in the MicroProfile Metrics API artifact, org.eclipse.microprofile.metrics:microprofile-metrics-api, transitively. With the addition of Micrometer support, this is no longer true. Depending on SmallRye Fault Tolerance 5.5 no longer brings in any metrics dependency. Dependency management has always been a responsibility of integrators. They now have to make sure the correct metrics API dependency is present, which should typically be rather straightforward. ### [Fault Tolerance 5.4.1](/blog/fault-tolerance-5-4-1/) Today, we announce the release of SmallRye Fault Tolerance 5.4.1. This is a small release with a few improvements. It is a safe upgrade for everyone using SmallRye Fault Tolerance 5.4.0. Deployment-time discovery of methods annotated with @ApplyFaultTolerance was fixed. This doesn’t change runtime behavior, because guarded methods that were not discovered during deployment are registered lazily at runtime. Some trace-level logging messages were promoted to the debug level, and were enhanced with a description of the guarded method. For the purpose of upcoming Quarkus dev UI for SmallRye Fault Tolerance, the entire effective fault tolerance configuration is now visible from outside. Some internal build-related improvements were also made. ### [Fault Tolerance 5.4](/blog/fault-tolerance-5-4/) Today, we announce the release of SmallRye Fault Tolerance 5.4.0. This release includes several new features and fixes related to the programmatic API. It should be a safe upgrade for everyone using SmallRye Fault Tolerance 5.3.x. Reusable, preconfigured fault tolerance strategies In SmallRye Fault Tolerance 5.3.0, we introduced the programmatic API. In this release, we augment that with a declarative way of applying programmatically created fault tolerance! This allows centralizing fault tolerance configuration, as well as sharing fault tolerance state, all in a nice declarative fashion consistent with MicroProfile Fault Tolerance. Let’s demonstrate it with an example. First, you have to create a bean of type FaultTolerance with an @Identifier qualifier: @ApplicationScoped public class PreconfiguredFaultTolerance { @Produces @Identifier("my-fault-tolerance") public static final FaultTolerance<String> FT = FaultTolerance.<String>create() .withRetry().maxRetries(2).done() .withFallback().handler(() -> "fallback").done() .build(); } It is customary to create the bean by declaring a static producer field, which is what we’ve done here. Once we have that, we can apply my-fault-tolerance to synchronous methods that return String: @ApplicationScoped public class MyService { @ApplyFaultTolerance("my-fault-tolerance") public String doSomething() { ... } } See the documentation for more information. Exception decisions in programmatic API The circuit breaker, fallback, and retry fault tolerance strategies allow configuring what happens on certain exceptions. Both the declarative and programmatic API allow configuring a set of exception classes that are considered expected and unexpected. With this release, the programmatic API also lets you supply a simple exception predicate, which allows expressing more complex exception decisions. For example: Callable<String> guarded = FaultTolerance.createCallable(this::action) .withFallback().handler(this::fallback).when(e -> e instanceof RuntimeException).done() .build(); Of course, the value of this approach is that the predicate may be more complex than a simple instanceof check. Support for Kotlin suspending functions SmallRye Fault Tolerance already supports some asynchronous types on top of the CompletionStage type mandated by the MicroProfile Fault Tolerance specification. Specifically, there’s support for Mutiny and RxJava 3 and more could easily be added if needed. In this release of SmallRye Fault Tolerance, a new module smallrye-fault-tolerance-kotlin is added that provides support for Kotlin suspend functions. They are also considered asynchronous, so fault tolerance applies across suspension points, like you’d expect. For example: @ApplicationScoped open class MyService { @Retry(maxRetries = 2) @Fallback(fallbackMethod = "helloFallback") open suspend fun hello(): String { delay(100) throw IllegalArgumentException() } private suspend fun helloFallback(): String { delay(100) return "hello" } } Others The SmallRye Fault Tolerance documentation of the programmatic API recommends to store FaultTolerance instances into static fields. This has some interesting implications. Specifically, the entire fault tolerance chain is built in the static initializer, and that includes looking up several beans from the CDI container and possibly even creating a thread. That is problematic in Quarkus when compiling to a native image, because static initialization code is executed during native image build. In this release of SmallRye Fault Tolerance, this problem is fixed. Almost all of the initialization is deferred to runtime. All in all, upgrading to 5.4.0 is very much recommended. As described above, there are certain new things, so if you encounter any bugs, please let us know in the issue tracker! We’re still very much interested in any feedback on the programmatic API. ### [Fault Tolerance 5.3.2](/blog/fault-tolerance-5-3-2/) Today, we announce the release of SmallRye Fault Tolerance 5.3.2. This is a small release with one bug fix. It is a safe upgrade for everyone using SmallRye Fault Tolerance 5.3.1. In SmallRye Fault Tolerance 5.3, we revamped the support for additional async types. During that refactoring, we introduced a bug that manifests in environments with security manager enabled. In this release, the bug is fixed. ### [Fault Tolerance 5.3.1](/blog/fault-tolerance-5-3-1/) Today, we announce the release of SmallRye Fault Tolerance 5.3.1. This is a small release with one bug fix. It is a safe upgrade for everyone using SmallRye Fault Tolerance 5.3.0. In SmallRye Fault Tolerance 5.3, we revamped the support for additional async types. During that refactoring, we introduced a bug that manifests in environments with complex classloading requirements, such as WildFly. In this release, the bug is fixed. Additionally, the programmatic API documentation was slightly improved. ### [Fault Tolerance 5.3](/blog/fault-tolerance-5-3/) Today, we announce the release of SmallRye Fault Tolerance 5.3.0. This release includes one big new feature, the programmatic API, and several smaller additions and fixes. It should be a safe upgrade for everyone using SmallRye Fault Tolerance 5.2.1. Programmatic API Since the very beginning, SmallRye Fault Tolerance has implemented the MicroProfile Fault Tolerance declarative, annotation-based API. It also has several SmallRye-specific additions to this API, such as retry backoff strategies or circuit breaker maintenance. With this release, SmallRye Fault Tolerance adds an alternative, programmatic API. It has extensive documentation, so we’ll just provide a short overview here. Let’s start with an example: public class MyService { private static final FaultTolerance<String> guard = FaultTolerance.<String>create() .withCircuitBreaker().done() .withFallback().handler(() -> "fallback").done() .build(); public String hello() throws Exception { return guard.call(externalService::hello); } } The important part of this snippet is the guard variable. It contains a FaultTolerance instance, which is basically a configured set of fault tolerance strategies. The builder API allows creating the same fault tolerance strategies as the annotation-based API of MicroProfile Fault Tolerance. Order of with* method invocations doesn’t matter, the fault tolerance strategies are ordered according to the MicroProfile Fault Tolerance specification. The FaultTolerance interface includes methods to run a Callable, Supplier or Runnable and guard them. That’s what guard.call(...) does in the body of the hello method. A FaultTolerance instance created like this may be used to guard multiple different actions. If you only need to guard a single action, the previous example can be shortened to: public class MyService { private final Callable<String> guard = FaultTolerance.createCallable(externalService::hello) .withCircuitBreaker().done() .withFallback().handler(() -> "fallback").done() .build(); public String hello() throws Exception { return guard.call(); } } Similarly to the set of FaultTolerance methods to guard various types of actions, there’s a set of create* static methods to create a Callable, Supplier or Runnable. There’s also a set of createAsync* static methods to guard asynchronous actions using CompletionStage. Mutiny support The smallrye-fault-tolerance-mutiny artifact, also described below in the section on additional async types, contains a MutinyFaultTolerance interface. That interface contains create* static methods to guard asynchronous actions that return the Mutiny Uni type. Events The programmatic API has one feature that the declarative API doesn’t have: ability to observe certain events. For example, when configuring a circuit breaker, it is possible to register a callback for circuit breaker state changes or for a situation when an open circuit breaker prevents an invocation. When configuring a timeout, it is possible to register a callback for when the invocation times out, etc. etc. For example: private static final FaultTolerance<String> guard = FaultTolerance.<String>create() .withTimeout().duration(5, ChronoUnit.SECONDS).onTimeout(() -> ...).done() .build(); Circuit breaker maintenance There’s one exception to the above claim that the declarative API isn’t able to observe events. With this release, CircuitBreakerMaintenance gains a method to observe circuit breaker state changes. No other events are exposed to the declarative API at the moment. Note that the programmatic API also has a method to obtain CircuitBreakerMaintenance: FaultTolerance.circuitBreakerMaintenance(). This methods returns the same object that you can @Inject, because circuit breakers created by the programmatic API and declarative API are stored in the same registry. Inspecting exception causes The @CircuitBreaker, @Fallback and @Retry fault tolerance strategies allow declaring the set of exception types for which the strategy should apply (or be ignored). When an exception is thrown, its class is checked for presence in one of these sets, and the strategy behaves accordingly. This works fine, until wrapper exceptions come to play. In certain contexts, the true exceptions are often (or always) wrapped into another exception. In such situation, configuring when a fault tolerance strategy should apply or be ignored becomes nearly impossible. In this release, SmallRye Fault Tolerance adds a non-standard feature to solve this problem. In the non-compatible mode, if the class of the thrown exception isn’t present in either of the two sets, the cause chain of the exception is inspected automatically. Revamped async types support SmallRye Fault Tolerance offers support for more asynchronous types than just MicroProfile Fault Tolerance mandated CompletionStage. So far, that support was based on the SmallRye Reactive Converters project, because that offers conversion between CompletionStage and other types. Asynchronous implementations of fault tolerance strategies in SmallRye Fault Tolerance are based on CompletionStage, so that seems like a natural fit, but it has one issue. In case the other async type is lazy (which is always the case with RxJava, Mutiny or Reactor), resubscription doesn’t work. In this release, the dependency on SmallRye Reactive Converters is dropped. Instead, SmallRye Fault Tolerance has its own set of support libraries for various reactive types. These support libraries convert between types lazily, so resubscription works properly. Specifically, there’s smallrye-fault-tolerance-mutiny for Mutiny and smallrye-fault-tolerance-rxjava3 for RxJava 3. Support for RxJava 1, RxJava 2 and Reactor was dropped, but may easily be added back if there’s a need. Others If you use @Fallback with a FallbackHandler class, you might have found that such fallback handler triggers a validation error when guarding methods that declare a primitive return type (or void). This has been fixed. A FallbackHandler that declares a wrapper type (such as java.lang.Integer) now correctly matches a corresponding primitive type (such as int). Upgrade to 5.3.0 is very much recommended. As described above, there are certain new things, so if you encounter any bugs, please let us know in the issue tracker! We’d be specifically interested in any feedback on the programmatic API. This is very new, so you have a unique chance to influence its future! ### [Log4j2 Vulnerability and SmallRye](/blog/log4j2-vulnerability/) On Thursday (December 9th), a 0-day exploit in the popular Java logging library log4j (version 2) was discovered that results in Remote Code Execution (RCE) by logging a certain string. Please check the following links for additional information on this vulnerability: CVE-2021-44228 Detail Remote code injection in Log4j Log4Shell: RCE 0-day exploit found in log4j 2, a popular Java logging package If you are using log4j2, or have it available in your runtime we advise you to update it to 2.15.0 as soon as possible. What does this mean for SmallRye? SmallRye libraries do not include or use any log4j artifacts in their runtime dependencies. Below you can find a detailed report for each SmallRye dependency (we used the Maven Dependency Plugin to search for possible inclusions): smallrye-async-api smallrye-common smallrye-config smallrye-context-propagation smallrye-converters smallrye-fault-tolerance smallrye-graphql smallrye-health smallrye-jwt smallrye-maven-plugin smallrye-metrics smallrye-mutiny smallrye-mutiny-vertx-bindings smallrye-mutiny-zero smallrye-open-api smallrye-opentelemetry smallrye-opentracing smallrye-parent smallrye-reactive-converters smallrye-reactive-messaging smallrye-safer-annotations smallrye-stork smallrye-testing SmallRye Dependency Log4j2 Report Note The command used was mvn org.apache.maven.plugins:maven-dependency-plugin:2.8:tree -Dincludes=org.apache.logging.log4j::: -Dverbose We were able to find that smallrye-reactive-messaging-kafka and smallrye-stork-service-discovery-eureka reference log4j2 artifacts, but only in the test scope, so this is not an issue. Additionally, since all SmallRye projects receive dependabot updates, we can detect any possible updates to log4j2 dependencies with the following Github Report. Indeed, there were two updates sent by dependabot to smallrye-mutiny-vertx-bindings, but these updates target the dependencies of a Maven plugin execution, so again, not an issue for runtime. Additional Information Even if SmallRye itself is not directly affected by this vulnerability, the runtime where you are running may be compromised. Check if this is the case and upgrade the log4j2 version. Feel free to reach out to the SmallRye team if you experience any issue with any of the SmallRye libraries to the SmallRye Mailing List. ### [Fault Tolerance 5.2.1](/blog/fault-tolerance-5-2-1/) Today, we announce the release of SmallRye Fault Tolerance 5.2.1. This is a small release with one bug fix. It is a safe upgrade for everyone using SmallRye Fault Tolerance 5.2.0. In SmallRye Fault Tolerance 5.0, we introduced support for the @Blocking and @NonBlocking annotations. From SmallRye Fault Tolerance perspective, these annotations make sense for methods that return an async type, such as CompletionStage or Uni. Naturally, we added validation, so that if the annotation was present on a method with some other return type, deployment would fail. This is actually problematic, because these annotations are generic. They are used by other frameworks and libraries (such as SmallRye Reactive Messaging or RESTEasy Reactive). In such case, SmallRye Fault Tolerance should just ignore them. However, if the annotation was present on a method that also applied some fault tolerance annotation, SmallRye Fault Tolerance would run the validation and fail the deployment. In this release, the validation is simply removed. SmallRye Fault Tolerance can’t know if the annotation is meant for some other framework or not. Additionally, we fixed some typos in the documentation. ### [Fault Tolerance 5.2](/blog/fault-tolerance-5-2/) Today, we announce the release of SmallRye Fault Tolerance 5.2.0. This release includes several new features and fixes. It is a safe upgrade for everyone using SmallRye Fault Tolerance 5.1.0. Backoff strategies for @Retry The @Retry annotation in MicroProfile Fault Tolerance supports a single backoff strategy: constant. That is, the delay between all retry attempts is identical (with the exception of a random jitter). SmallRye Fault Tolerance now offers 3 annotations to specify a different backoff strategy: @ExponentialBackoff @FibonacciBackoff @CustomBackoff One of these annotations may be present on a program element annotated @Retry, and it modifies the retry behavior. For example: package com.example; @ApplicationScoped public class MyService { @Retry @ExponentialBackoff public void hello() { ... } } With @ExponentialBackoff, the delays between retry attempts will grow exponentially. With @FibonacciBackoff, the delays will grow per the Fibonacci sequence. With @CustomBackoff, it is possible to implement completely custom backoff strategy. See the documentation for more information. @Blocking and @NonBlocking on classes Previously, we only documented (and tested) the @Blocking and @NonBlocking annotations on methods. However, these annotations can be placed on classes as well, so in this release, we documented that and tightened some validation. Previously, if you addded both of these annotations to the same method, SmallRye Fault Tolerance wouldn’t complain, even though this is clearly a mistake. This situation is now detected and application deployment ends with an error. However, if one of these annotations is placed on a class and the other on a method, that is a perfectly valid situation. In such case, the annotation on method has priority over the one on class. For example: package com.example; @ApplicationScoped @NonBlocking public class MyService { @Retry @Blocking public void hello() { ... } } Here, the hello method is treated as @Blocking, but other methods would inherit the @NonBlocking annotation from the class. See the documentation for more information. Non-compatible mode for determining asynchrony In addition to the @Asynchronous, @Blocking and @NonBlocking annotations, SmallRye Fault Tolerance now offers a mode where method asynchrony is determined solely from the its return type. This mode is not compatible with the MicroProfile Fault Tolerance specification and doesn’t pass 2 tests in the TCK. For that reason, this mode is disabled by default. To enable it, set the configuration property smallrye.faulttolerance.mp-compatibility to false. When the non-compatible mode is enabled, methods that have some fault tolerance strategy and return CompletionStage will not be offloaded to a thread pool, yet will have asynchronous fault tolerance applied automatically. In other words, they will be treated as if they were annotated @NonBlocking. For example: @ApplicationScoped public class MyService { @Retry CompletionStage<String> hello() { ... } } The hello method here will be executed on the original thread (as if it was annotated @NonBlocking) and will have asynchronous fault tolerance applied. That is, if the returned CompletionStage completes with an exception, it will be retried. (Per the MicroProfile Fault Tolerance specification, retry shouldn’t happen in such case. The compatible mode conforms to the specification, but we find that behavior less and less appropriate.) Quarkus will enable this mode by default in the 2.1.0.Final release. See the documentation for more information. Others Together with the new features described above, we have also performed a major internal refactoring. The configuration system, the single last remnant of SmallRye Fault Tolerance 2.x, has been rewritten from scratch. Instead of storing configuration values into a Map<String, Object>, the new system is based on configuration interfaces. Implementations of these interfaces are automatically generated during SmallRye Fault Tolerance build, using an annotation processor. See the documentation for more details if you’re interested. Furthermore, we have fixed a small bug in @Fallback validation. If you had a method guarded with @Fallback that returned a raw type (such as List), and its fallback method retured a parameterized type (such as List<String>), the validation code would enter an infinite regress. This case is now handled properly. Upgrade to 5.2.0 is very much recommended. As described above, there are certain new things, so if you encounter any bugs, please let us know in the issue tracker! ### [Fault Tolerance 5.1](/blog/fault-tolerance-5-1/) Today, we announce the release of SmallRye Fault Tolerance 5.1.0. This release includes some important bug fixes and one new feature. It is a safe upgrade for everyone using SmallRye Fault Tolerance 5.0.0. Java 16 support SmallRye Fault Tolerance includes a small utility class that helps calling default methods when they are declared as fallback methods with @Fallback. This class uses reflection to crack open some internal JDK classes on Java 8. Naturally, since Java 9, the JDK started complaining, and since Java 16, this became an error. For that reason, we have a variant of that utility class that uses Java 9 public API, and the main SmallRye Fault Tolerance JAR has, for a long time, been a multi-release JAR. Unfortunately, we introduced a bug in SmallRye Fault Tolerance 4.3.1. This bug causes the main SmallRye Fault Tolerance JAR to omit the META-INF/versions/9 directory, and so the Java 8 variant of the class is the only one present. In the 5.1.0 release, we fixed that bug and made sure the SmallRye Fault Tolerance release process is executed with Java 11. Hence, SmallRye Fault Tolerance should once again work as intended on all Java versions, particularly on Java 16. Note that even though we run the release process with Java 11, we still produce Java 8 bytecode. Java 8 is still supported with SmallRye Fault Tolerance 5.1.0, even though we may drop this support in future versions. Vert.x integration In certain situations, SmallRye Fault Tolerance runs @NonBlocking methods on a different thread than the original call was made on. This includes: @Retry methods, where a non-zero retry delay is configured (the delay must not block); @Bulkhead methods, where a non-zero bulkhead queue is configured (if the invocation is queued). By default, we run such guarded methods on a thread pool provided by the integrator. In this release, we provide an integration API for event loops, as well as an implementation of this API for Vert.x. With this integration enabled, invocations of @NonBlocking methods made on an event loop thread are always executed on the same event loop thread. For more information, see user documentation and integration documentation. Others We have also significantly expanded our CI coverage. We now run tests with: all Java LTS releases we care about (at this moment, Java 8 and 11); the latest Java release (at this moment, Java 16); the upcoming Java release (at this moment, Java 17-ea). All of this on Linux, Windows and macOS, thanks to GitHub Actions. (In fact, we currently don’t run tests with Java 17-ea, because of a bug in JBoss Class File Writer. That should be resolved shortly, and we are not aware of any other issue with Java 17-ea.) With this CI coverage expansion, we found and fixed a particularly nasty concurrency issue in handling @Timeouts on Future-returning methods when @Retry is present. @Bulkheads on Future-returning methods, in presence of @Retry, were fixed as well. Upgrade to 5.1.0 is therefore very much recommended! ### [Fault Tolerance 5.0](/blog/fault-tolerance-5-0/) Roughly a year ago, we announced the release of SmallRye Fault Tolerance 4.0, the new implementation of Eclipse MicroProfile Fault Tolerance. Today, we bring you version 5.0, an evolution of the 4.x stream that fully implements MicroProfile Fault Tolerance 3.0 and brings a lot of improvements and even new features. These new features are not present in the MicroProfile Fault Tolerance specification, but were requested by users, especially in the Quarkus community. In addition, the API for integrators has been simplified significantly, and the first version of documentation is also ready. Let’s take a look. MicroProfile Fault Tolerance 3.0 From user’s perspective, MicroProfile Fault Tolerance 3.0 is a relatively small release, including just two important changes: metrics overhaul, and lifecycle specification for circuit breakers and bulkheads. It is a major release because the metrics changes are very much backwards incompatible, so pay attention to that. Metrics overhaul The fault tolerance metrics now take advantage of tags. Most importantly, the full method name used to be a part of the metric name, but it’s now a metric tag. For example, suppose we have a method guarded with the @Timeout strategy: @Singleton public class MyService { @Timeout public String hello() { ... } } Previously, if you wanted to know how many times this method timed out, you’d have to look at the metric called ft.com.example.MyService.hello.timeout.callsTimedOut.total. With MicroProfile Fault Tolerance 3.0, you need to look at ft.timeout.calls.total{method="com.example.MyService.hello", timedOut="true"} instead. You can find all the new metric names and possible tags in the MicroProfile Fault Tolerance 3.0 specification. Also, fault tolerance metrics moved from the application scope to base. Lifecycle specification for circuit breakers and bulkheads Previously, MicroProfile Fault Tolerance didn’t specify lifecycle for stateful fault tolerance strategies, that is, circuit breakers and bulkheads. This becomes important when you have @RequestScoped beans, such as: @RequestScoped public class MyService { @CircuitBreaker public String hello() { ... } } You get a new instance of the bean for each request, and the MicroProfile Fault Tolerance specification didn’t say whether all such instances share the same circuit breaker for the hello method, or if each instance has its own. The specification now mandates that all instances share the same circuit breaker. Bulkheads behave identically. This behavior was actually implemented by SmallRye Fault Tolerance since the beginning, so no behavioral change for you. SmallRye Fault Tolerance improvements The SmallRye Fault Tolerance 5.0 release brings a lof of additional improvements, both internal and user-facing. Changes that concern SmallRye Fault Tolerance integrators are described in more detail in a subsequent section. Circuit breaker maintenance We have previously introduced a way to observe circuit breaker state changes, using the CircuitBreakerStateChanged CDI event. This was subsequently deprecated, because we found a better way. In this release, the CircuitBreakerStateChanged CDI event is removed, and a new API for circuit breaker maintenance is introduced. Circuit breakers can now be given a name using the @CircuitBreakerName annotation. Afterwards, you can @Inject a CircuitBreakerMaintenance and use its currentState method to obtain current status of the circuit breaker. In addition, CircuitBreakerMaintenance also allows you to reset any given named circuit breaker (reset), or all circuit breakers (resetAll), to the initial state. Read the documentation for more information and examples. @Blocking and @NonBlocking In addition to the MicroProfile Fault Tolerance @Asynchronous annotation, we also introduce support for the @Blocking and @NonBlocking annotations from SmallRye Common. @Blocking means that the annotated method blocks and hence its execution must be offloaded to another thread. This is basically equivalent to @Asynchronous. On the other hand, @NonBlocking means that the annotated method doesn’t block and hence execution doesn’t have to be moved to another thread, yet all asynchronous fault tolerance behaviors are still supported. Note that these annotations are only taken into account if the annotated method also applies some other fault tolerance strategy, such as @Fallback or @Retry, and if the method returns CompletionStage (or some of the additional asynchronous types as described below). If there’s no fault tolerance annotation, or if the method doesn’t return CompletionStage, SmallRye Fault Tolerance will ignore the @Blocking and @NonBlocking annotations completely. Read the documentation for more information and examples. Additional asynchronous types In addition to CompletionStage, SmallRye Fault Tolerance now supports additional asynchronous types from libraries such as RxJava, Mutiny or Reactor. Note that only single-valued types, such as Single or Uni, are supported; stream-like types are not, because their semantics can’t be easily expressed in terms of CompletionStage. This support is based on the SmallRye Reactive Converters project, so you have to make sure that the corresponding converter library is present. Integrators may include some converters by default if they choose so. Read the documentation for more information and examples. Other improvements Exception handling in half-open circuit breakers was fixed. Previously, half-open circuit breakers would treat all exceptions as failures, which is wrong. Even in the half-open state, circuit breakers have to consider the failOn and skipOn configuration. This bug was not caught, because the MicroProfile Fault Tolerance TCK doesn’t have a test. That is something we are also going to fix. Circuit breakers were also improved to reject excess attempts in the half-open state. Previously, half-open circuit breakers would allow all invocations to go through, which kinda defeats the purpose of the half-open state. This was improved to only allow the first successThreshold invocations (also called "probe invocations"); the excess ones are outright rejected. It is only after moving to the closed state when all invocations are allowed. All CompletionStage fault tolerance strategies were examined and improved to avoid premature thread offload. This was required for the @NonBlocking support described above, but it’s also an important optimization. Thread pool usage was radically improved. Previously, SmallRye Fault Tolerance would use 1 thread pool for executing @Asynchronous methods, 1 thread pool for watching for timeouts, and 1 thread pool for each thread pool style bulkhead. Now, SmallRye Fault Tolerance uses a single thread pool for everything. Thread pool style bulkheads were also significantly optimized. The metrics subsystem was completely rewritten. Trace logging has been added for all core implementations of fault tolerance strategies. We also started using JBoss Logging Tools to generate logger implementations. Integration changes How SmallRye Fault Tolerance can be integrated into a runtime has changed in two important ways: the thread pool integration is now based on CDI, and some additional dependencies are required. Previously, the thread pool integration was based on ServiceLoader. Integrators had to provide implementation of the ExecutorFactory interface, which allowed customizing how all the different thread pools are created. With the 5.0 release, SmallRye Fault Tolerance no longer insists on creating its own thread pools. Instead, it works with a single thread pool and expects integrator to provide it via CDI. To do that, integrators should provide a CDI bean implementing the AsyncExecutorProvider interface. This implementation should be @Singleton, must be marked as alternative and selected globally for the application. The interface has one method that returns the thread pool which the integrator desires to use for fault tolerance. If the integrator doesn’t want to manage their own thread pool for fault tolerance, they can subclass DefaultAsyncExecutorProvider. This at least allows customizing the ThreadFactory. As described above, the SmallRye Reactive Converters project is used to add support for additional asynchronous types. This means that SmallRye Fault Tolerance requires the io.smallrye.reactive:smallrye-reactive-converter-api artifact to be present. Presence of Reactive Converter API implementations is optional, but the API itself is mandatory. Read the integration documentation for more information. Summary Looking back at the 4.0 announcement, we have since implemented almost all the planned improvements in SmallRye Fault Tolerance internals. On the other hand, the user-facing improvements we planned had to be postponed — but we implemented other user-facing improvements instead. We still intend to work on @FailFast or @AdaptiveBulkhead, but feature requests or bug reports by actual users will always have priority. With that in mind, please don’t hesitate to get in touch. You can use the SmallRye Fault Tolerance issue tracker, the Zulip Chat, the SmallRye Fault Tolerance Gitter, or the SmallRye mailing list. ### [Fault Tolerance 4.3.1](/blog/fault-tolerance-4-3-1/) Today, we announce the release of SmallRye Fault Tolerance 4.3.1. This is a small release with a couple of bug fixes and one API deprecation. It is a safe upgrade for everyone using SmallRye Fault Tolerance 4.3.0. In the previous release, we introduced an experimental API for observing circuit breaker state changes. The CircuitBreakerStateChanged event type is now deprecated and will be removed in a subsequent release. At the same time, we will introduce a new API for accessing circuit breaker maintenance features: observing its current state and resetting to the initial state. If you want to know more, feel free to watch issue #280. Also, to slightly improve quality of life, starting with this release, SmallRye Fault Tolerance will log its version number during boot. ### [SmallRye Config 1.9 Released](/blog/smallrye-config-1-9/) In SmallRye Config 1.9 we continue our innovation and experimentation model, by bringing additional features and enhancements to the API. This release introduces the following big changes: Config Mappings A Config Mapping provides a way to group multiple configuration properties into a single cohesive API. A Config Mapping requires a simple interface with minimal metadata configuration. @ConfigMapping(prefix = "server") interface Server { String host(); int port(); } The Server interface retrieves and maps configuration properties with the name server.host into the Server.host() and server.port into Server.port() method. The configuration property name to lookup builds from the @ConfigMapping annotation prefix and the method name with . (dot) as the separator. The @ConfigMapping annotation is used to auto-discover and register these mapping interfaces in a CDI aware environment. In non-CDI environments, register the Config Mapping via SmallRyeConfigBuilder#withMapping. To retrieve such Config Mapping, a simple @Inject in any CDI aware bean is enough: @Inject Server server; void businessMethod() { String host = server.host(); } To retrieve the Config Mapping in non-CDI environments use the API io.smallrye.config.SmallRyeConfig#getConfigMapping: SmallRyeConfig config = (SmallRyeConfig) ConfigProvider.getConfig(); Server server = config.getConfigMapping(Server.class); Additionally, Config Mappings also support: Automatic conversion of the configuration type. Nested Config Mapping groups. Validate if configuration properties exist at the startup. Map, Optional, and primitive types. @WithName to override the property name. @WithConverter to override the converter to use. @WithDefault to set the default value if none is found in the config sources. Combining all of these features, we can write a Config Mapping that looks like this: @ConfigMapping(prefix = "server") public interface Server { String host(); int port(); @WithConverter(DurationConverter.class) Duration timeout(); @WithName("io-threads") int threads(); Map<String, String> form(); Optional<Ssl> ssl(); Optional<Proxy> proxy(); Log log(); interface Ssl { int port(); String certificate(); @WithDefault("TLSv1.3,TLSv1.2") List<String> protocols(); } interface Proxy { boolean enable(); } interface Log { @WithDefault("false") boolean enabled(); @WithDefault(".log") String suffix(); @WithDefault("true") boolean rotate(); @WithDefault("COMMON") Pattern pattern(); enum Pattern { COMMON, SHORT, COMBINED, LONG; } } } For additional information, check out our documentation about Config Mappings and the example in the https://github.com/smallrye/smallrye-config/tree/main/examples/mapping SmallRye Config Github repo. In MicroProfile Config 2.0, an initial version for this feature will be available. It doesn’t support all the features implemented in SmallRye Config, but the plan is to keep evolving and add more functionality based on the feedback of the community. You can read more about it here. Configurable Config Sources A highly requested feature is the ability to configure custom Config Sources, meaning it should be possible to retrieve configuration values from other sources before building our own. Take for instance a Database based Config Source. Such a source requires additional configurations like URL, username, and password to connect to the database. Where do we set these configurations? The new ConfigSourceFactory API provides a context with access to the currently available configuration. With a ConfigSourceFactory, it is possible to bootstrap a ConfigSource that configures itself with other sources. The ConfigSourceFactory requires the implementation of a single method ConfigSource getConfigSource(ConfigSourceContext context): @Override public class ConfigMapConfigSourceFactory implements ConfigSourceFactory { @Override public ConfigSource getConfigSource(final ConfigSourceContext context) { final ConfigValue value = context.getValue("config.map.dir.source"); if (value == null || value.getValue() == null) { throw new IllegalArgumentException("CONFIG_MAP_DIR_SOURCE not defined"); } return new FileSystemConfigSource(value.getValue()); } } The provided ConfigSourceContext may call a single method ConfigValue getValue(String name). This method lookups configuration names in all sources already initialized by the Config even if they have a lower priority than the one defined in the ConfigSourceFactory. A`ConfigSource` produced by a ConfigSourceFactory is not taken into account to configure other sources produced by lower priority ConfigSourceFactory. To register a ConfigSourceFactory use the standard Java ServiceLoader. For additional information, check out our documentation about Config Mappings and the example in the https://github.com/smallrye/smallrye-config/tree/main/examples/configmap SmallRye Config Github repo. Default Values Right now, the only way to set a default value for a configuration to use the org.eclipse.microprofile.config.inject.ConfigProperty#defaultValue. This has a few limitations. It doesn’t work in the programmatic lookup or if we are using the annotation and have to inject the same property in multiple places, we need to duplicate the default value in each injection point. Adding the configuration values into microprofile-config.properties to act as a default is not optimal either, since they may override lower priority custom sources. SmallRye Config adds a simple API to set such default values, with SmallRyeConfigBuilder#withDefaultValue(String name, String value) or SmallRyeConfigBuilder#withDefaultValue(Map<String, String> defaultValues). Default values for any configuration name can then be supplied with these APIs. SmallRye Config will only fallback to these default if no value is found in the available sources. The Default values API also supports name patterns. For instance a withDefaultValue("smallrye.*", "1234") provides default values for any configuration name with the prefix smallrye. Summary All the new features detailed here are experimental. The team is happy with them, and they had careful consideration when designed. We cannot guarantee that they won’t suffer any changes in the next few releases, especially considering that the SmallRye team is also pushing to have these added to the MicroProfile Config specification, which may require some changes. This shouldn’t discourage developers to use these new features. We believe these add a lot of utility and improve the developer experience when setting configurations in applications. A handful of other small improvements and bugs fixes are also included in this release. Check them out in the Release Notes Please, feel free to drop us any feedback to the SmallRye Mailing List. Additional Resources GitHub Repository Release Notes Documentation ### [Fault Tolerance 4.2 & 4.3](/blog/fault-tolerance-4-2-and-4-3/) Today, we announce two new releases of SmallRye Fault Tolerance: 4.2.1 and 4.3.0. 4.2.1 This release includes bugfixes and component updates and is safe to use for everyone who uses Fault Tolerance 4.1.0, 4.1.1 and 4.2.0. The 4.2.0 release happened a few weeks ago and didn’t contain anything but bugfixes. With 4.2.1, we now use MicroProfile Fault Tolerance 2.1.1, which includes some TCK fixes. There is one small feature in the 4.2.1 release, which is interesting for integrators. If you integrate SmallRye Fault Tolerance and provide your own ExecutorFactory, you can now inherit from the DefaultExecutorFactory class and override the threadFactory method. This allows customizing the most important property: how do the thread pools create their threads. All the other thread pool settings will stay at the SmallRye Fault Tolerance defaults. Of course, you can still provide a your own ExecutorFactory and customize everything. 4.3.0 This release builds on 4.2.1 and adds one new feature: you can now observe when circuit breakers change their state. Let’s first take a look at the code. Let’s say we have a method doWork which is guarded by a circuit breaker, presumably because it reaches out to some external service: @ApplicationScoped public class MyService { @CircuitBreaker(...) public void doWork() { ... } } Now, there are metrics for how often the circuit breaker trips etc., but you might want to observe when the circuit breaker state changes directly. With SmallRye Fault Tolerance 4.3.0, that is now possible: circuit breaker state changes are emitted as CDI events. With an event observer, it’s easy to react to circuit breaker state changing: @ApplicationScoped public class MyServiceObserver { public void onStateChange(@Observes CircuitBreakerStateChanged event) { if (MyService.class.equals(event.clazz) && "doWork".equals(event.method.getName())) { System.out.println("!!! circuit breaker is now " + event.targetState); } } } Note that in this example, we make one simplifying assumption: that the MyService class only has one method called doWork. If it had multiple doWork methods, each having different signature and each having its own circuit breaker, we would have to distinguish between them in the observer. The CircuitBreakerStateChanged event type includes: the bean clazz, as java.lang.Class; the guarded method, as java.lang.reflect.Method; the targetState of the circuit breaker, as a simple enum CircuitBreakerState with 3 values: CLOSED, OPEN and HALF_OPEN. Experimental API The CircuitBreakerStateChanged and CircuitBreakerState classes are meant for direct consumption by end users. They are considered an experimental API, because we’re trying to find out how to best provide this feature. This also means that breaking changes are very much possible, when we learn how to improve the API. Your feedback is very important here! If you use a runtime such as Thorntail or Quarkus, they should provide you the correct dependency automatically, after they update to SmallRye Fault Tolerance 4.3.0. If you use SmallRye Fault Tolerance directly, you should note that these classes are located in a new artifact: smallrye-fault-tolerance-api. ### [SmallRye Config 1.8 Released](/blog/smallrye-config-1-8/) SmallRye Config version 1.8 was released a few days ago. The latest version of SmallRye Config introduced a few experimental changes to enhance the API and to make SmallRye Config more extensible. One of the experimental changes is the new interceptor model, to intercept the lookup of a configuration value. The ConfigSourceInterceptor The ConfigSourceInterceptor allows to intercept the resolution of a configuration name before the Config resolves the configuration value and before any conversion taking place. This is useful to implement features like property expansion or configuration profiles. Implementations of ConfigSourceInterceptor are loaded via the java.util.ServiceLoader mechanism and can be registered by providing a resource named META-INF/services/io.smallrye.config.ConfigSourceInterceptor, which contains the fully qualified ConfigSourceInterceptor implementation class name as its content. A single method must be implemented, ConfigValue getValue(ConfigSourceInterceptorContext context, String name). The ConfigSourceInterceptorContext is used to proceed with the interceptor chain. The chain can be short-circuited by returning an instance of ConfigValue. public interface ConfigSourceInterceptor extends Serializable { ConfigValue getValue(ConfigSourceInterceptorContext context, String name); } The ConfigValue objects hold information about the key name, value, config source origin, and ordinal. Additionally, the ConfigSourceInterceptor may also intercept resolution of configuration names or configuration values with the methods Iterator<String> iterateNames(ConfigSourceInterceptorContext context) and Iterator<ConfigValue> iterateValues(ConfigSourceInterceptorContext context). The Interceptor chain applies before any conversion takes place. Implementation With the Interceptor API, it becomes trivial to implement a logging mechanism and to find out which ConfigSource loaded the resolved config: public class LoggingConfigSourceInterceptor implements ConfigSourceInterceptor { private static final Logger LOG = Logger.getLogger("io.smallrye.config"); @Override public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { final ConfigValue configValue = context.proceed(name); final String key = configValue.getName(); final String value = configValue.getValue(); final String configSource = configValue.getConfigSourceName(); LOG.infov("The key {0} was loaded from {1} with the value {2}", key, configSource, value); return configValue; } } SmallRye Config does ship with its own logging interceptor, so you don’t need to implement one. Built-In Interceptors SmallRye Config provides the following built-in interceptors to expand its feature set: RelocateConfigSourceInterceptor ProfileConfigSourceInterceptor ExpressionConfigSourceInterceptor FallbackConfigSourceInterceptor LoggingConfigSourceInterceptor SecretKeyConfigSourceInterceptor Not every interceptor is registered by default. Only the ProfileConfigSourceInterceptor, ExpressionConfigSourceInterceptor and SecretKeyConfigSourceInterceptor are added on new instances of Config. Other interceptors require manual registration via the ServiceLoader mechanism. To learn more about all the built-in interceptors, please refer to the documentation page. Expression Expansion The ExpressionConfigSourceInterceptor provides expression expansion on configuration values. An expression string is a mix of plain strings and expression segments, which are wrapped into ${ …​ }. For instance, consider the following configuration properties file: my.prop=1234 expression=${my.prop} Then the expression configuration will be resolved and expanded to the value 1234. Additionally, the expression expansion engine supports the following segments: ${expression:value} - Provides a default value after the : if the expansion doesn’t find a value. ${my.prop${compose}} - Composed expressions. Inner expressions are resolved first. ${my.prop}${my.prop} - Multiple expressions. Configuration Profiles The ProfileConfigSourceInterceptor allows multiple configurations with the same name and selects them via a profile property. To be able to set properties with the same name, each property needs to be prefixed with % followed by the profile name and a dot: my.prop=1234 %dev.my.prop=5678 Lookup is always performed with the my.prop property name. To use the profile dev, the configuration smallrye.config.profile=dev has to be set in any valid ConfigSource. When looking up the property my.prop with the dev profile active, the value is 5678. Only one profile can be active at any given time. API Enhancements Aside from interceptors, a few additional API enhancements shipped with the latest version of SmallRye Config: ConfigValue - The ConfigValue is a metadata object that holds additional information after the lookup of a configuration. ConfigValueConfigSource - Extends the original ConfigSource to expose methods that return a ConfigValue. SmallRyeConfigBuilder#withSecretKeys - Hide configuration properties that contain passwords or other kinds of secrets to prevent accidental exposure of such values. Summary All the new features detailed here are experimental. The team is happy with them, and they had careful consideration when designed. We cannot guarantee that they won’t suffer any changes in the next few releases, especially considering that the SmallRye team is also pushing to have these added to the MicroProfile Config specification, which may require some changes. This shouldn’t discourage developers to use these new features. We believe these add a lot of utility and improve the developer experience regarding configuration of applications. Please, feel free to drop us any feedback in the SmallRye Mailing List. Additional Resources Release Notes Documentation ### [Health Groups - experimental MicroProfile Health extension in SmallRye](/blog/health-groups/) If you are reading this blog, you have probably already heard about Eclipse MicroProfile Health technology. In this article, we will introduce a new experimental extension to MicroProfile Health 2.2 called Health groups. All of the source code that we will present in this article is available at this GitHub repository https://github.com/xstefank/health-groups. MicroProfile 2.2 health checks As you know, to define a health check procedure in MicroProfile Health you need something like this: package io.xstefank; import org.eclipse.microprofile.health.HealthCheck; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.Readiness; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped // 1. CDI scope @Readiness // 2. Qualifier (Readiness, Liveness, Health) public class ReadinessHealthCheck implements HealthCheck { // 3. implements HealthCheck interface @Override public HealthCheckResponse call() { return HealthCheckResponse.up(ReadinessHealthCheck.class.getSimpleName()); } } So just to recap, to define a health check your class: needs to be a CDI bean needs to have one of the health qualifiers (Readiness, Liveness, or deprecated Health) must implement the HealthCheck interface This is everything that you can use in MicroProfile 2.2. But what if you have a use case that doesn’t fall into one of Readiness or Liveness categories? The answer is custom health groups. Health Groups SmallRye Health 2.2.0 (already included in Quarkus 1.4.0) comes with a new addition to this API called health groups. A health group is basically a custom group of health check procedures that the user defines based on individual needs. As you probably noticed, Readiness and Liveness health checks already represent two predefined health groups. With the health groups feature you can define as many additional health check groups as you need. Defining a health Group To define a health group you need only to declare at least one health check procedure that belongs to the health group: package io.xstefank; import io.smallrye.health.HealthGroup; import org.eclipse.microprofile.health.HealthCheck; import org.eclipse.microprofile.health.HealthCheckResponse; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped @HealthGroup("custom-group-1") public class CustomGroup1Check implements HealthCheck { @Override public HealthCheckResponse call() { return HealthCheckResponse.up(CustomGroup1HC.class.getSimpleName()); } } So the only difference now is the change of the qualifier for which we now use io.smallrye.health.HealthGroup. This qualifier takes a string argument representing the name of the health group. This is all that needs to be done to define a new custom health group and a health check procedure that belongs to it. Accessing custom health groups Accessing the custom health groups is done a similar manner to the original MicroProfile Health 2.2 health invocations. The URL to access a custom group is HOST:PORT/health/group/{group-name}. This will return all health check procedures belonging to the groups {group-name}. You can also find all health check procedures that belong to any of the custom defined health group by accessing HOST:PORT/health/group. Here is a summary of endpoints exposed in Quarkus 1.4.0: Path Health checks /health @Readiness, @Liveness, @Health /health/ready @Readiness /health/live @Liveness /health/group all @HealthGroup(*) /health/groups/group-name @HealthGroup("group-name") Combining different health groups You are allowed to use more than one qualifier on any health check procedure that you define. For instance: package io.xstefank; import io.smallrye.health.HealthGroup; import org.eclipse.microprofile.health.HealthCheck; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.Readiness; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped @HealthGroup("custom-group-1") @HealthGroup("custom-group-2") @Readiness public class CustomGroup2ReadinessCheck implements HealthCheck { @Override public HealthCheckResponse call() { return HealthCheckResponse.up(CustomGroup2ReadinessCheck.class.getSimpleName()); } } This procedure will now be available in custom-group-1, custom-group-2 and the readiness groups. /health/group { "checks": [ { "name": "CustomGroup1Check", "status": "UP" }, { "name": "CustomGroup2ReadinessCheck", "status": "UP" } ], "status": "UP" } /health/group/custom-group-1 { "checks": [ { "name": "CustomGroup1Check", "status": "UP" }, { "name": "CustomGroup2ReadinessCheck", "status": "UP" } ], "status": "UP" } /health/group/custom-group-2 { "checks": [ { "name": "CustomGroup2ReadinessCheck", "status": "UP" } ], "status": "UP" } /health/ready { "checks": [ { "name": "CustomGroup2ReadinessCheck", "status": "UP" }, { "name": "ReadinessHealthCheck", "status": "UP" } ], "status": "UP" } Where this can come particularly handy is if you want to reuse predefined readiness and liveness procedures for custom views or simplified processing. For example, if you have several liveness procedures one of which is not essential and takes a long time you may want to define a health group that will be excluding the expensive liveness health check computation. Summary We introduced the new experimental feature extending the MicroProfile Health 2.2 API called the Health Groups. This feature is available for use in the SmallRye Health 2.2.0 (Quarkus 1.4.0) and later releases. In Quarkus, the health Groups are already included in the smallrye-health extension. If you wish to use in a different container you need to add following dependencies: <dependency> <groupId>io.smallrye</groupId> <artifactId>smallrye-health</artifactId> <version>${version.io.smallrye.health}</version> </dependency> <dependency> <groupId>io.smallrye</groupId> <artifactId>smallrye-health-extension-api</artifactId> <version>${version.io.smallrye.health}</version> </dependency> As we want to test features that we will eventually try to specify in MicroProfile, you can expect that if this feature will be used in Quarkus you will eventually see it in the MicroProfile Health specification. So if you are interested, please feel free to try it out, test it, and report any issues or enhancements in our issue tracker. ### [Fault Tolerance 4.1](/blog/fault-tolerance-4-1/) MicroProfile Fault Tolerance 2.1 was released just 2 weeks ago, and it didn’t take us long to fully implement. Today, we announce availability of SmallRye Fault Tolerance 4.1, a compliant implementation of MicroProfile Fault Tolerance 2.1. Here’s a list of the important changes in the specification: The @Retry.retryOn and abortOn attributes no longer ignore Throwable.class, to be consistent with other annotations that also specify exceptions. Only @Retry had a requirement that Throwable is to be ignored. Related to the previous item is that the specification now admits that throwing custom Throwables results in nonportable behavior. Fortunately, the use cases for throwing something that isn’t an Exception (nor an Error) should be very rare. Also, the behavior was previously unspecified when the @Retry.retryOn and abortOn attributes overlap. It is now specified that the abortOn attribute "wins" over retryOn. The @CircuitBreaker.skipOn attribute was added, to complement the existing failOn attribute. When the attributes overlap, skipOn "wins" over failOn. The @Fallback.applyOn and skipOn attributes were also added. When they overlap, skipOn "wins" over applyOn. It is now specified that during the @Asynchronous method execution, the CDI request context is always active. The specification previously did not require that. This release is also aligned with other SmallRye projects (Config and Metrics) that also recently released a new version in preparation of MicroProfile 3.3 platform release. Enjoy the new SmallRye Fault Tolerance, it is coming in the next Quarkus release! ### [Fault Tolerance 4.0](/blog/fault-tolerance-4-0/) SmallRye Fault Tolerance is our implementation of Eclipse MicroProfile Fault Tolerance. It was originally based on Hystrix, the Netflix library for latency and fault tolerance in distributed systems. Lately, we realized that Hystrix is not the best fit for implementing MicroProfile Fault Tolerance, because Hystrix meshes all fault tolerance concerns into one, while MicroProfile Fault Tolerance describes mostly a layered architecture. The MicroProfile Fault Tolerance specification also requires certain features that Hystrix intentionally doesn’t provide; most importantly, the ability to interrupt threads that Hystrix itself didn’t create. Last but not least, Hystrix is in maintenance mode, and hasn’t been actively developed for more than a year. When we tried to update to latest Hystrix version, we even faced breaking changes. We have been talking on and off about removing Hystrix and using our own implementation of core fault tolerance strategies, one that would be better suited as a base for implementing MicroProfile Fault Tolerance, but only a few months ago did we finally start working on it. Thanks to heroic work of Michał Szynkiewicz, the new implementation didn’t take long to pass the entire MicroProfile Fault Tolerance TCK. We have already released a first version of this new implementation, called 4.0.0. Of course, that’s not the end; in fact, it’s just a beginning. We should now have a better foundation to experiment with, and already have several ideas that we would like to explore and eventually propose to MicroProfile Fault Tolerance. In this article, we’ll take a brief look at how the new implementation works inside, what do you need to know as an integrator, and what are our plans for the future. Under the hood First, let’s take a brief look at the core. It is based on the idea of FaultToleranceStrategy, which is an interface that looks like this: interface FaultToleranceStrategy<V> { V apply(InvocationContext<V> ctx) throws Exception; } The InvocationContext is a Callable that represents the method invocation guarded by this fault tolerance strategy. The fault tolerance strategy does its work around ctx.call(). It can catch exceptions, invoke ctx.call() multiple times, invoke something else, etc. As an example, let’s consider this strategy, applicable to methods that return a String: public class MyStringFallback implements FaultToleranceStrategy<String> { @Override public String apply(InvocationContext<String> ctx) { try { return ctx.call(); } catch (Exception ignored) { return "my string value"; } } } This is a very simple fallback mechanism, which returns a pre-defined value in case of an exception. In the SmallRye Fault Tolerance codebase, you can find implementations of all the strategies required by MicroProfile Fault Tolerance: retry, fallback, timeout, circuit breaker or bulkhead. Asynchronous invocation, delegated to a thread pool, is of course also supported. When multiple fault tolerance strategies are supposed to be used to guard one method, they form a chain. Continuing with our simple example, adding the ability to chain with another strategy would look like this: public class MyStringFallback implements FaultToleranceStrategy<String> { private final FaultToleranceStrategy<String> delegate; public MyStringFallback(FaultToleranceStrategy<String> delegate) { this.delegate = delegate; } @Override public String apply(InvocationContext<String> ctx) { try { return delegate.apply(ctx); } catch (Exception ignored) { return "my string value"; } } } We see that one strategy delegates to another, passing the InvocationContext along. In fact, all the implementations in SmallRye Fault Tolerance are written like this: they expect to be used in a chain, so they take another FaultToleranceStrategy to which they delegate. But if all strategies have this form, when is ctx.call() actually invoked? Good question! The ultimate ctx.call() invocation is done by a special fault tolerance strategy which is called, well, Invocation. As an example which uses real MicroProfile Fault Tolerance annotations, let’s consider this method: @Retry(...) @Timeout(...) @Fallback(...) public void doSomething() { ... } The chain of fault tolerance strategies will look roughly like this: Fallback( Retry( Timeout( Invocation( // ctx.call() will happen here // that will, in turn, invoke doSomething() ) ) ) ) The order in which the strategies are chained (or, in fact, nested) is specified by MicroProfile Fault Tolerance. In asynchronous invocations, especially those using CompletionStage, it is a bit more complex, but the core idea is the same and the intuition you gained here should still apply. Please note that everything explained here is an implementation detail. API stability for these interfaces and classes is not guaranteed; we only mention them here to give you better understanding of the new implementation. You will also want to understand this if you decide to contribute (pull requests are always welcome!). Integration concerns If you integrate SmallRye Fault Tolerance to provide an implementation of MicroProfile Fault Tolerance, you should be aware of a few things. SmallRye Fault Tolerance creates several thread pools (ExecutorServices). One for asynchronous invocations, one for watching timeouts, and then one for each threadpool-style bulkhead. You might want to customize how these thread pools are created. For example, if you integrate SmallRye Fault Tolerance into a Java EE application server, you probably want these thread pools to be managed. We provide an SPI that you can implement for this exact purpose: ExecutorFactory. Size of these thread pools can be configured using the following configuration properties: io.smallrye.faulttolerance.globalThreadPoolSize Size of the thread pool for asynchronous invocations. Does not include bulkhead thread pools. Defaults to 100. io.smallrye.faulttolerance.timeoutExecutorThreads Size of the thread pool for watching timeouts. Defaults to 5. Optional integration with MicroProfile Context Propagation is present, in a separate artifact. Optional integration with MicroProfile OpenTracing is also present, but it’s currently built on top of the Context Propagation integration. We’re looking to potentially remove that dependency, so that OpenTracing integration is also possible if you’re not yet ready to incorporate Context Propagation. Future outlook As we mentioned above, this is not an end. Here’s a short list of what we want to look at. First of all, the 4.0 version implements MicroProfile Fault Tolerance 2.0. We will of course continue implementing subsequent specification versions, starting with 2.1, which should be released soon. Currently, MicroProfile Fault Tolerance specifies that @Asynchronous invocation always means delegating to a thread pool. We’d like to investigate what would it take to support asynchronous invocation on an event loop, such as one provided by Vert.x. We’d like to add a fail-fast strategy, tentatively called @FailFast. This is useful to prevent expensive calls when you know it doesn’t make sense to do them. One instance of this idea is the circuit breaker, which decides automatically based on rate of errors. Here, the decision would be entirely yours. We’d also like to add adaptive concurrency limiters, tentatively called @AdaptiveBulkhead. Bulkheads, as they exist in MicroProfile Fault Tolerance now, are defined statically. That is, you need to know upfront what is the maximum concurrency level. This is no longer enough in the cloud world, where services are scaled up and down dynamically. It is possible to determine the concurrency limits dynamically, by observing the invocation latencies and error rates. Netflix has been doing that in their concurrency limits project, and we can certainly take a lot of inspiration from them. Some of the items above are about providing a new API. The idea is that we would prototype that API in SmallRye and if it proves worthy, we’d work to specify it in MicroProfile. For that reason, we would probably mark these prototypes as experimental API, and if they get specified in MicroProfile, we’d rapidly deprecate and remove them. There are also some implementation aspects that we’d like to finetune. The metrics collection and configuration handling code mostly comes from the old implementation, and is due for serious refactoring. As mentioned above, each threadpool-style bulkhead currently gets a fresh thread pool. This is quite inefficient, and can be significantly improved. The current implementation includes a special strategy called Tracer, which can be put in between any two other strategies to print useful information about when and on which thread is the subsequent strategy invoked. This proved very useful in debugging, but using it requires manual changes and rebuild of the entire codebase. We want to add comprehensive debug and trace logging that is always present, so that you can easily enable it. And there’s a lot more, for sure. As we said above, this is just a beginning! ### [SmallRye Innovation](/blog/innovation/) SmallRye implements Eclipse MicroProfile specifications for use within any runtime. Currently, SmallRye is included in Quarkus, Thorntail, WildFly, and the reactive implementations are part of Open Liberty. That’s great, but that’s only implementing what’s been defined by a specification. Does SmallRye only implement the specifications "as is"? How do new ideas get added to MicroProfile, either as new specifications or changes to an existing specification? Questions like these, and others like them, are what I hear often from those not familiar with exactly how MicroProfile operates. Unlike how the JCP typically operated in the past when defining Java EE specifications, MicroProfile takes a very different approach. Bean Validation took a similar approach as MicroProfile. In MicroProfile we define specifications based on existing implementations and usage within projects, as it offers a greater indication that what’s being proposed is useful to developers. It’s much harder to create an API from ideas and have it be useful than to define a specification based on an already working implementation. How does this relate to how SmallRye develops implementations? Since its creation SmallRye was purposefully focused on implementing the MicroProfile specifications, while seeking to improve the specifications and TCKs when issues were found. Having reached a point where the implementations are stable and easily kept in line with modifications to existing specifications, it frees those working on the project to shift our focus to innovation! What type of innovation are we talking about? In theory, it could be absolutely anything. In practice, we’re not proposing a complete free for all, as that leads to churn without results. We have a few initiatives that are underway where we are beginning to innovate with MicroProfile. We’ve begun work on an entirely new implementation for Fault Tolerance, see here, which aims to be reactive friendly while still enabling the same functionality for imperative programming. In SmallRye Config we will be investigating how to implement support for using a pre captured configuration during the creation of later ConfigSources and ConfigSourceProviders, allowing configuration to be used to create latter stage configuration instances. There are also other innovations underway within the reactive sphere of SmallRye that we intend to announce soon. In addition to innovation within SmallRye projects, we’re in the process of accepting the donation from the MicroProfile Extensions project. The MicroProfile Extensions project includes many new ConfigSource and Converter types that will be added to SmallRye. A big thanks to Phillip and Derek for agreeing to this and pushing it forward. All this innovation in SmallRye is great, but what does that mean for MicroProfile specifications? Do they have these new innovations as well? In the short term, no they wouldn’t. The medium to longer-term goal for any innovation created in SmallRye is for it to be proposed to existing or new MicroProfile specifications. If you’d like to contribute to SmallRye and help us deliver innovation to MicroProfile, come by our forum and take a look at the issues in any of the projects on GitHub. ### [SmallRye on GraalVM with Quarkus!](/blog/graalvm-quarkus/) Marvel at SmallRye on GraalVM with Quarkus! If you haven’t heard already, today Quarkus was released! Quarkus is a new open source project for Supersonic Subatomic Java! Bringing a Kubernetes Native Java stack tailored for GraalVM and OpenJDK Hotspot, crafted from the best of breed Java libraries and standards. Additional details of Quarkus are on the website and announcement blog. How is the announcement of Quarkus important for SmallRye? Quarkus has extensions for each of the SmallRye implementations, enabling a user to create a Quarkus application using SmallRye, and thus Eclipse MicroProfile. You can now create an application with amazingly fast boot time, and incredibly low RSS memory (not just the heap size!), with Eclipse MicroProfile APIs. We look forward to hearing how developers enjoy the speed and memory performance in containers! ### [SmallRye adds MicroProfile 2.2 support!](/blog/microprofile-2-2/) SmallRye now has all implementations passing the TCKs for MicroProfile 2.2 specifications! The full list of completed implementations: Config 1.3 Fault Tolerance 2.0 Health 1.0 JWT 1.1 Metrics 1.1 OpenAPI 1.1 OpenTracing 1.3 REST Client 1.2 Check out the Projects page for all the details! Thanks to everyone from the community that enabled us to implement the specification so fast! ### [SmallRye adds MicroProfile 1.3 support!](/blog/microprofile-1-3/) SmallRye now has all implementations passing the TCKs for MicroProfile 1.3 specifications! The full list of completed implementations: Config 1.3 Fault Tolerance 1.0 Health 1.0 JWT 1.1 Metrics 1.1 OpenAPI 1.0.1 OpenTracing 1.1 REST Client 1.0 Check out the Projects page for all the details! One important to note is that some of these implementations are already compliant MicroProfile 1.4! The team is in the process of implementing updates to the remaining specifications to reach full MicroProfile 1.4 compliance. Why not join the community and help us out! ### [Welcome to SmallRye](/blog/welcome/) SmallRye welcomes you to our new community for developing shared implementations of Eclipse MicroProfile specifications! Right now we’re still in the process of seeding the initial versions of the repositories for each Eclipse MicroProfile specification implementation. As they’re released we will be updating the overview page and creating a page specific to each implementation on the website. Currently we have released the following implementations: Config, REST Client, Open API The plan is to have the remainder migrated and released within the next couple of weeks. ## Pages ### [MicroProfile Health 3.1 Compatible Certification Request](/certifications/ccr/health-3.1/) Specification details Repository - https://github.com/eclipse/microprofile-health MicroProfile Health 3.1 Tag - https://github.com/eclipse/microprofile-health/releases/tag/3.1 Commit - https://github.com/eclipse/microprofile-health/commit/99de1f27a646924f0fd761b844f8e7c61e5c9913 Download - https://download.eclipse.org/microprofile/staging/microprofile-health-3.1/ MicroProfile Health 3.1-RC3 (used for the CCR) Tag - https://github.com/eclipse/microprofile-health/releases/tag/3.1-RC3 Commit - https://github.com/eclipse/microprofile-health/commit/a2fabad69df840c79ac60ee23b712c5b31618598 Download - https://download.eclipse.org/microprofile/microprofile-health-3.1-RC3/ There are no differences between 3.1-RC3 and 3.1. The API and TCK binaries are the same. Implementation details Implementation name - SmallRye Health Version - 3.1.0-RC3 Download binary - https://repo1.maven.org/maven2/io/smallrye/smallrye-health/3.1.0-RC3/ Download Source Code - https://github.com/smallrye/smallrye-health VCS revision tag - https://github.com/smallrye/smallrye-health/releases/tag/3.1.0-RC3 VCS revision commit - https://github.com/smallrye/smallrye-health/commit/8361caf1aee355ca55c759c138fe5edb6bd57cc2 Compatibility Certification Request JDK 11 Environment details Output of uname -a Linux Set-FI 5.11.21-300.fc34.x86_64 #1 SMP Fri May 14 17:43:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux Output of java -version openjdk version "11.0.11" 2021-04-20 OpenJDK Runtime Environment AdoptOpenJDK-11.0.11+9 (build 11.0.11+9) OpenJDK 64-Bit Server VM AdoptOpenJDK-11.0.11+9 (build 11.0.11+9, mixed mode) Output of mvn -version Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d) Maven home: /opt/maven/apache-maven-3.8.1 Java version: 11.0.11, vendor: AdoptOpenJDK, runtime: /opt/java/hotspot/jdk-11.0.11+9 Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "5.11.21-300.fc34.x86_64", arch: "amd64", family: "unix" CCR execution JDK 11 Command - mvn -B javadoc:javadoc formatter:validate verify --file pom.xml Results surefire-reports zip - health-3.1-jdk-11-ccr-results.zip Results ------------------------------------------------------------------------------- Test set: TestSuite ------------------------------------------------------------------------------- Tests run: 28, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 62.881 s - in TestSuite <!-- Generated by org.testng.reporters.JUnitXMLReporter --> <testsuite ignored="38" hostname="Set-FI" failures="0" tests="28" name="Surefire test" time="60.243" errors="0" timestamp="08 Jun 2021 14:51:29 GMT"> <testcase classname="org.eclipse.microprofile.health.tck.JsonSchemaValidationTest" name="testPayloadJsonVerifiesWithTheSpecificationSchema" time="0.765"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleReadinessFailedTest" name="testFailureResponsePayload" time="0.067"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleReadinessFailedTest" name="testSuccessfulLivenessResponsePayload" time="0.006"/> <testcase classname="org.eclipse.microprofile.health.tck.SingleLivenessFailedTest" name="testFailureResponsePayload" time="0.051"/> <testcase classname="org.eclipse.microprofile.health.tck.SingleLivenessSuccessfulTest" name="testSuccessResponsePayload" time="0.054"/> <testcase classname="org.eclipse.microprofile.health.tck.SingleReadinessSuccessfulTest" name="testSuccessResponsePayload" time="0.05"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleStartupFailedTest" name="testFailingHealthResponsePayload" time="0.052"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleStartupFailedTest" name="testFailingStartupResponsePayload" time="0.005"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleStartupFailedTest" name="testSuccessfulLivenessResponsePayload" time="0.004"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleStartupFailedTest" name="testSuccessfulReadinessResponsePayload" time="0.004"/> <testcase classname="org.eclipse.microprofile.health.tck.DelegateHealthSuccessfulTest" name="testSuccessfulDelegateInvocation" time="0.053"/> <testcase classname="org.eclipse.microprofile.health.tck.SingleStartupSuccessfulTest" name="testSuccessResponsePayload" time="0.049"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleProceduresFailedTest" name="testFailureResponsePayload" time="0.07"/> <testcase classname="org.eclipse.microprofile.health.tck.SingleReadinessFailedTest" name="testFailureResponsePayload" time="0.062"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleLivenessFailedTest" name="testFailureLivenessResponsePayload" time="0.089"/> <testcase classname="org.eclipse.microprofile.health.tck.MultipleLivenessFailedTest" name="testSuccessfulReadinessResponsePayload" time="0.005"/> <testcase classname="org.eclipse.microprofile.health.tck.DelayedCheckTest" name="testSuccessResponsePayload" time="6.086"/> <testcase classname="org.eclipse.microprofile.health.tck.NoProcedureSuccessfulTest" name="testSuccessResponsePayload" time="0.044"/> <testcase classname="org.eclipse.microprofile.health.tck.HealthCheckResponseValidationTest" name="testValidateConcreteHealthCheckResponse" time="0.064"/> <testcase classname="org.eclipse.microprofile.health.tck.OnlySuccessfulProcedureTest" name="testSuccessfulLivenessResponsePayload" time="0.053"/> <testcase classname="org.eclipse.microprofile.health.tck.OnlySuccessfulProcedureTest" name="testSuccessfulReadinessResponsePayload" time="0.004"/> <testcase classname="org.eclipse.microprofile.health.tck.ConfigTest" name="testEmptyReadinessWithConfig" time="0.041"/> <testcase classname="org.eclipse.microprofile.health.tck.HealthCheckResponseAttributesTest" name="testSuccessResponsePayload" time="0.053"/> <testcase classname="org.eclipse.microprofile.health.tck.SingleStartupFailedTest" name="testFailedResponsePayload" time="0.054"/> <testcase classname="org.eclipse.microprofile.health.tck.CDIProducedProceduresTest" name="testFailureReadinessResponsePayload" time="0.053"/> <testcase classname="org.eclipse.microprofile.health.tck.CDIProducedProceduresTest" name="testSuccessStartupResponsePayload" time="0.005"/> <testcase classname="org.eclipse.microprofile.health.tck.CDIProducedProceduresTest" name="testSuccessfulLivenessResponsePayload" time="0.004"/> <testcase classname="org.eclipse.microprofile.health.tck.EnforceQualifierTest" name="testFailureResponsePayload" time="0.053"/> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@AfterSuite arquillianAfterSuite" time="0.0"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase classname="org.jboss.arquillian.testng.Arquillian" name="@BeforeSuite arquillianBeforeSuite" time="0.0"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> </testsuite> <!-- Surefire test --> Compatibility Certification Request JDK 8 Environment details Output of uname -a Linux Set-FI 5.11.21-300.fc34.x86_64 #1 SMP Fri May 14 17:43:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux Output of java -version openjdk version "1.8.0_265" OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_265-b01) OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.265-b01, mixed mode) Output of mvn -version Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d) Maven home: /opt/maven/apache-maven-3.8.1 Java version: 1.8.0_265, vendor: AdoptOpenJDK, runtime: /opt/java/hotspot/jdk8u265-b01/jre Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "5.11.21-300.fc34.x86_64", arch: "amd64", family: "unix" CCR execution JDK 8 Command - mvn -B javadoc:javadoc formatter:validate verify --file pom.xml Results surefire-reports zip - health-3.1-jdk-8-ccr-results.zip Results ------------------------------------------------------------------------------- Test set: TestSuite ------------------------------------------------------------------------------- Tests run: 28, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 64.858 s - in TestSuite <!-- Generated by org.testng.reporters.JUnitXMLReporter --> <testsuite hostname="Set-FI" ignored="38" name="Surefire test" tests="28" failures="0" timestamp="08 Jun 2021 15:53:22 GMT" time="62.301" errors="0"> <testcase name="testPayloadJsonVerifiesWithTheSpecificationSchema" time="0.851" classname="org.eclipse.microprofile.health.tck.JsonSchemaValidationTest"/> <testcase name="testFailureResponsePayload" time="0.06" classname="org.eclipse.microprofile.health.tck.MultipleReadinessFailedTest"/> <testcase name="testSuccessfulLivenessResponsePayload" time="0.005" classname="org.eclipse.microprofile.health.tck.MultipleReadinessFailedTest"/> <testcase name="testFailureResponsePayload" time="0.061" classname="org.eclipse.microprofile.health.tck.SingleLivenessFailedTest"/> <testcase name="testSuccessResponsePayload" time="0.059" classname="org.eclipse.microprofile.health.tck.SingleLivenessSuccessfulTest"/> <testcase name="testSuccessResponsePayload" time="0.058" classname="org.eclipse.microprofile.health.tck.SingleReadinessSuccessfulTest"/> <testcase name="testFailingHealthResponsePayload" time="0.054" classname="org.eclipse.microprofile.health.tck.MultipleStartupFailedTest"/> <testcase name="testFailingStartupResponsePayload" time="0.005" classname="org.eclipse.microprofile.health.tck.MultipleStartupFailedTest"/> <testcase name="testSuccessfulLivenessResponsePayload" time="0.004" classname="org.eclipse.microprofile.health.tck.MultipleStartupFailedTest"/> <testcase name="testSuccessfulReadinessResponsePayload" time="0.004" classname="org.eclipse.microprofile.health.tck.MultipleStartupFailedTest"/> <testcase name="testSuccessfulDelegateInvocation" time="0.067" classname="org.eclipse.microprofile.health.tck.DelegateHealthSuccessfulTest"/> <testcase name="testSuccessResponsePayload" time="0.048" classname="org.eclipse.microprofile.health.tck.SingleStartupSuccessfulTest"/> <testcase name="testFailureResponsePayload" time="0.063" classname="org.eclipse.microprofile.health.tck.MultipleProceduresFailedTest"/> <testcase name="testFailureResponsePayload" time="0.069" classname="org.eclipse.microprofile.health.tck.SingleReadinessFailedTest"/> <testcase name="testFailureLivenessResponsePayload" time="0.047" classname="org.eclipse.microprofile.health.tck.MultipleLivenessFailedTest"/> <testcase name="testSuccessfulReadinessResponsePayload" time="0.005" classname="org.eclipse.microprofile.health.tck.MultipleLivenessFailedTest"/> <testcase name="testSuccessResponsePayload" time="6.08" classname="org.eclipse.microprofile.health.tck.DelayedCheckTest"/> <testcase name="testSuccessResponsePayload" time="0.042" classname="org.eclipse.microprofile.health.tck.NoProcedureSuccessfulTest"/> <testcase name="testValidateConcreteHealthCheckResponse" time="0.078" classname="org.eclipse.microprofile.health.tck.HealthCheckResponseValidationTest"/> <testcase name="testSuccessfulLivenessResponsePayload" time="0.054" classname="org.eclipse.microprofile.health.tck.OnlySuccessfulProcedureTest"/> <testcase name="testSuccessfulReadinessResponsePayload" time="0.005" classname="org.eclipse.microprofile.health.tck.OnlySuccessfulProcedureTest"/> <testcase name="testEmptyReadinessWithConfig" time="0.038" classname="org.eclipse.microprofile.health.tck.ConfigTest"/> <testcase name="testSuccessResponsePayload" time="0.046" classname="org.eclipse.microprofile.health.tck.HealthCheckResponseAttributesTest"/> <testcase name="testFailedResponsePayload" time="0.052" classname="org.eclipse.microprofile.health.tck.SingleStartupFailedTest"/> <testcase name="testFailureReadinessResponsePayload" time="0.045" classname="org.eclipse.microprofile.health.tck.CDIProducedProceduresTest"/> <testcase name="testSuccessStartupResponsePayload" time="0.004" classname="org.eclipse.microprofile.health.tck.CDIProducedProceduresTest"/> <testcase name="testSuccessfulLivenessResponsePayload" time="0.004" classname="org.eclipse.microprofile.health.tck.CDIProducedProceduresTest"/> <testcase name="testFailureResponsePayload" time="0.038" classname="org.eclipse.microprofile.health.tck.EnforceQualifierTest"/> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@AfterSuite arquillianAfterSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @AfterSuite arquillianAfterSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> <testcase name="@BeforeSuite arquillianBeforeSuite" time="0.0" classname="org.jboss.arquillian.testng.Arquillian"> <ignored/> </testcase> <!-- @BeforeSuite arquillianBeforeSuite --> </testsuite> <!-- Surefire test --> Replicating the TCK execution git clone https://github.com/smallrye/smallrye-health.git -b 3.1.0-RC3 && cd smallrye-health mvn -B javadoc:javadoc formatter:validate verify --file pom.xml ### [Page not found](/404.html) The requested page could not be found. Try the home page, the project list or the documentation. ### [Community](/community/) Getting help Discussions Mailing list You can ask questions on our mailing list. Join the Google group via email smallrye+subscribe@googlegroups.com or by visiting the Google Groups page https://groups.google.com/d/forum/smallrye. Live chat on Zulip If you prefer live chat with the developers, we have a Zulip chat. Code and issue tracker The source code is hosted in the SmallRye organization on GitHub. If you need to report a bug or request a new feature, look for any existing issues in the GitHub repository for the specific project. If you don’t find any, create a new issue. If you believe you found a bug, please indicate a way to reproduce it, what you are seeing, and what you would expect to see. Don’t forget to indicate your SmallRye project, Java, and Maven version. Contributing Details on how to contribute can be found here. ### [Projects](/projects/) Eclipse MicroProfile Platform SmallRye Config An implementation of MicroProfile Config SmallRye JWT An implementation of MicroProfile JWT RBAC SmallRye Health An implementation of MicroProfile Health SmallRye Fault Tolerance An implementation of MicroProfile Fault Tolerance SmallRye Metrics An implementation of MicroProfile Metrics SmallRye OpenAPI An implementation of MicroProfile OpenAPI SmallRye OpenTracing An implementation of MicroProfile OpenTracing RESTEasy REST Client An implementation of MicroProfile REST Client Eclipse MicroProfile Standalone SmallRye Context Propagation An implementation of MicroProfile Context Propagation SmallRye Mutiny Intuitive Event-Driven Reactive Programming Library for Java and an implementation of MicroProfile Reactive Streams Operators SmallRye Reactive Messaging An implementation of MicroProfile Reactive Messaging SmallRye GraphQL An implementation of MicroProfile GraphQL SmallRye Standalone Jandex Space efficient Java class file indexer and offline reflection library SmallRye Common Common utilities for SmallRye projects and maybe more SmallRye Reactive Utils Helps the development of Reactive Applications SmallRye Open Telemetry Integration of OpenTelemetry in MicroProfile and SmallRye SmallRye Async API Implementation of the AsyncAPI with MicroProfile SmallRye Converters Provides an API to convert a String type to something else ### [Blog](/blog/) Fault Tolerance 7.0.0 Ladislav Thon 16 September 2026 SmallRye Fault Tolerance 7.0.0 released! Jandex 3.6.0 Ladislav Thon 8 June 2026 Jandex 3.6.0 released! Fault Tolerance 6.11.1 Ladislav Thon 30 March 2026 SmallRye Fault Tolerance 6.11.1 released! Fault Tolerance 6.11.0 Ladislav Thon 16 March 2026 SmallRye Fault Tolerance 6.11.0 released! Jandex 3.5.3 Ladislav Thon 2 December 2025 Jandex 3.5.3 released! Fault Tolerance 6.10.0 Ladislav Thon 21 November 2025 SmallRye Fault Tolerance 6.10.0 released! Jandex 3.5.2 Ladislav Thon 12 November 2025 Jandex 3.5.2 released! Jandex 3.5.1 Ladislav Thon 23 October 2025 Jandex 3.5.1 released! Fault Tolerance 6.9.3 Ladislav Thon 12 September 2025 SmallRye Fault Tolerance 6.9.3 released! Jandex 3.5.0 Ladislav Thon 12 September 2025 Jandex 3.5.0 released! Page 1 of 9 Older → ### [Blog](/blog/page/2/) Fault Tolerance 6.9.2 Ladislav Thon 31 July 2025 SmallRye Fault Tolerance 6.9.2 released! Jandex 3.4.0 Ladislav Thon 21 July 2025 Jandex 3.4.0 released! Jandex 3.3.2 Ladislav Thon 3 July 2025 Jandex 3.3.2 released! Jandex 3.3.1 Ladislav Thon 13 May 2025 Jandex 3.3.1 released! Fault Tolerance 6.9.1 Ladislav Thon 23 April 2025 SmallRye Fault Tolerance 6.9.1 released! Jandex 3.3.0 Ladislav Thon 7 April 2025 Jandex 3.3.0 released! Fault Tolerance 6.9.0 Ladislav Thon 11 March 2025 SmallRye Fault Tolerance 6.9.0 released! Jandex 3.2.7 Ladislav Thon 17 February 2025 Jandex 3.2.7 released! Jandex 3.2.6 Ladislav Thon 11 February 2025 Jandex 3.2.6 released! Jandex 3.2.5 Ladislav Thon 7 February 2025 Jandex 3.2.5 released! ← Newer Page 2 of 9 Older → ### [Blog](/blog/page/3/) Fault Tolerance 6.8.0 Ladislav Thon 4 February 2025 SmallRye Fault Tolerance 6.8.0 released! Jandex 3.2.4 Ladislav Thon 3 February 2025 Jandex 3.2.4 released! Fault Tolerance 6.7.3 Ladislav Thon 9 January 2025 SmallRye Fault Tolerance 6.7.3 released! Fault Tolerance 6.7.2 Ladislav Thon 6 January 2025 SmallRye Fault Tolerance 6.7.2 released! Fault Tolerance 6.7.1 Ladislav Thon 10 December 2024 SmallRye Fault Tolerance 6.7.1 released! Fault Tolerance 6.7.0 Ladislav Thon 28 November 2024 SmallRye Fault Tolerance 6.7.0 released! Fault Tolerance 6.6.3 Ladislav Thon 19 November 2024 SmallRye Fault Tolerance 6.6.3 released! Fault Tolerance 6.6.2 Ladislav Thon 14 November 2024 SmallRye Fault Tolerance 6.6.2 released! Fault Tolerance 6.6.1 Ladislav Thon 29 October 2024 SmallRye Fault Tolerance 6.6.1 released! Fault Tolerance 6.6.0 Ladislav Thon 24 October 2024 SmallRye Fault Tolerance 6.6.0 released! ← Newer Page 3 of 9 Older → ### [Blog](/blog/page/4/) Jandex 3.2.3 Ladislav Thon 24 October 2024 Jandex 3.2.3 released! Fault Tolerance 6.5.0 Ladislav Thon 11 October 2024 SmallRye Fault Tolerance 6.5.0 released! Fault Tolerance 6.4.1 Ladislav Thon 27 September 2024 SmallRye Fault Tolerance 6.4.1 released! Jandex 3.2.2 Ladislav Thon 8 August 2024 Jandex 3.2.2 released! Jandex 3.2.1 Ladislav Thon 29 July 2024 Jandex 3.2.1 released! Fault Tolerance 6.4.0 Ladislav Thon 22 July 2024 SmallRye Fault Tolerance 6.4.0 released! Jandex 3.2.0 Ladislav Thon 16 May 2024 Jandex 3.2.0 released! Jandex 3.1.8 Ladislav Thon 7 May 2024 Jandex 3.1.8 released! Fault Tolerance 6.3.0 Ladislav Thon 11 April 2024 SmallRye Fault Tolerance 6.3.0 released! Jandex 3.1.7 Ladislav Thon 14 March 2024 Jandex 3.1.7 released! ← Newer Page 4 of 9 Older → ### [Blog](/blog/page/5/) Jandex 3.1.6 Ladislav Thon 27 November 2023 Jandex 3.1.6 released! Jandex 3.1.5 Ladislav Thon 22 September 2023 Jandex 3.1.5 released! Jandex 3.1.3 Ladislav Thon 28 August 2023 Jandex 3.1.3 released! Fault Tolerance 6.2.6 Ladislav Thon 25 July 2023 SmallRye Fault Tolerance 6.2.6 released! Fault Tolerance 6.2.4 Ladislav Thon 21 June 2023 SmallRye Fault Tolerance 6.2.4 released! Jandex 3.1.2 Ladislav Thon 8 June 2023 Jandex 3.1.2 released! Fault Tolerance 6.2.3 Ladislav Thon 26 May 2023 SmallRye Fault Tolerance 6.2.3 released! Jandex 3.1.1 Ladislav Thon 13 April 2023 Jandex 3.1.1 released! Jandex 3.1.0 Ladislav Thon 6 April 2023 Jandex 3.1.0 released! Fault Tolerance 6.2.2 Ladislav Thon 6 April 2023 SmallRye Fault Tolerance 6.2.2 released! ← Newer Page 5 of 9 Older → ### [Blog](/blog/page/6/) Fault Tolerance 6.2.1 Ladislav Thon 3 March 2023 SmallRye Fault Tolerance 6.2.1 released! Fault Tolerance 6.2.0 Ladislav Thon 10 February 2023 SmallRye Fault Tolerance 6.2.0 released! Jandex 3.0.5 Ladislav Thon 2 December 2022 Jandex 3.0.5 released! Jandex 3.0.4 Ladislav Thon 24 November 2022 Jandex 3.0.4 released! Jandex 3.0.3 Ladislav Thon 9 November 2022 Jandex 3.0.3 released! Jandex 3.0.2 Ladislav Thon 8 November 2022 Jandex 3.0.2 released! Fault Tolerance 5.6.0 and 6.1.0 Ladislav Thon 25 October 2022 SmallRye Fault Tolerance 5.6.0 and 6.1.0 released! Jandex 3.0.1 Ladislav Thon 16 September 2022 Jandex 3.0.1 released! Fault Tolerance 6.0.0 Ladislav Thon 7 September 2022 SmallRye Fault Tolerance 6.0.0 released! Jandex 3.0.0 Ladislav Thon 25 August 2022 Jandex found a new home in SmallRye and version 3.0.0 is available! ← Newer Page 6 of 9 Older → ### [Blog](/blog/page/7/) Fault Tolerance 5.5 Ladislav Thon 11 July 2022 SmallRye Fault Tolerance 5.5 released! Fault Tolerance 5.4.1 Ladislav Thon 28 June 2022 SmallRye Fault Tolerance 5.4.1 released! Fault Tolerance 5.4 Ladislav Thon 31 March 2022 SmallRye Fault Tolerance 5.4 released! Fault Tolerance 5.3.2 Ladislav Thon 14 February 2022 SmallRye Fault Tolerance 5.3.2 released! Fault Tolerance 5.3.1 Ladislav Thon 10 February 2022 SmallRye Fault Tolerance 5.3.1 released! Fault Tolerance 5.3 Ladislav Thon 8 February 2022 SmallRye Fault Tolerance 5.3 released! Log4j2 Vulnerability and SmallRye Roberto Cortez 13 December 2021 Log4j2 Vulnerability and SmallRye Fault Tolerance 5.2.1 Ladislav Thon 16 July 2021 SmallRye Fault Tolerance 5.2.1 released! Fault Tolerance 5.2 Ladislav Thon 2 July 2021 SmallRye Fault Tolerance 5.2 released! Fault Tolerance 5.1 Ladislav Thon 18 May 2021 SmallRye Fault Tolerance 5.1 released! ← Newer Page 7 of 9 Older → ### [Blog](/blog/page/8/) Fault Tolerance 5.0 Ladislav Thon 18 January 2021 SmallRye Fault Tolerance 5.0 released, implementing MicroProfile Fault Tolerance 3.0 and bringing a lot of other improvements. Fault Tolerance 4.3.1 Ladislav Thon 29 September 2020 SmallRye Fault Tolerance 4.3.1 released! SmallRye Config 1.9 Released Roberto Cortez 24 September 2020 SmallRye Config 1.8 Released Fault Tolerance 4.2 & 4.3 Ladislav Thon 29 May 2020 SmallRye Fault Tolerance 4.2 and 4.3 released! SmallRye Config 1.8 Released Roberto Cortez 22 May 2020 SmallRye Config 1.8 Released Health Groups - experimental MicroProfile Health extension in SmallRye Martin Stefanko 7 May 2020 An experimental MicroProfile Health extension in SmallRye Fault Tolerance 4.1 Ladislav Thon 17 February 2020 SmallRye Fault Tolerance 4.1 released! Fault Tolerance 4.0 Ladislav Thon 22 January 2020 Why we reimplemented SmallRye Fault Tolerance from scratch and how does it look like? SmallRye Innovation Ken Finnigan 27 November 2019 How does SmallRye go beyond just implementing Eclipse MicroProfile specifications? SmallRye on GraalVM with Quarkus! Ken Finnigan 7 March 2019 Quarkus utilizes SmallRye on GraalVM. Marvel at its supersonic subatomic speed! ← Newer Page 8 of 9 Older → ### [Blog](/blog/page/9/) SmallRye adds MicroProfile 2.2 support! Ken Finnigan 6 March 2019 SmallRye now has all implementations passing the TCKs for MicroProfile 2.2 specifications! SmallRye adds MicroProfile 1.3 support! Ken Finnigan 7 September 2018 SmallRye now has all implementations passing the TCKs for MicroProfile 1.3 specifications! Welcome to SmallRye Ken Finnigan 28 June 2018 SmallRye welcomes you to our new community for developing shared implementations of Eclipse MicroProfile specifications! ← Newer Page 9 of 9