Quarkus Cheat-Sheet

What is Quarkus? Or in Kotlin: Command mode

Quarkus is a Native Java stack tailored for GraalVM & plugins { You can dene the main CLI method to start Quarkus. There are two OpenJDK HotSpot, crafted from the best of breed Java libraries and java ways, implementing io.quarkus.runtime.QuarkusApplication standards. Also focused on developer experience, making things } interface or use the Java main method to launch Quarkus. just work with little to no conguration and allowing to do live apply(plugin = "io.quarkus") coding. @io.quarkus.runtime.annotations.QuarkusMain repositories { public class HelloWorldMain implements QuarkusApplication { Cheat-sheet tested with Quarkus 1.13.0.Final. mavenCentral() @Override } public int run(String... args) throws Exception { Getting Started System.out.println("Hello World"); dependencies { return 10; Quarkus comes with a Maven archetype to scaffold a very simple implementation(enforcedPlatform("io.quarkus:quarkus-bo } starting project. m:0.26.1")) } implementation("io.quarkus:quarkus-resteasy") } mvn io.quarkus:quarkus-maven-plugin:1.13.0.Final:create \ -DprojectGroupId=org.acme \ run method called when Quarkus starts, and stops when it nishes. -DprojectArtifactId=getting-started \ -DclassName="org.acme.quickstart.GreetingResource" \ Packaging As Java main : -Dpath="/hello"

mvn clean package @QuarkusMain public class JavaMain { This creates a simple JAX-RS resource called GreetingResource . public static void main(String... args) { Quarkus.run(HelloWorldMain.class, args); You need to distribute the -runner.jar le together with quarkus- @Path("/hello") } app directory. public class GreetingResource { } If quarkus.package.uber-jar property is set to true, then a uber-jar is @GET created with all dependencies bundled inside the JAR. @Produces(MediaType.TEXT_PLAIN) public String hello() { By default, Quarkus uses fast jar packaging, if quarkus.package.type Use @QuarkusMain in only one place. return "hello"; property is set to legacy-jar then Quarkus creates the old standard } jar le. Use Quarkus.waitForExit() from the main thread if you want to run } application.properties some logic on startup, and then run like a normal application (i.e. not exit). quarkus.package.uber-jar=true Gradle quarkus.package.type=legacy-jar You can inject command line arguments by using @CommandLineArguments annotation: There is no way to scaffold a project in Gradle but you only need to do: To compile to native, you need to set GRAALVM_HOME environment @CommandLineArguments variable and run the native prole. String[] args; plugins { id 'java' mvn clean package -Pnative id 'io.quarkus' version '0.26.1' Picocli } ./gradlew build -Dquarkus.package.type=native You can use Picocli to implement CLI applications: repositories { mavenCentral() ./mvnw quarkus:add-extension Possible quarkus.package.type are: jar , legacy-jar , uber-jar and } -Dextensions="picocli" native .

dependencies { AppCDS implementation enforcedPlatform('io.quarkus:quarkus-bo m:0.26.1') Automatically generate AppCDS as part of the build process set the implementation 'io.quarkus:quarkus-resteasy' next property: quarkus.package.create-appcds=true . } To make use of it, just run java -jar -XX:SharedArchiveFile=app- cds.jsa myapp.jar . @CommandLine.Command @CommandLine.Command Dev Mode public class HelloCommand implements Runnable { public class EntryCommand implements Runnable { @CommandLine.Option(names = "-c", description = "JDBC c ./mvnw compile quarkus:dev @CommandLine.Option(names = {"-n", "--name"}, descripti onnection string")

on = "Who will we greet?", defaultValue = "World") String connectionString; ./gradlew quarkusDev String name; @Inject private final GreetingService greetingService; DataSource dataSource; } Endpoints are registered automatically to provide some basic public HelloCommand(GreetingService greetingService) { debug info in dev mode: this.greetingService = greetingService; @ApplicationScoped HTTP GET /quarkus/arc/beans } class DatasourceConfiguration {

Query Parameters: scope , beanClass , kind . @Override @Produces

public void run() { @ApplicationScoped HTTP GET /quarkus/arc/observers greetingService.sayHello(name); DataSource dataSource(CommandLine.ParseResult parseResu } lt) { Dev UI } System.out.println(parseResult.matchedOption("c").g etValue().toString()); Quarkus adds a Dev UI console to expose extension features. } } All classes annotated with picocli.CommandLine.Command are The Dev UI is available in dev mode only and accessible at the registered as CDI beans. /q/dev endpoint by default. If only one class annotated with picocli.CommandLine.Command it will Extensions Adding Conguration Parameters be used as entry point. If you want to provide your own @QuarkusMain : Quarkus comes with extensions to integrate with some libraries To add conguration to your application, Quarkus relies on such as JSON-B, Camel or MicroProle spec. To list all available MicroProle Cong spec. @QuarkusMain extensions just run: @CommandLine.Command(name = "demo", mixinStandardHelpOption @ConfigProperty(name = "greetings.message") s = true) ./mvnw quarkus:list-extensions String message; public class ExampleApp implements Runnable, QuarkusApplica

tion { @ConfigProperty(name = "greetings.message",

defaultValue = "Hello") @Inject You can use -DsearchPattern=panache to lter out all String messageWithDefault; CommandLine.IFactory factory; extensions except the ones matching the expression.

@ConfigProperty(name = "greetings.message") @Override And to register the extensions into build tool: Optional optionalMessage; public void run() { } ./mvnw quarkus:add-extension -Dextensions=""

@Override Properties can be set (in decreasing priority) as: ./mvnw quarkus:remove-extension -Dextensions="" public int run(String... args) throws Exception { return new CommandLine(this, factory).execute(arg System properties ( -Dgreetings.message ). s); } extensions property supports CSV format to register more Environment variables ( GREETINGS_MESSAGE ). } than one extension at once. Environment le named .env placed in the current working directory ( GREETING_MESSAGE= ). Application Lifecycle Use quarkus.picocli.native-image.processing.enable to false to use External cong directory under the current working directory: the picocli-codegen annotation processor instead of build steps. You can be notied when the application starts/stops by observing config/application.properties . StartupEvent and ShutdownEvent events. You can also congure CDI beans with PicoCLI arguments: Resources src/main/resources/application.properties . @ApplicationScoped public class ApplicationLifecycle { greetings.message = Hello World void onStart(@Observes StartupEvent event) {} void onStop(@Observes ShutdownEvent event) {} } Array , List and Set are supported. The delimiter is comma ( , ) char and \ is the escape char.

Quarkus supports graceful shutdown. By default there is no timeout Conguration Proles but can be set by using the quarkus.shutdown.timeout cong Quarkus allow you to have multiple conguration in the same le @ConfigProperty(name = "quarkus.application.name") @ConfigProperties(prefix = "greeting", namingStrategy=Namin ( application.properties ). String applicationName; gStrategy.KEBAB_CASE) public class GreetingConfiguration { The syntax for this is %{profile}.config.key=value . public String message; Additional locations public HiddenConfig hidden; quarkus.http.port=9090 %dev.quarkus.http.port=8181 You can use smallrye.config.locations property to set additional public static class HiddenConfig { conguration les. public List recipients; } HTTP port will be 9090, unless the 'dev' prole is active. } smallrye.config.locations=config.properties Default proles are:

And an application.properties mapping previous class: dev : Activated when in development mode ( quarkus:dev ). or

test : Activated when running tests. greeting.message = hello java -jar -Dsmallrye.config.locations=config.properties greeting.hidden.recipients=Jane,John prod : The default prole when not running in development or test mode You can embed conguration les inside a dependency by adding Bean Validation is also supported so properties are validated at You can create custom prole names by enabling the prole either META-INF/microprofile.properties inside the JAR. When dependency startup time, for example @Size(min = 20) public String message; . setting quarkus.profile system property or QUARKUS_PROFILE is added to the application, conguration properties are merged environment variable. with current conguration. prefix attribute is not mandatory. If not provided, attribute is determined by class name (ie GreeetingConfiguration is quarkus.http.port=9090 @CongProperties translated to greeting or GreetingExtraConfiguration to %staging.quarkus.http.port=9999 As an alternative to injecting multiple related conguration values, greeting-extra ). The sux of the class is always removed. you can also use the @io.quarkus.arc.config.ConfigProperties annotation to group properties. Naming strategy can be changed with property namingStrategy . And enable it quarkus.profile=staging . KEBAB_CASE (whatever.foo-bar) or VERBATIM (whatever.fooBar).

@ConfigProperties(prefix = "greeting", namingStrategy=Namin To get the active prole programmatically use @io.quarkus.arc.config.ConfigIgnore annotation can be used to gStrategy.KEBAB_CASE) io.quarkus.runtime.configuration.ProfileManager.getActiveProfile() . ignore the injection of conguration elements. public class GreetingConfiguration { private String message; @ConfigIgnore You can also set it in the build tool: // getter/setter public Integer ignored; } org.apache.maven.plugins maven-surefire-plugin ${surefire-plugin.version} YAML Cong This class maps greeting.message property dened in application.properties . YAML conguration is also supported. The conguration le is called application.yaml and you need to register a dependency to foo You can inject this class by using CDI @Inject GreetingConfiguration enable its support: ${project.build.directory} greeting; . pom.xml Also you can use an interface approach: @ConfigProperties(prefix = "greeting", namingStrategy=Namin io.quarkus gStrategy.KEBAB_CASE) quarkus-config-yaml public interface GreetingConfiguration { Same for maven-failsafe-plugin .

@ConfigProperty(name = "message") String message(); test { quarkus: String getSuffix(); useJUnitPlatform() datasource: systemProperty "quarkus.test.profile", "foo" url: jdbc:://localhost:5432/some-database } driver: org.postgresql.Driver If property does not follow getter/setter naming convention you need to use org.eclipse.microprofile.config.inject.ConfigProperty to set it. Special properties are set in prod mode: Or with proles: quarkus.application.version and quarkus.application.name to get Nested objects are also supporte: them available at runtime. Then you need to register the ConfigSource as Java service. Create "%dev": @ApplicationScoped a le with the following content: quarkus: public class GreetingService { datasource: /META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource url: jdbc:postgresql://localhost:5432/some-database public String message(String message) { driver: org.postgresql.Driver com.acme.config.InMemoryConfig return message.toUpperCase(); } }

In case of subkeys ~ is used to refer to the unprexed part. Custom Converters

You can implement your own conversion types from String. quarkus: Scope annotation is mandatory to make the bean discoverable. Implement org.eclipse.microprofile.config.spi.Converter http: interface: cors: @Inject ~: true GreetingService greetingService; methods: GET,PUT,POST @Priority(DEFAULT_QUARKUS_CONVERTER_PRIORITY + 100) public class CustomInstantConverter implements Converter { Quarkus is designed with Substrate VM in mind. For this Is equivalent to: @Override reason, we encourage you to use package-private scope public Instant convert(String value) { instead of private. quarkus.http.cors=true if ("now".equals(value.trim())) { quarkus.http.cors.methods=GET,PUT,POST return Instant.now(); Produces } return Instant.parse(value); You can also create a factory of an object by using @javax.enterprise.inject.Produces annotation. Custom Loader } } You can implement your own ConfigSource to load conguration @Produces from different places than the default ones provided by Quarkus. @ApplicationScoped Message message() { For example, database, custom XML, REST Endpoints, … @Priority annotation is used to override the default Message m = new Message(); InstantConverter . You need to create a new class and implement ConfigSource m.setMsn("Hello"); return m; interface: Then you need to register the Converter as Java service. Create a le with the following content: }

package com.acme.config; /META-INF/services/org.eclipse.microprofile.config.spi.Converter @Inject public class InMemoryConfig implements ConfigSource { Message msg; com.acme.config.CustomInstantConverter private Map prop = new HashMap<>();

public InMemoryConfig() { Qualiers // Init properties Undertow Properties } You can use qualiers to return different implementations of the Possible parameters with prex quarkus.servlet : same interface or to customize the conguration of the bean. @Override public int getOrdinal() { context-path // The highest ordinal takes precedence The context path to serve all Servlet context from. (default: / ) return 900; } default-charset

The default charset to use for reading and writing requests. @Override (default: UTF-8 ) public Map getProperties() { return prop; } Injection

@Override Quarkus is based on CDI 2.0 to implement injection of code. It is public String getValue(String propertyName) { not fully supported and only a subset of the specication is return prop.get(propertyName); implemented. }

@Override public String getName() { return "MemoryConfigSource"; } } To work with JSON-B you need to add a dependency: @Qualifier @Dependent @Retention(RUNTIME) public class TracerConfiguration { @Target({TYPE, METHOD, FIELD, PARAMETER}) @Produces ./mvnw quarkus:add-extension public @interface Quote { @IfBuildProfile("prod") -Dextensions="io.quarkus:quarkus-resteasy-jsonb" @Nonbinding String value(); public Tracer realTracer(Reporter reporter, Configurati } on configuration) { return new RealTracer(reporter, configuration); Any POJO is marshaled/unmarshalled automatically. @Produces } @Quote("") @Produces public class Sauce { Message message(InjectionPoint msg) { @DefaultBean private String name; Message m = new Message(); public Tracer noopTracer() { private long scovilleHeatUnits; m.setMsn( return new NoopTracer();

msg.getAnnotated() } // getter/setters .getAnnotation(Quote.class) } } .value() );

Using @io.quarkus.arc.profile.IfBuildProperty annotation, you can return m; JSON equivalent: conditionally enable a bean. @io.quarkus.arc.DefaultBean sets the } default bean. { @Inject "name":"Blair's Ultra Death", @Dependent @Quote("Aloha Beach") "scovilleHeatUnits": 1100000 public class TracerConfiguration { Message message; } @Produces @IfBuildProperty(name = "some.tracer.enabled", stringVa lue = "true") Quarkus breaks the CDI spec by allowing you to inject public Tracer realTracer(Reporter reporter, Configurati In a POST endpoint example: qualied beans without using @Inject annotation. on configuration) {} @POST @Quote("Aloha Beach") @Produces @Consumes(MediaType.APPLICATION_JSON) Message message; @DefaultBean public Response create(Sauce sauce) { public Tracer noopTracer() {} // Create Sauce } return Response.created(URI.create(sauce.getId())) .build(); Quarkus breaks the CDI spec by skipping the @Produces annotation completely if the producer method is annotated } with a scope annotation, a stereotype or a qualier. Properties set at runtime have absolutely no effect on the bean resolution using @IfBuildProperty . @Quote("") To provide custom JsonBCong object: Message message(InjectionPoint msg) { Container-managed Concurrency } @Dependent Quarkus provides @io.quarkus.arc.Lock and a built-in interceptor for JsonbConfig jsonConfig(Instance cust @Quote("Aloha Beach") concurrency control. omizers) { Message message; JsonbConfig config = myJsonbConfig(); // Custom `JsonbC @Lock onfig` @ApplicationScoped for (JsonbConfigCustomizer customizer : customizers) { Alternatives class SharedService { customizer.customize(config); } It is also possible to select alternatives for an application using void addAmount(BigDecimal amout) { application.properties . } return config; } @Lock(value = Lock.Type.READ, time = 1, unit = TimeUni quarkus.arc.selected-alternatives=org.acme.Foo,org.acme.*,B t.SECONDS) ar BigDecimal getAmount() { To work with Jackson you need to add: } } Beans by Quarkus Prole ./mvnw quarkus:add-extension -Dextensions="quarkus-resteasy-jackson" Using @io.quarkus.arc.profile.IfBuildProfile and By default the class is in write mode (so no concurrent calls @io.quarkus.arc.profile.UnlessBuildProfile annotations, you can conditionally enable a bean. allowed) except when lock type is READ where the method can be called concurrently if no write operation in process. If you don’t want to use the default ObjectMapper you can customize it by: JSON Marshalling/Unmarshalling Quarkus uses Validator to validate input/output of REST @ApplicationScoped public class NotExpiredValidator services and business services using Bean validation spec. public class CustomObjectMapperConfig { implements ConstraintValidator @Singleton { @Produces ./mvnw quarkus:add-extension public ObjectMapper objectMapper(Instance customizers) { public boolean isValid(LocalDate value, ObjectMapper objectMapper = new ObjectMapper(); ConstraintValidatorContext ctx) { // perform configuration Annotate POJO objects with validator annotations such as: if ( value == null ) return true; @NotNull , @Digits , @NotBlank , @Min , @Max , … LocalDate today = LocalDate.now(); for (ObjectMapperCustomizer customizer : customizer return ChronoUnit.YEARS.between(today, value) > 0; s) { } public class Sauce { customizer.customize(mapper); }

} @NotBlank(message = "Name may not be blank") return objectMapper; private String name; } @Min(0) And use it normally: } private long scovilleHeatUnits; @NotExpired // getter/setters @JsonbDateFormat(value = "yyyy-MM-dd") } private LocalDate expired; Default media type in Quarkus RestEasy is JSON.

XML Marshalling/Unmarshalling To validate an object use @Valid annotation: Manual Validation

To work with JAX-B you need to add a dependency: public Response create(@Valid Sauce sauce) {} You can call the validation process manually instead of relaying to @Valid by injecting Validator class.

./mvnw quarkus:add-extension @Inject -Dextensions="quarkus-resteasy-jaxb" If a validation error is triggered, a violation report is Validator validator; generated and serialized as JSON. If you want to manipulate the output, you need to catch in the code the Then annotated POJOs are converted to XML. ConstraintViolationException exception. And use it: Create Your Custom Constraints @XmlRootElement Set> violations = public class Message { First you need to create the custom annotation: } validator.validate(sauce);

@GET @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, @Produces(MediaType.APPLICATION_XML) PARAMETER, TYPE_USE }) Localization public Message hello() { @Retention(RUNTIME) return message; @Documented You can congure the based locale for validation messages. } @Constraint(validatedBy = { NotExpiredValidator.class}) public @interface NotExpired { quarkus.default-locale=ca-ES

# Supported locales resolved by Accept-Language String message() default "Sauce must not be expired"; quarkus.locales=en-US,es-ES,fr-FR, ca_ES JAXP Class[] groups() default { }; Class[] payload() default { }; To work with JAX-P you need to add a dependency: } ValidationMessages_ca_ES.properties

./mvnw quarkus:add-extension pattern.message=No conforme al patro -Dextensions="jaxp" You need to implement the validator logic in a class that implements ConstraintValidator . @Pattern(regexp = "A.*", message = "{pattern.message}") final DocumentBuilder dBuilder = DocumentBuilderFactory.new private String name; Instance().newDocumentBuilder(); final Document doc = dBuilder.parse(in); return doc.getDocumentElement().getTextContent(); Bean Validation can be congured . The prex is: quarkus.hibernate-validator .

Validator fail-fast When fail fast is enabled the validation will stop on the rst The path to log le (default: quarkus.log ) syslog.truncate constraint violation detected. (default: false ) Message should be truncated (default: true ) file.rotation.max-file-size method-validation.allow-overriding-parameter-constraints The maximum le size of the log le syslog.block-on-reconnect Dene whether overriding methods that override constraints Block when attempting to reconnect (default: true ) should throw an exception. (default: false ). file.rotation.max-backup-index The maximum number of backups to keep (default: 1 ) syslog.async method-validation.allow-parameter-constraints-on-parallel-methods Log asynchronously (default: false ) Dene whether parallel methods that dene constraints should file.rotation.file-suffix throw an exception. (default: false ). Rotating log le sux. syslog.async.queue-length The queue length to use before ushing writing (default: 512 ) method-validation.allow-multiple-cascaded-validation-on-return- file.rotation.rotate-on-boot values Indicates rotate logs at bootup (default: true ) syslog.async.overflow Dene whether more than one constraint on a return value may Action when queue is full (default: BLOCK ) be marked for cascading validation are allowed. (default: false ). file.async Logging Log asynchronously (default: false ) You can inject logger instance:

file.async.queue-length import org.jboss.logging.Logger; You can congure how Quarkus logs: The queue length to use before ushing writing (default: 512 ) import io.quarkus.arc.log.LoggerName;

quarkus.log.console.enable=true file.async.overflow @Inject quarkus.log.console.level=DEBUG Logger log; Action when queue is full (default: BLOCK ) quarkus.log.console.color=false quarkus.log.category."com.lordofthejars".level=DEBUG @LoggerName("foo") syslog.enable Logger fooLog; syslog logging is enabled (default: false ) Prex is quarkus.log . public void ping() { syslog.format log.info("Simple!"); category."".level The format pattern to use for logging to syslog. Default value: } Minimum level category (default: INFO ) %d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n

level syslog.level Gelf ouput Default minimum level (default: INFO ) The minimum log level to write to syslog (default: ALL ) You can congure the output to be in GELF format instead of plain text. console.enabled syslog.endpoint Console logging enabled (default: true ) The IP address and port of the syslog server (default: localhost:514 ) ./mvnw quarkus:add-extension -Dextensions="quarkus-logging-gelf" console.format Format pattern to use for logging. Default value: syslog.app-name %d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n The app name used when formatting the message in RFC5424 format (default: current process name) handler.gelf.enabled console.level Enable GELF logging handler (default: false ) syslog.hostname Minimum log level (default: INFO ) The name of the host the messages are being sent from (default: handler.gelf.host console.color current hostname) Hostname/IP of Logstash/Graylof. Prepend tcp: for using TCP protocol. (default: udp:localhost ) Allow color rendering (default: true ) syslog.facility handler.gelf.port file.enable Priority of the message as dened by RFC-5424 and RFC-3164 (default: USER_LEVEL ) The port. (default: 12201 ) File logging enabled (default: false )

syslog.syslog-type handler.gelf.version file.format The syslog type of format message (default: RFC5424 ) Format pattern to use for logging. Default value: GELF version. (default: 1.1 ) %d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n syslog.protocol handler.gelf.extract-stack-trace

file.level Protocol used (default: TCP ) Post Stack-Trace to StackTrace eld. (default: true ) Minimum log level (default: ALL ) syslog.use-counting-framing handler.gelf.stack-trace-throwable-reference

file.path Message prexed with the size of the message (default false ) Gets the cause level to stack trace. 0 is fulls tack trace. (default: ) handler.gelf.filter-stack-trace json.print-details You can still use the JAX-RS client without any problem Stack-Trace ltering. (default: false ) Detailed caller information should be logged (default: false) ClientBuilder.newClient().target(… ) handler.gelf.timestamp-pattern Rest Client Adding headers Java Date pattern. (default: yyyy-MM-dd HH:mm:ss,SSS ) You can customize the headers passed by implementing Quarkus implements MicroProle Rest Client spec: MicroProle ClientHeadersFactory annotation: handler.gelf.level

Log level java.util.logging.Level . (default: ALL ) ./mvnw quarkus:add-extension @RegisterForReflection -Dextensions="quarkus-rest-client" public class BaggageHeadersFactory handler.gelf.facility implements ClientHeadersFactory { Name of the facility. (default: jboss-logmanage ) @Override To get content from http://worldclockapi.com/api/json/cet/now public MultivaluedMap update( handler.gelf.additional-field.. you need to create a service interface: MultivaluedMap incomingHeaders, MultivaluedMap outgoingHeaders) {} Post additional elds. quarkus.log.handler.gelf.additional- } field.field1.type=String @Path("/api") @RegisterRestClient handler.gelf.include-full-mdc public interface WorldClockService { Include all elds from the MDC. And registering it in the client using RegisterClientHeaders @GET @Path("/json/cet/now") annotation. @Produces(MediaType.APPLICATION_JSON) handler.gelf.maximum-message-size WorldClock getNow(); @RegisterClientHeaders(BaggageHeadersFactory.class) Maximum message size (in bytes). (default: 8192 ) @RegisterRestClient @GET public interface WorldClockService {} handler.gelf.include-log-message-parameters @Path("/json/{where}/now") Include message parameters from the log event. (default: true ) @Produces(MediaType.APPLICATION_JSON) WorldClock getSauce(@BeanParam handler.gelf.include-location WorldClockOptions worldClockOptions); Or statically set:

Include source code location. (default: true ) } @GET JSON output @ClientHeaderParam(name="X-Log-Level", value="ERROR") Response getNow(); You can congure the output to be in JSON format instead of plain text. public class WorldClockOptions { @HeaderParam("Authorization") Asynchronous String auth; ./mvnw quarkus:add-extension -Dextensions="quarkus-logging-json" A method on client interface can return a CompletionStage class to @PathParam("where") be executed asynchronously. String where; } @GET @Path("/json/cet/now") And the conguration values are prex with quarkus.log : @Produces(MediaType.APPLICATION_JSON) json CompletionStage getNow(); And congure the hostname at application.properties : JSON logging is enabled (default: true).

org.acme.quickstart.WorldClockService/mp-rest/url= json.pretty-print Reactive http://worldclockapi.com JSON output is "pretty-printed" (default: false) Rest Client also integrates with reactive library named Mutiny. To start using it you need to add the quarkus-rest-client-mutiny . json.date-format Injecting the client: Specify the date format to use (default: the default format) After that, a methodon a client interface can return a io.smallrye.mutiny.Uni instance. @RestClient json.record-delimiter WorldClockService worldClockService; Record delimiter to add (default: no delimiter) @GET @Path("/json/cet/now") @Produces(MediaType.APPLICATION_JSON) json.zone-id Uni getNow(); If invokation happens within JAX-RS, you can propagate headers The time zone ID from incoming to outgoing by using next property. json.exception-output-type A RESTEasy Reactive-based REST Client extension. You only need org.eclipse.microprofile.rest.client.propagateHeaders= to replace the quarkus-rest-client to quarkus-rest-client-reactive . The exception output type: detailed , formatted , detailed-and- Authorization,MyCustomHeader formatted (default: detailed ) Multipart It is really easy to send multipart form-data with Rest Client. Possible conguration properties: @QuarkusTest public class GreetingResourceTest { %s/mp-rest/trustStore org.jboss.resteasy Trust store location dened with classpath: or file: prex. @Test resteasy-multipart-provider public void testHelloEndpoint() { %s/mp-rest/trustStorePassword given() Trust store password. .when().get("/hello") .then() The model object: %s/mp-rest/trustStoreType .statusCode(200) .body(is("hello")); Trust store type (default: JKS ) } import java.io.InputStream; } %s/mp-rest/hostnameVerifier import javax.ws.rs.FormParam; Custom hostname verier class name. To disable SSL verication import javax.ws.rs.core.MediaType; you can use io.quarkus.restclient.NoopHostnameVerifier . Test port can be set in quarkus.http.test-port property. Timeout can be set in quarkus.http.test-timeout property. import %s/mp-rest/keyStore org.jboss.resteasy.annotations.providers.multipart.Part Key store location dened with classpath: or file: prex. Type; You can also inject the URL where Quarkus is started:

%s/mp-rest/keyStorePassword public class MultipartBody { @TestHTTPResource("index.html") Key store password. URL url; @FormParam("file") @PartType(MediaType.APPLICATION_OCTET_STREAM) %s/mp-rest/keyStoreType private InputStream file; Key store type (default: JKS ) @TestHTTPEndpoint(GreetingResource.class) @FormParam("fileName") Timeout @TestHTTPResource @PartType(MediaType.TEXT_PLAIN) URL url; private String name; You can dene the timeout of the Rest Client:

// getter/setters org.acme.quickstart.WorldClockService/mp-rest/connectTimeou } @QuarkusTest t= @TestHTTPEndpoint(GreetingResource.class) 1000 public class GreetingResourceTest { org.acme.quickstart.WorldClockService/mp-rest/readTimeout= @Test And the Rest client interface: 2000 public void testHelloEndpoint() { given() import .when().get() org.jboss.resteasy.annotations.providers.multipart.Mult Instantiate client programmatically .then() ipartForm; .statusCode(200) .body(is("hello")); MovieReviewService reviewSvc = RestClientBuilder.newBuilder @Path("/echo") } () @RegisterRestClient } .baseUri(apiUri) public interface MultipartService { .build(WorldClockService.class);

@POST Root path is calculated automatically, not necessary to explicitly @Consumes(MediaType.MULTIPART_FORM_DATA) set. @Produces(MediaType.TEXT_PLAIN) Testing String sendMultipartData(@MultipartForm If you want any changes made to be rolled back at the end ofthe MultipartBody data); Quarkus archetype adds test dependencies with JUnit 5 and Rest- test you can use the io.quarkus.test.TestTransaction annotation. Assured library to test REST endpoints. } QuarkusTestProle

You can dene for each Test class a different conguration options. SSL This implies that the Quarkus service is restarted. You can congure Rest Client key stores.

org.acme.quickstart.WorldClockService/mp-rest/trustStore= classpath:/store.jks org.acme.quickstart.WorldClockService/mp-rest/trustStorePas sword= supersecret And needs to be registered as Java SPI: public class MyProfile implements io.quarkus.test.junit.Qua public class MyCustomTestResource rkusTestProfile { implements QuarkusTestResourceLifecycleManager { META- INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback @Override @Override io.quarkus.it.main.SimpleAnnotationCheckerBeforeClassCallba public Map getConfigOverrides() { public Map start() { ck return Map.of("greetings.message", "This is a Test" // return system properties that ); // should be set for the running test } return Collections.emptyMap(); } Mocking @Override public String getConfigProfile() { @Override If you need to provide an alternative implementation of a service return "my-test-profile"; public void stop() { (for testing purposes) you can do it by using CDI @Alternative } } annotation using it in the test service placed at src/test/java :

@Override // optional @Alternative public Set tags() { @Override @Priority(1) return Collections.singleton("test1"); public void inject(Object testInstance) { @ApplicationScoped } } public class MockExternalService extends ExternalService {} } // optional @QuarkusTest @Override @TestProfile(MyProfile.class) public int order() { This does not work when using native image testing. public class MyTestClass { return 0; } } } A stereotype annotation io.quarkus.test.Mock is provided declaring @Alternative , @Priority(1) and @Dependent . quarkus.test.profile.tags property can be set to limit test Mockito execution of test proles. If not set all tests are executed. Returning new system properties implies running parallel tests in different JVMs. Instead of creating stubs, you can also create mocks of your quarkus.test.profile.tags=test1 services with mockito. Add the following dependency And the usage: io.quarkus:quarkus-junit5-mockito :

Quarkus Test Resource @QuarkusTestResource(MyCustomTestResource.class) @InjectMock public class MyTest { GreetingService greetingService; You can execute some logic before the rst test run ( start ) and } execute some logic at the end of the test suite ( stop ). @BeforeEach public void setup() { You need to create a class implementing Mockito.when(greetingService.greet()).thenReturn("Hi"); When using multiple QuarkusTestResource you can set parallel QuarkusTestResourceLifecycleManager interface and register it in the } attribute to true to start them concurrently. test via @QuarkusTestResource annotation. Testing Callbacks @Path("/hello") public class ExampleResource { You can enrich all your @QuarkusTest classes by implementing the following callback interfaces: @Inject GreetingService greetingService; io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback }

io.quarkus.test.junit.callback.QuarkusTestAfterConstructCall back Mock is automatically injected and only valid for the dened test class. io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback

Also spy is supported: io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback

@InjectSpy public class SimpleAnnotationCheckerBeforeClassCallback imp GreetingService greetingService; lements QuarkusTestBeforeClassCallback {

@Override Mockito.verify(greetingService, Mockito.times(1)).greet(); public void beforeClass(Class testClass) { } } REST Client To Mock REST Client, you need to dene the interface with includes Persistence @ApplicationScope : A list of class les to include in the report. (default: ** ) Quarkus works with JPA(Hibernate) as persistence solution. But @ApplicationScoped excludes also provides an Active Record pattern implementation under @RegisterRestClient A list of class les to exclude from the report. Panache project. public interface GreetingService { } To use database access you need to add Quarkus JDBC drivers report-location instead of the original ones. At this time Apache Derby , H2 , MariaDB , @InjectMock The location of the report les. (default: jacoco-report ) MySQL , MSSQL and PostgreSQL drivers are supported. @RestClient Native Testing GreetingService greetingService; ./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-hibernate-orm-panache, To test native executables annotate the test with @NativeImageTest . Mockito.when(greetingService.hello()).thenReturn("hello fro io.quarkus:quarkus-jdbc-" m mockito"); Quarkus Integration Tests

@QuarkusIntegrationTest should be used to launch and test the Interceptors artifact produced by the Quarkus build. If the result of a Quarkus @Entity build is a JAR then the app is launched as java -jar , if native is public class Developer extends PanacheEntity { Tests are actually full CDI beans, so you can apply CDI interceptors: launched as ./application , if container image is created (JiB, extensions) is launched as docker run . // id field is implicit

@QuarkusTest public String name; @Stereotype } @Transactional @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface TransactionalQuarkusTest { And conguration in src/main/resources/application.properties : } quarkus.datasource.jdbc.url=jdbc:mariadb://localhost:3306/m @TransactionalQuarkusTest ydb public class TestStereotypeTestCase {} quarkus.datasource.db-kind=mariadb quarkus.datasource.username=developer quarkus.datasource.password=developer Test Coverage quarkus.hibernate-orm.database.generation=update

Due the nature of Quarkus to calculate correctly the coverage information with JaCoCo, you might need oine instrumentation. List of datasource parameters.

./mvnw quarkus:add-extension quarkus.datasource as prex is skipped in the next table. -Dextensions="quarkus-jacoco " db-kind Built-in datasource kinds so the JDBC driver is resolved automatically. Possible values: derby , h2 , mariadb , mssql , mysql , Possible conguration parameters prexed quarkus.jacoco : postgresql , db2 . data-file username The jacoco data le. (default: jacoco-quarkus.exec ) Username to access. report password If Quarkus should generate the Jacoco report. (default: true ) Password to access. output-encoding driver Encoding of the generated reports. (default: UTF-8 ) JDBC Driver class. It is not necessary to set if db-kind used. title Name of the root node HTML report pages. credentials-provider Sets a custom credential provider name. footer Footer text used in HTML report pages. credentials-provider-name It is the @Named value of the credentials provider bean. Not source-encoding necessary if only one implementation. Encoding of the source les (default: UTF-8 ) jdbc.url dialect Number of rows fetched at a time. The datasource URL. Class name of the Hibernate ORM dialect. jdbc.statement-batch-size jdbc.min-size dialect.storage-engine Number of updates sent at a time. The datasource pool minimum size. (default: 0 ) The storage engine when the dialect supports multiple storage engines. log.sql jdbc.max-size Show SQL logs (default: false ) The datasource pool maximum size. (default: 20 ) sql-load-script Name of the le containing the SQL statements to execute when log.jdbc-warnings jdbc.initial-size starts. no-file force Hibernate to skip SQL import. (default: statistics import.sql ) The initial size of the pool. Enable statiscs collection. (default: false )

batch-fetch-size jdbc.background-validation-interval physical-naming-strategy The interval at which we validate idle connections in the The size of the batches. (default: -1 disabled) Class name of the Hibernate PhysicalNamingStrategy background. (default: 2M ) implementation. maxFetchDepth

jdbc.acquisition-timeout The maximum depth of outer join fetch tree for single-ended globally-quoted-identifiers associations. The timeout before cancelling the acquisition of a new Should quote all identiers. (default: false ) connection. (default: 5 ) multitenant metrics-enabled jdbc.leak-detection-interval Denes the method for multi-tenancy. Possible values: DATABASE , Metrics published with smallrye-metrics extension (default: NONE , SCHEMA . (default: NONE ) The interval at which we check for connection leaks. false )

multitenant-schema-datasource jdbc.idle-removal-interval second-level-caching-enabled Denes the name of the data source to use in case of SCHEMA The interval at which we try to remove idle connections. (default: Enable/Disable 2nd level cache. (default: true ) approach. 5M ) Database operations: query.query-plan-cache-max-size jdbc.max-lifetime The max lifetime of a connection. The maximum size of the query plan cache. // Insert Developer developer = new Developer(); query.default-null-ordering jdbc.transaction-isolation-level developer.name = "Alex"; Default precedence of null values in ORDER BY . Possible values: developer.persist(); The transaction isolation level. Possible values: UNDEFINED , NONE , none , first , last . (default: none ) READ_UNCOMMITTED , READ_COMMITTED , REPEATABLE_READ , SERIALIZABLE . // Find All database.generation Developer.findAll().list(); jdbc.detect-statement-leaks

Database schema is generation. Possible values: none , create , Warn when a connection is returned to the pool without the // Hibernate Filters drop-and-create , drop , update . (default: none ) application having closed all open statements. (default: true ) Person.findAll().filter("Person.hasName", Parameters.with( "name", "Alex")); database.generation.halt-on-error jdbc.new-connection-sql Query executed when rst using a connection. Stop on the rst error when applying the schema. (default: false ) // Find By Query Developer.find("name", "Alex").firstResult(); database.generation.create-schemas jdbc.validation-query-sql Query executed to validate a connection. Hibernate ORM should create the schemas automatically (for // Delete databases supporting them). Developer developer = new Developer(); developer.id = 1; jdbc.pooling-enabled database.default-catalog developer.delete(); Disable pooling to prevent reuse of Connections. (default: true ) Default catalog. Person.deleteById(id); jdbc.enable-metrics // Delete By Query database.default-schema Enable datasource metrics collection when using quarkus- long numberOfDeleted = Developer.delete("name", "Alex"); Default Schema. smallrye-metrics extension.

database.charset jdbc.additional-jdbc-properties. Remember to annotate methods with @Transactional annotation to Charset. Unspecied properties to be passed to the JDBC driver when make changes persisted in the database. creating new connections. jdbc.timezone If queries start with the keyword from then they are treated as HQL Hibernate conguration properties. Prex quarkus.hibernate-orm is Time Zone JDBC driver. query, if not then next short form is supported: skipped. jdbc.statement-fetch-size order by which expands to from EntityName order by … which expands to from EntityName where count : String , [ Object… , Map , Parameters ] If entities are dened in external JAR, you need to enable in these =? Number of entities meeting given query with parameters set. projects the Jandex plugin in project.

which is expanded to from EntityName where Enables a Hibernate lter during fetching of results for this query. Static Methods org.jboss.jandex deleteAll jandex-maven-plugin findById : Object Number of deleted entities. 1.0.3 Returns object or null if not found. Overloaded version with delete : String , [ Object… , Map , Parameters ] LockModeType is provided. make-index Number of deleted entities meeting given query with parameters findByIdOptional : Optional set. jandex Returns object or java.util.Optional . deleteById : boolean , [ Object ] find : String , [ Object… , Map , Parameters ] Delete by id. Returns if deleted or not. Lists of entities meeting given query with parameters set. Returning a PanacheQuery . persist : [ Iterable , Steram , Object… ] Persist object. org.jboss find : String , Sort , [ Object… , Map , Parameters ] jandex 2.1.1.Final Lists of entities meeting given query with parameters set sorted In case of using streams, remember to close them or use a by Sort attribute/s. Returning a PanacheQuery . try/catch block: try (Stream persons = Person.streamAll()) . find methods denes a withLock(LockModeType) to dene findAll the lock type and withHint(QueryHints.HINT_CACHEABLE, Finds all entities. Returning a PanacheQuery . "true") to dene hints. Panache includes an annotation processor that enhance your findAll : Sort Named Queries entities. If you disable annotation processors you might need to Finds all entities sorted by Sort attribute/s. Returning a create a marker le on Panache archives at META-INF/panache- PanacheQuery . @Entity archive.marker manually. @NamedQuery(name = "Person.getByName", query = "from Person list : String , [ Object… , Map , Parameters ] where name = :name") Testing Lists of entities meeting given query with parameters set. public class Person extends PanacheEntity { To mock using active record pattern: Returning a List . public static Person findByName(String name){ list : String , Sort , [ Object… , Map , Parameters ] return find("#Person.getByName", name).firstResult io.quarkus Lists of entities meeting given query with parameters set sorted (); } quarkus-panache-mock by Sort attribute/s. Returning a List . } test listAll Finds all entities. Returning a List . Pagination listAll : Sort @Test PanacheQuery livingPersons = Person public void testPanacheMocking() { Finds all entities sorted by Sort attribute/s. Returning a List . .find("status", Status.Alive); PanacheMock.mock(Person.class); livingPersons.page(Page.ofSize(25)); stream : String , [ Object… , Map , Parameters ] Mockito.when(Person.count()).thenReturn(23l); java.util.stream.Stream of entities meeting given query with // get the first page Assertions.assertEquals(23, Person.count()); parameters set. List firstPage = livingPersons.list(); PanacheMock.verify(Person.class, Mockito.times(1)).coun // get the second page t(); stream : String , Sort , [ Object… , Map , Parameters ] List secondPage = livingPersons.nextPage().list(); } java.util.stream.Stream of entities meeting given query with parameters set sorted by Sort attribute/s. Range DevServices streamAll When testing or running in dev mode Quarkus can even provide you java.util.stream.Stream of all entities. PanacheQuery livingPersons = Person with a zero cong database out of the box. Depending on your .find("status", Status.Alive); database type you may need docker installed in order to use this streamAll : Sort List secondRange = livingPersons.range(25, 49).list feature. java.util.stream.Stream of all entities sorted by Sort attribute/s. (); The following open source databases: count Number of entities You cannot mix pagination and range Postgresql (container) MySQL (container) @Transactional(REQUIRES_NEW) : starts a transaction if none was # default started; if an existing one was started, suspends it and starts a quarkus.datasource.db-kind=h2 MariaDB (container) new one for the boundary of that method. quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:def ault H2 (in-process) @Transactional(MANDATORY) : fails if no transaction was started ; .... works within the existing transaction otherwise. Apache Derby (in-process) # users datasource quarkus.datasource.users.devservices=false @Transactional(SUPPORTS) : if a transaction was started, joins it ; To use DevServices don’t congure a database URL, username and quarkus.datasource.users.db-kind=h2 otherwise works with no transaction. password, Quarkus will provide the database and you can just start quarkus.datasource.users.jdbc.url=jdbc:h2:tcp://localhost/m coding without worrying about cong. em:users @Transactional(NOT_SUPPORTED) : if a transaction was started, suspends it and works with no transaction for the boundary of quarkus.datasource.db-kind=mariadb the method; otherwise works with no transaction. %prod.quarkus.datasource.jdbc.url=jdbc:mariadb://db:3306/my Notice that after datasource you set the datasource name, in @Transactional(NEVER) : if a transaction was started, raises an db previous case users . %prod.quarkus.datasource.username=developer exception; otherwise works with no transaction. %prod.quarkus.datasource.password=developer You can inject then AgroalDataSource with You can congure the default transaction timeout using io.quarkus.agroal.DataSource . quarkus.transaction-manager.default-transaction-timeout conguration property. By default it is set to 60 seconds. Possible conguration values prexed with quarkus.datasource : @DataSource("users") AgroalDataSource dataSource1; You can set a timeout property, in seconds, that applies to devservices transactions created within the annotated method by using If devservices is enabled or not. (default: true ) @TransactionConfiguration annotation. Flushing devservices.image-name @Transactional The container image name to use instead of the default one. You can force ush operation by calling .flush() or @TransactionConfiguration(timeout=40) .persistAndFlush() to make it in a single call. public void createDeveloper() {} devservices.properties This ush is less ecient and you still need to commit Generic properties that are added to the database connection transaction. URL. If you want more control over transactions you can inject UserTransaction and use a programmatic way. Testing DAO pattern There is a Quarkus Test Resource that starts and stops H2 server @Inject UserTransaction transaction Also supports DAO pattern with PanacheRepository . before and after test suite. transaction.begin(); @ApplicationScoped Register dependency io.quarkus:quarkus-test-h2:test . transaction.commit(); public class DeveloperRepository transaction.rollback(); implements PanacheRepository { And annotate the test: public Person findByName(String name){ return find("name", name).firstResult(); @QuarkusTestResource(H2DatabaseTestResource.class) You can implement your custom credentials provider (ie Azure } public class FlywayTestResources { KeyVault) to provide a username/password for the database } } connection. Name information is not necessary if there is only one custom credential provider.

EntityManager You can inject EntityManager in your classes: Transactions

@Inject The easiest way to dene your transaction boundaries is to use the EntityManager em; @Transactional annotation.

@Inject Transactions are mandatory in case of none idempotent org.hibernate.Session session; operations.

@Inject @Transactional org.hibernate.SessionFactory sessionFactory; public void createDeveloper() {}

em.persist(car); You can control the transaction scope:

Multiple datasources @Transactional(REQUIRED) (default): starts a transaction if none was started, stays with the existing one otherwise. You can register more than one datasource. get(@PathParam("id")) , list , add(Developer) , @ApplicationScoped quarkus.hibernate-orm.database.generation=none update(@PathParam("id"), Developer) , delete(@PathParam("id")) @Unremovable @Named("my-credentials-provider") quarkus.hibernate-orm.multitenant=DATABASE You can customize these defaults by using @ResourceProperties and public class CustomCredentialsProvider implements Credentia @MethodProperties annotations. lsProvider { # default tenant @Inject quarkus.datasource.base.db-kind=postgresql Config config; quarkus.datasource.base.username=quarkus_test @ResourceProperties(hal = true, path = "my-developer", halC ... ollectionName = "dev-collections") @Override # Tenant 'mycompany' public interface DeveloperResource extends PanacheEntityRes public Properties getCredentials(String credentials quarkus.datasource.mycompany.db-kind=postgresql ource { ProviderName) { quarkus.datasource.mycompany.username=mycompany @MethodProperties(path = "all") quarkus.flyway.mycompany.locations=classpath:database/mycom List list(); properties.put(CredentialsProvider.USER_PROPERTY_NA pany @MethodProperties(exposed = false) ME, "hibernate_orm_test"); ... void delete(Long id); properties.put(CredentialsProvider.PASSWORD } _PROPERTY_NAME, "hibernate_orm_test");

If you need more dynamic approach implement: @ApplicationScoped } io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver If hal is true , you need to send the Accept: application/hal+json } HTTP header to get the response. Hibernate Envers Hibernate Reactive

quarkus.datasource.credentials-provider= Quarkus supports Hibernate Envers. custom ./mvnw quarkus:add-extension quarkus.datasource.credentials-provider-name= ./mvnw quarkus:add-extension -Dextensions="quarkus-hibernate-reactive, quarkus-resteas my-credentials-provider -Dextensions="hibernate-envers" y-mutiny, "

Hibernate Multitenancy REST Data Panache Also you need to add the reactive driver (ie quarkus-reactive-pg- client ). Multitenancy is supported using Schema or Database approach. REST Data with Panache extension can generate the basic CRUD First you need to dene how tenant is identied: You can use: org.hibernate.reactive.mutiny.Mutiny or endpoints for your entities and repositories. org.hibernate.reactive.stage.Stage . @RequestScoped @Unremovable ./mvnw quarkus:add-extension @Entity public class CustomTenantResolver implements TenantResolver -Dextensions="hibernate-orm-rest-data-panache" @Table(name = "dev") { public class Developer { } @Inject You also need to add the JDBC driver extension and a JSON RoutingContext context; Marshaller (ie resteasy-jackson ). @Inject CompletionStage stageSession; @Override Then you can dene interfaces for dening endpoints: public String getDefaultTenantId() { @Inject return "base"; In case of Active Record pattern: Uni mutinySession; } public interface DeveloperResource extends PanacheEntityRes public Uni reactivePersist() { @Override ource { return mutinySession public String resolveTenantId() { } .flatMap(s -> s.persist(new Developer(1, "Alex")) } .flatMap(v -> session.flush()) .... } In case of Repository: }

public interface DeveloperResource extends PanacheRepositor Schema approach public CompletionStage reactiveFind() { yResource { return stageSession } .thenCompose(session -> { quarkus.hibernate-orm.database.generation=none session.find(Developer.class, 1); }); quarkus.hibernate-orm.multitenant=SCHEMA Quarkus will generate automatically the implementation for you } following the next rules:

Database approach Default path is a hyphenated lowercase resource name without a sux of or Innispan Quarkus integrates with Innispan: @Produces Conguration in infinispan.xml : FileDescriptorSource bookProtoDefinition() { ./mvnw quarkus:add-extension return FileDescriptorSource -Dextensions="infinispan-client" .fromString("library.proto", "package book_sample;\n" + Annotation based "}"); }

@ProtoFactory public Author(String name, String surname) { Set conguration le location in application.properties : this.name = name; Marshaller this.surname = surname; quarkus.infinispan-embedded.xml-config=infinispan.xml } Using org.infinispan.protostream.MessageMarshaller interface.

@ProtoField(number = 1) public class AuthorMarshaller And you can inject the main entry point for the cache: public String getName() { implements MessageMarshaller { return name; @Inject } @Override org.infinispan.manager.EmbeddedCacheManager cacheManager; public String getTypeName() { @ProtoField(number = 2) return "book_sample.Author"; public String getSurname() { } return surname; Redis } @Override public Class getJavaClass() { Quarkus integrates with Redis. return Author.class; } Initializer to set conguration settings. ./mvnw quarkus:add-extension

-Dextensions="redis-client" @Override @AutoProtoSchemaBuilder(includeClasses = public void writeTo(ProtoStreamWriter writer, { Book.class, Author.class }, Author author) throws IOException { schemaPackageName = "book_sample") writer.writeString("name", author.getName()); Congure Redis location: interface BookContextInitializer writer.writeString("surname", author.getSurname()); extends SerializationContextInitializer { } } quarkus.redis.hosts=localhost:6379

@Override public Author readFrom(ProtoStreamReader reader) User written based throws IOException { You can use synchronous or reactive clients: String name = reader.readString("name"); There are three ways to create your schema: String surname = reader.readString("surname"); @Inject return new Author(name, surname); RedisClient redisClient; Protole } } @Inject Creates a .proto le in the META-INF directory. ReactiveRedisClient reactiveRedisClient;

package book_sample; And producing the marshaller:

message Author { required string name = 1; @Produces required string surname = 2; MessageMarshaller authorMarshaller() { } return new AuthorMarshaller(); }

In case of having a Collection eld you need to use the repeated key (ie repeated Author authors = 4 ). Innispan Embedded

In code ./mvnw quarkus:add-extension -Dextensions="infinispan-embeddedy" Setting proto schema directly in a produced bean. sql-migration-prefix void increment(String key, Integer incrementBy) { Flyway redisClient.incrby(key, incrementBy.toString()); Prex for versioned SQL migrations (default: V ) } Quarkus integrates with Flyway to help you on database schema migrations. repeatable-sql-migration-prefix:: Prex for repeatable SQL Uni> keys() { migrations (default: R ) return reactiveRedisClient ./mvnw quarkus:add-extension baseline-on-migrate .keys("*") -Dextensions="quarkus-flyway" .map(response -> { Only migrations above baseline-version will then be applied List result = new ArrayList<>(); for (Response r : response) { baseline-version Then place migration les to the migrations folder result.add(r.toString()); ( classpath:db/migration ). Version to tag an existing schema with when executing baseline } (default: 1) return result; You can inject org.flywaydb.core.Flyway to programmatically }); execute the migration. baseline-description } Description to tag an existing schema with when executing @Inject baseline (default: Flyway Baseline ) Flyway flyway; Multiple Redis Clients validate-on-migrate flyway.migrate(); Validate the applied migrations against the available ones quarkus.redis.hosts = localhost:6379 (default: true ) quarkus.redis.second.hosts = localhost:6379

Or can be automatically executed by setting migrate-at-start placeholder-prefix property to true . Prex of every placeholder (default: ${ ) @Inject RedisClient defaultRedisClient; quarkus.flyway.migrate-at-start=true placeholder-suffix Sux of every placeholder (default: } ) @Inject @RedisClientName("second") List of Flyway parameters. callbacks RedisClient redisClient2; Comma-separated list of fully qualied class names of Callback quarkus.flyway as prex is skipped in the next table. implementations.

clean-at-start List of Redis parameters. ignore-future-migrations Execute Flyway clean command (default: false ) Ignore future migrations when reading the history table. quarkus.redis as prex is skipped in the next table. migrate-at-start health.enabled Multiple Datasources Flyway migration automatically (default: false ) Health check is published in case the smallrye-health extension To use multiple datasource in Flyway you just need to add the is present. (default: true ) locations datasource name just after the flyway property: CSV locations to scan recursively for migrations. Supported password prexes classpath and filesystem (default: quarkus.datasource.users.jdbc.url=jdbc:h2:tcp://localhost/m The Redis password. classpath:db/migration ). em:users quarkus.datasource.inventory.jdbc.url=jdbc:h2:tcp://localho hosts connect-retries st/mem:inventory The Redis hosts. (default: localhost:6379 ) The maximum number of retries when attempting to connect # ... (default: 0) database quarkus.flyway.users.schemas=USERS_TEST_SCHEMA quarkus.flyway.inventory.schemas=INVENTORY_TEST_SCHEMA The Redis database. schemas # ... CSV case-sensitive list of schemas managed (default: none) timeout The maximum delay to wait before a blocking command to redis table server times out. (default: 10s ) The name of Flyway’s schema history table (default: Liquibase flyway_schema_history ) ssl Quarkus integrates with Liquibase to help you on database schema Enables or disables the SSL on connect. out-of-order migrations. Allows migrations to be run "out of order". clinet-type ./mvnw quarkus:add-extension The Redis client type. Possible values: standalone , cluster , ignore-missing-migrations -Dextensions="quarkus-liquibase" sentinel (default: standalone ) Ignore missing migrations when reading the history table. Then place changelog les to the ( src/main/resources/db ) folder. liquibase-catalog-name You need to dene the analyzers and normalizers dened in The liquibase tables catalog name. annotations. You only need to implement You can inject org.quarkus.liquibase.LiquibaseFactory to ElasticsearchAnalysisConfigurer interface and congure it. programmatically execute the migration. liquibase-schema-name The liquibase tables schema name. public class MyQuarkusAnalysisConfigurer @Inject implements ElasticsearchAnalysisConfigurer { LiquibaseFactory liquibaseFactory; liquibase-tablespace-name @Override try (Liquibase liquibase = liquibaseFactory.createLiquibase The liquibase tables tablespace name. public void configure( ()) { ElasticsearchAnalysisDefinitionContainerContext ct ... Multiple Datasources x) } { To use multiple datasource in Liquibase you just need to add the ctx.analyzer("english").custom() datasource name just after the liquibase property: .withTokenizer("standard") Or can be automatically executed by setting migrate-at-start .withTokenFilters("asciifolding", quarkus.datasource.users.jdbc.url=jdbc:h2:tcp://localhost/m property to true . "lowercase", "porter_stem"); em:users quarkus.datasource.inventory.jdbc.url=jdbc:h2:tcp://localho ctx.normalizer("sort").custom() quarkus.liquibase.migrate-at-start=true st/mem:inventory .withTokenFilters("asciifolding", "lowercase"); # ... } } List of Liquibase parameters. quarkus.liquibase.users.schemas=USERS_TEST_SCHEMA quarkus.liquibase.inventory.schemas=INVENTORY_TEST_SCHEMA quarkus.liquibase as prex is skipped in the next table. # ... Use Hibernate Search in REST service: change-log The change log le. XML , YAML , JSON , SQL formats supported. public class LibraryResource { (default: db/changeLog.xml ) Hibernate Search @Inject change-log-parameters."" Quarkus integrates with Elasticsearch to provide a full-featured full- EntityManager em; text search using Hibernate Search API. Liquibase changelog parameters. @Transactional public List searchAuthors( migrate-at-start ./mvnw quarkus:add-extension -Dextensions="quarkus-hibernate-search-elasticsearch" @QueryParam("pattern") String pattern) { The migrate at start ag. (default: false ) return Search.getSearchSession(em) .search(Author.class) validate-on-migrate .predicate(f -> You need to annotate your model with Hibernate Search API to The validate on update ag. (default: false ) pattern == null || pattern.isEmpty() ? index it: f.matchAll() : clean-at-start f.simpleQueryString() @Entity .onFields("firstName", The clean at start ag. (default: false ) @Indexed "lastName", "books.title") public class Author extends PanacheEntity { .matching(pattern) contexts ) The list of contexts. @FullTextField(analyzer = "english") .sort(f -> f.byField("lastName_sort") public String bio; .then().byField("firstName_sort")) labels .fetchHits(); The list of labels. @FullTextField(analyzer = "name") } @KeywordField(name = "firstName_sort", database-change-log-table-name sortable = Sortable.YES, normalizer = "sort") When not using Hibernate ORM, index data using The database change log lock table name. (default: public String firstName; Search.getSearchSession(em).createIndexer() DATABASECHANGELOG ) .startAndWait() at startup time. @OneToMany database-change-log-lock-table-name @IndexedEmbedded Congure the extension in application.properties : The database change log lock table name. (default: public List books; DATABASECHANGELOGLOCK ) } default-catalog-name The default catalog name. default-schema-name It is not mandatory to use Panache. The default schema name When enabled, re-indexing of is skipped if the changes are on quarkus.hibernate-search.elasticsearch.version=7 @Inject properties that are not used when indexing. quarkus.hibernate-search.elasticsearch. DynamoDbClient dynamoDB; analysis-configurer=MyQuarkusAnalysisConfigurer quarkus.hibernate-search.elasticsearch. index-defaults.lifecycle.strategy Index lifecycle ( none , validate , update , create , drop-and-create , automatic-indexing.synchronization-strategy=searchable To use asycnhronous client with Mutiny: quarkus.hibernate-search.elasticsearch. drop-abd-create-drop ) index-defaults.lifecycle.strategy=drop-and-create ./mvnw quarkus:add-extension quarkus.hibernate-search.elasticsearch. index-defaults.lifecycle.required-status -Dextensions="quarkus-amazon-dynamodb, resteasy-mutiny" index-defaults.lifecycle.required-status=yellow Minimal cluster status ( green , yellow , red )

index-defaults.lifecycle.required-status-wait-timeout List of Hibernate-Elasticsearch properties prexed with Waiting time before failing the bootstrap. @Inject quarkus.hibernate-search.elasticsearch : DynamoDbAsyncClient dynamoDB; index-defaults.refresh-after-write backends Set if index should be refreshed after writes. Uni.createFrom().completionStage(() -> dynamoDB.scan(scanRe Map of conguration of additional backends. quest())).... Possible annotations: version Version of Elasticsearch @Indexed To use it as a local DynamoDB instance: Register entity as full text index analysis-configurer quarkus.dynamodb.region= Class or name of the neab used to congure. @FullTextField eu-central-1 Full text search. Need to set an analyzer to split tokens. quarkus.dynamodb.endpoint-override= hosts http://localhost:8000 quarkus.dynamodb.credentials.type=STATIC List of Elasticsearch servers hosts. @KeywordField quarkus.dynamodb.credentials.static-provider The string is kept as one single token but can be normalized. .access-key-id=test-key username quarkus.dynamodb.credentials.static-provider Username for auth. IndexedEmbedded .secret-access-key=test-secret Include the Book elds into the Author index. password Password for auth. @ContainerExtraction If you want to work with an AWS account, you’d need to set it with: Sets how to extract a value from container, e.g from a Map . connection-timeout quarkus.dynamodb.region= Duration of connection timeout. @DocumentId quarkus.dynamodb.credentials.type=DEFAULT Map an unusual entity identier to a document identier. max-connections Max number of connections to servers. @GenericField DEFAULT credentials provider chain: Full text index for any supported type. max-connections-per-route System properties aws.accessKeyId , aws.secretKey Max number of connections to server. @IdentifierBridgeRef Env. Varables AWS_ACCESS_KEY_ID , AWS_SECRET_ACCESS_KEY Reference to the identier bridge to use for a @DocumentId . indexes Credentials prole ~/.aws/credentials Per-index specic conguration. @IndexingDependency How a dependency of the indexing process to a property should Credentials through the Amazon EC2 container service if the discovery.enabled affect automatic reindexing. AWS_CONTAINER_CREDENTIALS_RELATIVE_URI set Enables automatic discovery. @ObjectPath Credentials through Amazon EC2 metadata service. discovery.refresh-interval @ScaledNumberField Conguration parameters prexed with quarkus.dynamodb : Refresh interval of node list. For java.math.BigDecimal or java.math.BigInteger that you need higher precision. discovery.default-scheme Parameter Default Description Scheme to be used for the new nodes. Amazon DynamoDB Endpoint discovery automatic-indexing.synchronization-strategy Quarkus integrates with https://aws.amazon.com/dynamodb/: enable-endpoint- for a service API that false Status for which you wait before considering the operation discovery supports endpoint completed ( queued , committed or searchable ). ./mvnw quarkus:add-extension discovery. -Dextensions="quarkus-amazon-dynamodb" automatic-indexing.enable-dirty-check endpoint-override Congure the Parameter Default Description Parameter Default Description endpoint with which the SDK should PROFILE Connections in pool use-idle-connection- communicate. true should be closed reaper asynchronously. profile- The name of the Time to complete an default api-call-timeout provider.profile-name prole to use. execution. Endpoint of the proxy proxy.endpoint server. PROCESS List of class interceptors interceptors. proxy.enabled false Enables HTTP proxy. Command to execute process- to retrieve provider.command Conguration parameters prexed with quarkus.dynamodb.aws : credentials. proxy.username Proxy username. Parameter Default Description process- proxy.password Proxy password. Max bytes to retrieve Region that hosts provider.process- 1024 region from process. DynamoDB. output-limit For NTLM, domain proxy.ntlm-domain name. Credentials that The amount of time process- should be used between credentials provider.credential- PT15S DEFAULT , STATIC , expire and proxy.ntlm- For NTLM, refresh-threshold SYSTEM_PROPERTY , workstation workstation name. credentials.type DEFAULT credentials refreshed. ENV_VARIABLE , PROFILE , CONTAINER , INSTANCE_PROFILE , process- proxy.preemptive- Authenticate pre- PROCESS , ANONYMOUS provider.async- Should fetch basic-authentication- false emptively. credential-update- credentials async. enabled enabled Credentials specic parameters prexed with quarkus.dynamodb.aws.credentials : proxy.non-proxy- List of non proxy In case of synchronous client, the next parameters can be hosts hosts. Parameter Default Description congured prexed by quarkus.dynamodb.sync-client :

TLS manager: none , DEFAULT Parameter Default Description tls-managers- system-property system-property , provider.type connection- Connection file-store 10S default- acquisition-timeout acquisation timeout. provider.async- Should fetch false credential-update- credentials async. tls-managers- enabled Max time to provider.file- Path to key store. connection-max-idle- 60S connection to be store.path time opened. default- Should reuse the last provider.reuse-last- true successful tls-managers- provider-enabled credentials. connection-timeout Connection timeout. provider.file- Key store type. store.type

STATIC connection-time-to- Max time connection 0 live to be open. tls-managers- provider.file- Key store password. static- store.password provider.access-key- AWS access key id. socket-timeout 30S Time to wait for data. id In case of asynchronous client, the next parameters can be max-connections 50 Max connections. congured prexed by quarkus.dynamodb.async-client : static- AWS secret access Parameter Default Description provider.secret- key. access-key Client send an HTTP expect-continue- true expect-continue connection- Connection enabled 10S handsake. acquisition-timeout acquisation timeout. Parameter Default Description Parameter Default Description quarkus.s3.endpoint-override=http://localhost:8008 quarkus.s3.interceptors=io.quarkus.it.amazon.s3.S3ModifyRes Max time to Sets the HTTP connection-max-idle- protocol HTTP_1_1 ponse 60S connection to be protocol. time quarkus.s3.aws.region=us-east-1 opened. quarkus.s3.aws.credentials.type=static quarkus.s3.aws.credentials.static-provider.access-key-id=te Max number of max-http2-streams st-key connection-timeout Connection timeout. concurrent streams. quarkus.s3.aws.credentials.static-provider.secret-access-ke y=test-secret

connection-time-to- Max time connection Enable custom event 0 event-loop.override false live to be open. loop conf. You can inject asynchronous client too:

Max number of event-loop.number-of- Number of threads to @Inject max-concurrency 50 concurrent threads use in event loop. S3AsyncClient s3AsyncClient; connections.

event-loop.thread- aws-java-sdk- Prex of thread And you need to add the asynchronous Netty client: Connections in pool name-prefix NettyEventLoop names. use-idle-connection- true should be closed reaper asynchronously. Amazon S3 software.amazon.awssdk netty-nio-client read-timeout 30S Read timeout. ./mvnw quarkus:add-extension -Dextensions="quarkus-amazon-s3" write-timeout 30S Write timeout. Conguration properties are the same as Amazon DynamoDB but changing the prex from dynamodb to s3 . Endpoint of the proxy @Inject proxy.endpoint server. S3Client s3Client; Neo4j

Quarkus integrates with Neo4j: proxy.enabled false Enables HTTP proxy. You need to set a HTTP client either URL Connection : ./mvnw quarkus:add-extension -Dextensions="quarkus-neo4j" proxy.non-proxy- List of non proxy hosts hosts. software.amazon.awssdk url-connection-client @Inject TLS manager: none , tls-managers- org.neo4j.driver.Driver driver; system-property system-property , provider.type file-store or Apache HTTP: Conguration properties: tls-managers- software.amazon.awssdk provider.file- Path to key store. quarkus.neo4j as prex is skipped in the next table. apache-client store.path Prex is quarkus.neo4j .

uri tls-managers- provider.file- Key store type. URI of Neo4j. (default: localhost:7687 ) quarkus.s3.sync-client.type=apache store.type authentication.username Username. (default: neo4j ) tls-managers- And congure it: provider.file- Key store password. authentication.password store.password Password. (default: neo4j )

SSL Provider ( jdk , authentication.disabled ssl-provider openssl , openssl- Disable authentication. (default: false ) refcnt ). Enable metrics. (default: false ) @GET quarkus.mongodb as prex is skipped in the following table. public Publisher get() { pool.log-leaked-sessions return Multi.createFrom().resource(driver::rxSession, Parameter Type Description Enable leaked sessions logging. (default:`false`) session -> session.readTransaction(tx -> { RxResult result = tx.run("MATCH (f:Fruit) RETUR MongoDB connection connection-string String pool.max-connection-pool-size N f.name as name"); URI. Max amount of connections. (default: 100 ) return Multi.createFrom().publisher(result.reco rds()) .map(record -> record.get("name").asStr pool.max-connection-lifetime Addresses passed as ing()); hosts List Pooled connections older will be closed and removed from the host:port . }) pool. (default: 1H ) ).withFinalizer(session -> { return Uni.createFrom().publisher(session.close()); application-name String Application name. pool.connection-acquisition-timeout }); Timout for connection adquisation. (default: 1M) } Maximum number of max-pool-size Int pool.idle-time-before-connection-test connections. Pooled connections idled in the pool for longer than this timeout MongoDB Client will be tested before they are used. (default: -1 ) Minimum number of Quarkus integrates with MongoDB: min-pool-size Int As Neo4j uses SSL communication by default, to create a native connections. executable you need to compile with next options GraalVM options: ./mvnw quarkus:add-extension -Dextensions="quarkus-mongodb-client" max-connection-idle- Idle time of a pooled -H:EnableURLProtocols=http,https --enable-all-security-services - Duration H:+JNI time connection.

And Quarkus Maven Plugin with next conguration: @Inject max-connection-life- Life time of pooled Duration com.mongodb.client.MongoClient client; time connection. quarkus-maven-plugin

@Inject io.quarkus.mongodb.reactive.ReactiveMongoClient client; Maximum wait time wait-queue-timeout Duration native-image for new connection. native-image INFO: Reactive client uses exposes Mutiny API. Time period between maintenance- Duration runs of maintenance frequency true quarkus.mongodb.connection-string=mongodb://localhost:27018 job. quarkus.mongodb.write-concern.journal=false true Time to wait before maintenance-initial- true Duration running the rst Multi MongoDB support delay maintenance job. true You can congure multiple MongoDB clients using same approach as with DataSource . The syntax is quarkus.mongodb.. Multiplied with max- : pool-size gives max wait-queue-multiple Int numer of threads quarkus.mongodb.users.connection-string = mongodb://mongo2: waiting. 27017/userdb Alternatively, and as a not recommended way in production, you quarkus.mongodb.inventory.connection-string = mongodb://mon can disable SSL and Quarkus will disable Bolt SSL as well. go3:27017/invdb connection-timeout Duration quarkus.ssl.native=false .

If you are using Neo4j 4.0, you can use fully reactive. Add the next extension: quarkus-resteasy-mutiny . Inject the instance using socket-timeout Duration @io.quarkus.mongodb.runtime.MongoClientName annotation:

tls-insecure boolean [false] Insecure TLS. @Inject @MongoClientName("users") MongoClient mongoClient1; tls boolean [false] Enable TLS Parameter Type Description Parameter Type Description person.persist(); person.update(); Implies hosts given Source of the replica-set-name String credentials.auth- person.delete(); are a seed list. String authentication source credentials. List allPersons = Person.listAll(); person = Person.findById(personId); server-selection- Time to wait for Duration List livingPersons = Person.list("status", Status.A timeout server selection. Authentication credentials.auth- live); Map mechanism mechanism-properties List persons = Person.list(Sort.by("name").and("bir properties. th")); Minimum ping time

local-threshold Duration to make a server long updated = Person.update("name", "Mortal").where("statu eligible. MongoDB Panache s", Status.Alive);

You can also use the Panache framework to write persistence part Frequency to long countAll = Person.count(); when using MongoDB. heartbeat-frequency Duration determine the state of servers. Person.deleteById(id); ./mvnw quarkus:add-extension Person.delete("status", Status.Alive); -Dextensions="mongodb-panache" primary , primaryPreferred , All list methods have equivalent stream versions. read-preference secondary , Read preferences. MongoDB conguration comes from MongoDB Client section. secondaryPreferred , Pagination nearest @MongoEntity(collection="ThePerson") You can also use pagination: public class Person extends PanacheMongoEntity { public String name; Max number of PanacheQuery livingPersons =

concurrent Person.find("status", Status.Alive); max-wait-queue-size Int @BsonProperty("birth") operations allowed to livingPersons.page(Page.ofSize(25)); public LocalDate birthDate; wait.

// get the first page public Status status; List firstPage = livingPersons.list(); Ensures are writes } write-concern.safe boolean [true] // get the second page are ack. List secondPage = livingPersons.nextPage().list();

Possible annotations in elds: @BsonId (for custom ID), write- Journal writing boolean [true] @BsonProperty and @BsonIgnore . concern.journal aspect. Range

@MongoEntity is optional. PanacheQuery livingPersons = Person Value to all write .find("status", Status.Alive); write-concern.w String commands. Multi-tenancy with MongoDB Panache List secondRange = livingPersons.range(25, 49).list ();

write-concern.retry- Retry writes if @MongoEntity(collection = "TheBook", clientName = "client2" boolean [false] writes network fails. , database = "database2") You cannot mix pagination and range.

Queries write-concern.w- Timeout to all write Duration Methods provided are similar of the ones shown in Persistence timeout commands. section. Native MongoDB queries are supported (if they start with { or org.bson.Document instance) as well as Panache Queries. Panache Queries equivalence in MongoDB: credentials.username String Username.

firstname = ?1 and status = ?2 → {'firstname': ?1, 'status': ? 2} credentials.password String Password.

amount > ?1 and firstname != ?2 → {'amount': {'$gt': ?1}, 'firstname': {'$ne': ?2}} credentials.auth- MONGO-CR , GSSAPI , mechanism PLAIN , MONGODB-X509 lastname like ?1 → {'lastname': {'$regex': ?1}}

lastname is not null → {'lastname':{'$exists': true}} Then you can dene interfaces for dening endpoints: PanacheQL refers to the Object parameter name but native queries refer to MongoDB eld names. org.jboss.jandex In case of Active Record pattern: jandex-maven-plugin Projection 1.0.3 public interface DeveloperResource extends PanacheMongoEnti Projection can be done for both PanacheQL and native queries. tyResource { make-index } import io.quarkus.mongodb.panache.ProjectionFor; jandex @ProjectionFor(Person.class) (1) In case of Repository: public class PersonName { public String name; public interface DeveloperResource extends PanacheMongoRepo } sitoryResource { } PanacheQuery shortQuery = Person.find("status " org.jboss , Status.Alive).project(PersonName.class); jandex 2.1.1.Final Cassandra 1 Entity class. Quarkus integrates with Cassandra and DataStax Object Mapper. Testing To mock using active record pattern: Panache includes an annotation processor that enhance your com.datastax.oss.quarkus entities. If you disable annotation processors you might need to cassandra-quarkus-client create a marker le on Panache archives at META-INF/panache- io.quarkus archive.marker manually. quarkus-panache-mock Reactive Panache test Enities and DAOs are generated as you have been doing with MongoDB with Panache allows using reactive implementation too DataStax Object Mapper. by using ReactivePanacheMongoEntity or You need to create a DaoProducer: ReactivePanacheMongoEntityBase or ReactivePanacheMongoRepository or ReactivePanacheMongoRepositoryBase depending on your style. @Test @Inject public void testPanacheMocking() { public FruitDaoProducer(QuarkusCqlSession session) { PanacheMock.mock(Person.class); public class ReactivePerson extends ReactivePanacheMongoEnt FruitMapper mapper = new FruitMapperBuilder(session).buil ity { d(); Mockito.when(Person.count()).thenReturn(23l); public String name; fruitDao = mapper.fruitDao(); Assertions.assertEquals(23, Person.count()); } } PanacheMock.verify(Person.class, Mockito.times(1)).coun

t(); CompletionStage cs1 = person.persist(); @Produces } CompletionStage> allPersons = Reactive @ApplicationScoped Person.listAll(); FruitDao produceFruitDao() { Publisher allPersons = ReactivePerson.strea return fruitDao; mAll(); } DAO pattern Uni> persons = ReactivePersonEntity.find( @ApplicationScoped "lastname", name).project(PersonName.class).list(); public class PersonRepository Cassandra conguration: implements PanacheMongoRepository { } MongoDB REST Data Panache quarkus.cassandra.contact-points=127.0.0.1:9042 quarkus.cassandra.local-datacenter=datacenter1 MongoDB REST Data with Panache extension can generate the quarkus.cassandra.keyspace=k1 Jandex quarkus.cassandra.auth.username=john basic CRUD endpoints for your entities and repositories. quarkus.cassandra.auth.password=s3cr3t If entities are dened in external JAR, you need to enable in these projects the Jandex plugin in project. ./mvnw quarkus:add-extension -Dextensions="mongodb-rest-data-panache" You can congure other Cassandra Java driver settings using application.conf or application.json les. They need to be located in the classpath of your application. Driver settings reference. You also need to add the JDBC driver extension and a JSON Marshaller (ie resteasy-jackson ). If MicroProle Metrics extension is registered, the Cassandra extension can provide (if enabled) metrics about the session: quarkus.cassandra.metrics.enabled=true Reactive Programming @GET quarkus.cassandra.metrics.session-enabled=connected-nodes,b @Produces(MediaType.TEXT_PLAIN) ytes-sent Quarkus implements MicroProle Reactive spec and uses RXJava2 public Uni hello() { quarkus.cassandra.metrics.node-enabled=pool.open-connection to provide reactive programming model. return Uni.createFrom().item(() -> "hello"); s } ./mvnw quarkus:add-extension -Dextensions="quarkus-smallrye-reactive-streams-operator @GET Reactive s" @Produces(MediaType.TEXT_PLAIN) public Multi multi() { You can also use Mutiny to dene a reactive DAO: return Multi.createFrom().items("hello", "world"); } Asynchronous HTTP endpoint is implemented by returning Java @Dao CompletionStage . You can create this class either manually or using public interface FruitDaoReactive { MicroProle Reactive Streams spec: Mutiny @Update @GET Uni update(Fruit fruit); Quarkus integrates with Mutiny as reactive programming library: @Path("/reactive")

@Produces(MediaType.TEXT_PLAIN) @Select ./mvnw quarkus:add-extension public CompletionStage getHello() { MutinyMappedReactiveResultSet findById(String stor -Dextensions="mutiny" return ReactiveStreams.of("h", "e", "l", "l", "o") eId); .map(String::toUpperCase) } .toList()

.run() @Mapper @ApplicationScoped .thenApply(list -> list.toString()); public interface FruitMapper { public static class ReactiveHello { }

@DaoFactory public Uni greeting() { FruitDaoReactive fruitDaoReactive(); return Uni.createFrom().item(() -> "hello") } Creating streams is also easy, you just need to return Publisher .emitOn(Infrastructure.getDefaultExecutor object. ()); } @GET @Path("/stream") public Multi stream() { @Produces(MediaType.SERVER_SENT_EVENTS) return Multi.createFrom().items("hello", "world") public Publisher publishers() { .emitOn(Infrastructure.getDefaultExecutor return Flowable ()); .interval(500, TimeUnit.MILLISECONDS) } .map(s -> atomicInteger.getAndIncrement()) } .map(i -> Integer.toString(i)); } Converting from/to RxJava2 or Reactor APIs:

Mutiny and JAX-RS RxJava 2

Apart from the CompletionStage support, there is also support for Mutiny. io.smallrye.reactive mutiny-rxjava ./mvnw quarkus:add-extension -Dextensions="quarkus-resteasy-mutiny"

From RxJava2 : Uni uniFromCompletable = Uni.createFrom() Uni uniFromMono = Uni.createFrom().converter(UniRea package org.acme.rest; .converter(UniRxConvert ctorConverters.fromMono(), mono); import javax.ws.rs.GET; ers.fromCompletable(), completable); Uni uniFromFlux = Uni.createFrom().converter(UniRea import javax.ws.rs.Path; Uni uniFromSingle = Uni.createFrom() ctorConverters.fromFlux(), flux); @Path("rest") .converter(UniRxConverters. Multi multiFromMono = Multi.createFrom().converter public class Endpoint { fromSingle(), single); (MultiReactorConverters.fromMono(), mono); Uni uniFromObservable = Uni.createFrom() Multi multiFromFlux = Multi.createFrom().converter @Path("hello") .converter(UniRxConverters. (MultiReactorConverters.fromFlux(), flux); @GET fromObservable(), observable); public String hello(){ Uni uniFromFlowable = Uni.createFrom() // executed in event-loop .converter(UniRxConverters. return "Hello, World!"; To Reactor : fromFlowable(), flowable); } ... Mono mono = uni.convert().with(UniReactorConverter @GET Multi multiFromCompletable = Multi.createFrom() s.toMono()); public Uni culinaryGuide(){ .converter(MultiRxC Flux flux = uni.convert().with(UniReactorConverter // executed in event-loop but not blocking onverters.fromCompletable(), completable); s.toFlux()); return Book.findByIsbn("978-2081229297"); Multi multiFromObservable = Multi.createFrom() } .converter(MultiRxC Mono mono2 = multi.convert().with(MultiReactorConve onverters.fromObservable(), observable); rters.toMono()); @io.smallrye.common.annotation.Blocking Multi multiFromFlowable = Multi.createFrom() Flux flux2 = multi.convert().with(MultiReactorConve @GET .converter(MultiRxC rters.toFlux()); public String blockingHello() throws InterruptedExcepti onverters.fromFlowable(), flowable); on { ... // executed in worker-thread CompletionStages or Publisher return "Yaaaawwwwnnnnnn…"; }

To RxJava2 : CompletableFuture future = Uni } .createFrom().completionStage(CompletableFuture.sup Completable completable = uni.convert().with(UniRxConverter plyAsync(() -> "hello")); s.toCompletable()); Single> single = uni.convert().with(UniRxC CompletationStage cs = Uni Reactive Messaging onverters.toSingle()); .createFrom().subscribeAsCompletionStage(); Observable observable = uni.convert().with(UniRxCon Quarkus relies on MicroProle Reactive Messaging spec to verters.toObservable()); implement reactive messaging streams. Flowable flowable = uni.convert().with(UniRxConvert Multi implements Publisher . ers.toFlowable()); mvn quarkus:add-extension ... RESTEasy Reactive -Dextensions="

io.quarkus:quarkus-smallrye-reactive-messaging" Completable completable = multi.convert().with(MultiRxConve RESTEasy Reactive is a new implementation of JAX-RS but fully rters.toCompletable()); reactive. Single> single = multi.convert().with(Mult iRxConverters.toSingle()); You can just start using in-memory streams by using @Incoming to Observable observable = multi.convert().with(MultiR mvn quarkus:add-extension produce data and @Outgoing to consume data. xConverters.toObservable()); -Dextensions="quarkus-resteasy-reactive" Flowable flowable = multi.convert().with(MultiRxCon Produce every 5 seconds one piece of data. verters.toFlowable()); ... @ApplicationScoped public class ProducerData {

Reactor API @Outgoing("my-in-memory") public Flowable generate() { return Flowable.interval(5, TimeUnit.SECONDS) .map(tick -> random.nextInt(100)); io.smallrye.reactive } mutiny-reactor }

or in Mutiny: From Reactor : @ApplicationScoped @Inject @Stream(“out”) mp.messaging.outgoing.generated-price.connector= public class ProducerData { Publisher result; smallrye-kafka @Outgoing("my-in-memory") mp.messaging.outgoing.generated-price.topic= public Multi generate() { @GET prices return Multi.createFrom().ticks().every(Duration.of @Produces(SERVER_SENT_EVENTS) mp.messaging.outgoing.generated-price.bootstrap.servers= Seconds(5)) public Publisher stream() { localhost:9092 .onItem().apply(n -> random.nextInt(100)); return result; mp.messaging.outgoing.generated-price.value.serializer= } } org.apache.kafka.common.serialization.IntegerSerializer } mp.messaging.incoming.prices.connector= Message → Business Logic smallrye-kafka If you want to dispatch to all subscribers you can annotate the mp.messaging.incoming.prices.value.deserializer= org.apache.kafka.common.serialization.IntegerDeserializ method with @Broadcast . @ApplicationScoped er public class ReceiverMessages { Consumes generated data from my-in-memory stream. @Incoming("prices") public void print(String price) { @ApplicationScoped } A complete list of supported properties are in Kafka site. For the public class ConsumerData { } producer and for consumer @Incoming("my-in-memory") public void randomNumber(int randomNumber) { JSON-B Serializer/Deserializer System.out.println("Received " + randomNumber); To indicate that the method should be executed on a worker pool You can use JSON-B to serialize/deserialize objects. } you can use @Blocking : } ./mvnw quarkus:add-extension @Outgoing("Y") -Dextensions="quarkus-kafka-client" @Incoming("X") You can also inject an stream as a eld: @Blocking To serialize you can use @Inject io.quarkus.kafka.client.serialization.JsonbSerializer . @Stream("my-in-memory") Publisher randomRumbers; To customize: To deserialize you need to extend io.quarkus.kafka.client.serialization.JsonbDeserializer and @Blocking(value="my-custom-pool", ordered = false) provide a type. @Inject @Stream("generated-price") Emitter emitter; public class BeerDeserializer smallrye.messaging.worker.my-custom-pool.max-concurrency=3 extends JsonbDeserializer {

Patterns public BeerDeserializer() { REST API → Message Possible implementations are: super(Beer.class); } In-Memory @Inject @Stream(“in”) } Emitter emitter; If the stream is not congured then it is assumed to be an in-

memory stream, if not then stream type is dened by connector emitter.send(message); eld. AMQP

Kafka To integrate with AMQP you need to add next extensions: Message → Message To integrate with Kafka you need to add next extensions: ./mvnw quarkus:add-extension @Incoming(“in”) -Dextensions="reactive-messaging-amqp" @Outgoing(“out”) mvn quarkus:add-extension public String process(String in) { -Dextensions=" } io.quarkus:quarkus-smallrye-reactive-messaging-kafka" Then @Outgoing , @Incoming or @Stream can be used.

AMQP conguration schema: mp.messaging.[outgoing|incoming]. Message → SSE Then @Outgoing , @Incoming or @Stream can be used. {stream-name}.= . Special properties amqp-username and amqp-password are used to congure AMQP broker credentials. Kafka conguration schema: mp.messaging.[outgoing|incoming]. {stream-name}.= . The connector type is smallrye-amqp .

The connector type is smallrye-kafka . Common Reeactive DataSource Client conguration properties amqp-username=quarkus Kafka Streams prexed with quarkus.datasource : amqp-password=quarkus # write Create streaming queries with the Kafka Streams API. reactive.cache-prepared-statements mp.messaging.outgoing.generated-price.connector= Prepared statements should be cached on the client side. smallrye-amqp ./mvnw quarkus:add-extension (default: false ) mp.messaging.outgoing.generated-price.address= -Dextensions="kafka-streams" prices mp.messaging.outgoing.generated-price.durable= reactive.url true The datasource URL. All we need to do for that is to declare a CDI producer method # read which returns the Kafka Streams mp.messaging.incoming.prices.connector= reactive.max-size org.apache.kafka.streams.Topology : smallrye-amqp The datasource pool maximum size. mp.messaging.incoming.prices.durable= true @ApplicationScoped reactive.trust-all public class TopologyProducer { @Produces All server certicates should be trusted. (default: false ) public Topology buildTopology() { A complete list of supported properties for AMQP. org.apache.kafka.streams.StreamsBuilder.StreamsBuil reactive.trust-certificate-pem MQTT der Trust conguration in the PEM format. builder = new StreamsBuilder(); To integrate with MQTT you need to add next extensions: // ... reactive.trust-certificate-jks builder.stream() Trust conguration in the JKS format. .join() ./mvnw quarkus:add-extension // ... -Dextensions="vertx, smallrye-reactive-streams-operator reactive.trust-certificate-pfx .toStream() s .to(); Trust conguration in the PFX format. smallrye-reactive-messaging" return builder.build(); } reactive.key-certificate-pem } Key/cert conguration in the PEM format. And add io.smallrye.reactive:smallrye-reactive-messaging-mqtt- 1.0:0.0.10 dependency in your build tool. reactive.key-certificate-jks Previous example produces content to another stream. If you want Then @Outgoing , @Incoming or @Stream can be used. Key/cert conguration in the JKS format. to write interactive queries, you can use Kafka streams. MQTT conguration schema: mp.messaging.[outgoing|incoming]. reactive.key-certificate-pfx {stream-name}.= . @Inject Key/cert conguration in the PFX format. KafkaStreams streams; The connector type is smallrye-mqtt . reactive.thread-local return streams Use one connection pool per thread. mp.messaging.outgoing.topic-price.type= .store("stream", QueryableStoreTypes.keyValueStore smallrye-mqtt ()); reactive.reconnect-attempts mp.messaging.outgoing.topic-price.topic= prices The number of reconnection attempts when a pooled connection cannot be established on rst try. (default: 0 ) mp.messaging.outgoing.topic-price.host= The Kafka Streams extension is congured via the Quarkus localhost conguration le application.properties . mp.messaging.outgoing.topic-price.port= reactive.reconnect-interval 1883 The interval between reconnection attempts when a pooled quarkus.kafka-streams.bootstrap-servers=localhost:9092 mp.messaging.outgoing.topic-price.auto-generated-client-id= connection cannot be established on rst try. (default: PT1S ) quarkus.kafka-streams.application-id=temperature-aggregator true quarkus.kafka-streams.application-server=${hostname}:8080 reactive.idle-timeout quarkus.kafka-streams.topics=weather-stations,temperature-v mp.messaging.incoming.prices.type= alues The maximum time without data written to or read from a smallrye-mqtt connection before it is removed from the pool. mp.messaging.incoming.prices.topic= kafka-streams.cache.max.bytes.buffering=10240 prices kafka-streams.commit.interval.ms=1000 mp.messaging.incoming.prices.host= Reactive PostgreSQL Client localhost mp.messaging.incoming.prices.port= You can use Reactive PostgreSQL to execute queries to PostreSQL 1883 IMPORTANT: All the properties within the kafka-streams database in a reactive way, instead of using JDBC way. mp.messaging.incoming.prices.auto-generated-client-id= namespace are passed through as-is to the Kafka Streams engine. true Changing their values requires a rebuild of the application. ./mvnw quarkus:add-extension -Dextensions="quarkus-reactive-pg-client" Reactive DataSource Properties Database conguration is the same as shown in Persistence Reactive Transactions Artemis JMS section, but URL is different as it is not a jdbc. If you want to use JMS with Artemis, you can do it by using its io.vertx.mutiny.sqlclient.SqlClientHelper is an util class that extension: quarkus.datasource.db-kind=postgresql allows you to run reactive persisten code within a transaction. quarkus.datasource.reactive.url=postgresql:///your_database ./mvnw quarkus:add-extension Uni r = SqlClientHelper.inTransactionUni(client, tx - -Dextensions="quarkus-artemis-jms" > { Then you can inject io.vertx.mutiny.pgclient.PgPool class. Uni> insertOne = tx.preparedQuery("INSE RT INTO fruits (name) VALUES ($1) RETURNING (id)") And then you can inject javax.jms.ConnectionFactory : @Inject .execute(Tuple.of(fruit1.name)); PgPool client; }); @ApplicationScoped Uni> fruits = public class ArtemisConsumerManager { client.preparedQuery("SELECT * FROM fruits") ActiveMQ Artemis .onItem().apply(rowSet -> { @Inject ConnectionFactory connectionFactory; JsonArray jsonArray = new JsonArray(); Quarkus uses Reactive Messaging to integrate with messaging

for (Row row : rowSet) { systems, but in case you need deeper control when using Apache private Connection connection; jsonArray.add(from(row)); ActiveMQ Artemis there is also an extension: } return jsonArray; @PostConstruct }) ./mvnw quarkus:add-extension public void init() throws JMSException { -Dextensions="quarkus-artemis-core" connection = connectionFactory.createConnection(); connection.start(); } Reactive MySQL Client And then you can inject } org.apache.activemq.artemis.api.core.client.ServerLocator You can use Reactive MySQL to execute queries to MySQL instance. database in a reactive way, instead of using JDBC. Conguration options are the same as Artemis core. @ApplicationScoped ./mvnw quarkus:add-extension public class ArtemisConsumerManager { -Dextensions="quarkus-reactive-mysql-client" Vert.X Reactive Clients @Inject ServerLocator serverLocator; Vert.X Reactive clients in Quarkus, the next clients are supported Database conguration is the same as shown in Persistence and you need to add the dependency to use them: section, but URL is different as it is not a jdbc. private ClientSessionFactory connection; Vert.X Mail Client @PostConstruct quarkus.datasource.db-kind=mysql io.smallrye.reactive:smallrye-mutiny-vertx-mail-client quarkus.datasource.reactive.url=mysql:///your_database public void init() throws Exception { connection = serverLocator.createSessionFactory(); Vert.X MongoDB Client } } io.smallrye.reactive:smallrye-mutiny-vertx-mongo-client Then you can inject io.vertx.mutiny.mysqlclient.MySQLPool class. Vert.X Redis Client Reactive DB2 Client io.smallrye.reactive:smallrye-mutiny-vertx-redis-client And congure ServerLocator in application.properties : You can use Reactive DB2 to execute queries to DB2 database in a Vert.X Cassandra Client reactive way, instead of using JDBC. quarkus.artemis.url=tcp://localhost:61616 io.smallrye.reactive:smallrye-mutiny-vertx-cassandra-client

./mvnw quarkus:add-extension Vert.X Consul Client -Dextensions="quarkus-reactive-db2-client" You can congure ActiveMQ Artemis in application.properties le io.smallrye.reactive:smallrye-mutiny-vertx-consul-client by using next properties prexed with quarkus :

artemis.url Vert.X Kafka Client Database conguration is the same as shown in Persistence Connection URL. io.smallrye.reactive:smallrye-mutiny-vertx-kafka-client section, but URL is different as it is not a jdbc.

artemis.username Vert.X AMQP Client quarkus.datasource.db-kind=db2 Username for authentication. io.smallrye.reactive:smallrye-mutiny-vertx-amqp-client quarkus.datasource.reactive.url=vertx-reactive:db2://localh ost:50005/hreact artemis.password Vert.X RabbitMQ Client Password for authentication. io.smallrye.reactive:smallrye-mutiny-vertx-rabbitmq-client

Then you can inject i i db2 li 2 l class Example of Vert.X Web Client: quarkus.sqs.sync-client.type=apache TLS

@Inject You can trust all certicates globally by using quarkus.tls.trust- Vertx vertx; You can go async by using Mutiny: all=true

private WebClient client; RBAC @Inject @PostConstruct software.amazon.awssdk.services.sqs.SqsAsyncClient sqs; You can set RBAC using annotations or in application.properties . void initialize() { this.client = WebClient.create(vertx, ...); Uni.createFrom() Annotations } .completionStage( sqs.sendMessage(m -> m.queueUrl(queueUrl).messageBo You can dene roles by using dy(message)) javax.annotation.security.RolesAllowed annotation. ) Amazon SQS Client .onItem()... @RolesAllowed("Subscriber")

return Uni.createFrom() ./mvnw quarkus:add-extension .completionStage( -Dextensions="amazon-sqs" sqs.receiveMessage(m -> m.maxNumberOfMessages(10).q You can use io.quarkus.security.Authenticated as a shortcut of ueueUrl(queueUrl)) @RolesAllowed("*") . ) Injecting the client: .onItem() To alter RBAC behaviour there are two conguration properties:

@Inject quarkus.security.deny-unannotated=true software.amazon.awssdk.services.sqs.SqsClient sqs; And you need to add the asynchronous Netty client:

SendMessageResponse response = sqs.sendMessage(m -> m.queue Conguration options: Url(queueUrl).messageBody(message)); software.amazon.awssdk

netty-nio-client quarkus.jaxrs.deny-uncovered List messages = sqs.receiveMessage(m -> m.maxNumbe If true denies by default to all JAX-RS endpoints. (default: false ) rOfMessages(10).queueUrl(queueUrl)).messages();

quarkus.security.deny-unannotated If true denies by default all CDI methods and JAX-RS endpoints. And congure it: Conguration properties are the same as Amazon DynamoDB but changing the prex from dynamodb to sqs . (default: false )

quarkus.sqs.endpoint-override=http://localhost:8010 By default in Quarkus, if an incoming request has a credential the quarkus.sqs.aws.region=us-east-1 request will always be authenticated (even if the target page does quarkus.sqs.aws.credentials.type=static not require authentication). quarkus.sqs.aws.credentials.static-provider.access-key-id=t est-key You can change this behaviour by setting quarkus.sqs.aws.credentials.static-provider.secret-access-k quarkus.http.auth.proactive property to false . ey=test-secret File Conguration

Dening RBAC in application.properties instead of using You need to set a HTTP client either URL Connection : annotations.

software.amazon.awssdk url-connection-client

or Apache HTTP:

software.amazon.awssdk apache-client Sets header such as Cookie is used to pass the token. (default: quarkus.http.auth.policy.role-policy1.roles-allowed= quarkus.security.security-providers=BC Authorization ). user,admin quarkus.security.security-providers=BCJSSE quarkus.http.auth.permission.roles1.paths= quarkus.security.security-providers=BCFIPS /roles-secured/*,/other/*,/api/* quarkus.security.security-providers=BCFIPSJSSE smallrye.jwt.token.cookie quarkus.http.auth.permission.roles1.policy= Name of the cookie containing a token. role-policy1 JWT smallrye.jwt.token.schemes quarkus.http.auth.permission.permit1.paths= Comma-separated list containing an alternative single or multiple /public/* schemes. (default: Bearer ). quarkus.http.auth.permission.permit1.policy= Quarkus implements MicroProle JWT RBAC spec.

permit smallrye.jwt.require.named-principal quarkus.http.auth.permission.permit1.methods= mvn quarkus:add-extension A token must have a upn or preferred_username or sub claim set GET -Dextensions="io.quarkus:quarkus-smallrye-jwt" if using java.security.Principal . True makes throw an exception

if not set. (default: false ). quarkus.http.auth.permission.deny1.paths= /forbidden Minimum JWT required claims: typ , alg , kid , iss , sub , exp , iat , quarkus.http.auth.permission.deny1.policy= smallrye.jwt.path.sub jti , upn , groups . deny Path to the claim with subject name.

You can inject token by using JsonWebToken or a claim individually by smallrye.jwt.claims.sub using @Claim . You need to provide permissions set by using the roles-allowed Default sub claim value. property or use the built-in ones deny , permit or authenticated . @Inject JsonWebToken jwt; smallrye.jwt.path.groups You can use enabled property (ie Path to the claim containing the groups. quarkus.http.auth.permission.permit1.enabled ) to enable the entire @Inject permission set. @Claim(standard = Claims.preferred_username) smallrye.jwt.groups-separator String name; Testing Separator for splitting a string which may contain multiple group values. (default. ` `). Quarkus provides explicit support for testing with different users, @Inject @Claim("groups") and with the security subsystem disabled. smallrye.jwt.claims.groups Set groups; Default groups claim value. @Inject io.quarkus JWTParser parser; smallrye.jwt.jwks.refresh-interval quarkus-test-security JWK cache refresh interval in minutes. (default: 60 ). test smallrye.jwt.expiration.grace Set of supported types: String , Set , Long , Boolean, `javax.json.JsonValue , Optional , Expiration grace in seconds. (default: 60 ). org.eclipse.microprofile.jwt.ClaimValue . @Test smallrye.jwt.verify.aud @TestSecurity(authorizationEnabled = false) And conguration in src/main/resources/application.properties : Comma separated list of the audiences that a token aud claim void someTestMethod() { may contain. ... mp.jwt.verify.publickey.location= } META-INF/resources/publicKey.pem smallrye.jwt.verify.algorithm mp.jwt.verify.issuer= Signature algorith. (defsult: RS256 ) @Test https://quarkus.io/using-jwt-rbac @TestSecurity(user = "testUser", roles = {"admin", "user"}) smallrye.jwt.token.kid void someTestMethod() { If set then the verication JWK key as well every JWT token must ... Conguration options: } have a matching kid header.

mp.jwt.verify.publickey smallrye.jwt.time-to-live Public Key text itself to be supplied as a string. BouncyCastle The maximum number of seconds that a JWT may be issued for use. mp.jwt.verify.publickey.location Relative path or URL of a public Quarkus supports BouncyCastle, you only need to add the key. smallrye.jwt.sign.key-location BouncyCastle dependency and congure the security provider: mp.jwt.verify.issuer Location of a private key which will be used to sign the claims iss accepted as valid. when either a no-argument sign() or innerSign() method is called. smallrye.jwt.token.header smallrye.jwt.encrypt.key-location Location of a public key which will be used to encrypt the claims tenant-enabled Jwt.claims() or inner JWT when a no-argument encrypt() method is called. .issuer("https://server.com") If the tenant conguration is enabled. (default: true ) .claim("customClaim", 3) Supported public key formats: .sign(createKey()); application-type

PKCS#8 PEM The application type. Possible values: web_app , service . (default: JwtSignatureBuilder jwtSignatureBuilder = Jwt.claims("/test service ) JWK JsonToken.json").jws(); jwtSignatureBuilder connection-delay .signatureKeyId("some-key-id") JWKS The maximum amount of time the adapter will try connecting. .signatureAlgorithm(SignatureAlgorithm.ES256) JWK Base64 URL .header("custom-header", "custom-value"); auth-server-url .sign(createKey()); JWKS Base64 URL The base URL of the OpenID Connect (OIDC) server. Jwt.claims("/testJsonToken.json") To send a token to server-side you should use Authorization .encrypt(createKey()); introspection-path header: curl -H "Authorization: Bearer eyJraWQiOi… " . Relative path of the RFC7662 introspection service. JwtEncryptionBuilder jwtEncryptionBuilder = Jwt.claims("/te To inject claim values, the bean must be @RequestScoped CDI stJsonToken.json").jwe(); jwks-path scoped. If you need to inject claim values in scope with a lifetime jwtEncryptionBuilder Relative path of the OIDC service returning a JWK set. greater than @RequestScoped then you need to use .keyEncryptionKeyId("some-key-id") javax.enterprise.inject.Instance interface. .keyEncryptionAlgorithm(KeyEncryptionAlgorithm.ECDH_E public-key S_A256KW) @Inject .header("custom-header", "custom-value"); Public key for the local JWT token verication @Claim(standard = Claims.iat) .encrypt(createKey()); private Instance providerIAT; client-id Jwt.claims("/testJsonToken.json") The client-id of the application. .innerSign(createKey()); RBAC .encrypt(createKey()); roles.role-claim-path Path to the claim containing an array of groups. ( realm/groups ) JWT groups claim is directly mapped to roles to be used in security annotations. OpenId Connect roles.role-claim-separator Separator for splitting a string which may contain multiple group @RolesAllowed("Subscriber") Quarkus can use OpenId Connect or OAuth 2.0 authorization values. servers such as Keycloak to protect resources using bearer token issued by Keycloak server. token.issuer Generate tokens Issuer claim value. mvn quarkus:add-extension JWT generation API: -Dextensions="using-openid-connect" token.audience Audience claim value.

You can also protect resources with security annotations. token.expiration-grace Expiration grace period in seconds. @GET @RolesAllowed("admin") token.principal-claim Name of the claim which contains a principal name.

Congure application to Keycloak service in application.properties token.refresh-expired le. If property is enabled then a refresh token request is performed.

quarkus.oidc.realm=quarkus credentials.secret quarkus.oidc.auth-server-url=http://localhost:8180/auth The client secret quarkus.oidc.resource=backend-service quarkus.oidc.bearer-only=true authentication.redirect-path quarkus.oidc.credentials.secret=secret Relative path for calculating a redirect_uri query parameter.

authentication.restore-path-after-redirect Conguration options with quarkus.oidc prex: The original request URI used before the authentication will be enabled restored after the user has been redirected back to the application. (default: true ) The OIDC is enabled. (default: true ) authentication.scopes quarkus.oidc.auth-server-url=http://localhost:8180/auth/rea Authenticating via HTTP List of scopes. lms/quarkus quarkus.oidc.client-id=multi-tenant-client HTTP basic auth is enabled by the quarkus.http.auth.basic=true authentication.extra-params quarkus.oidc.application-type=web-app property. Additional properties which will be added as the query parameters . quarkus.oidc.tenant-b.auth-server-url=https://accounts.goog HTTP form auth is enabled by the le.com quarkus.http.auth.form.enabled=true property. authentication.cookie-path quarkus.oidc.tenant-b.application-type=web-app quarkus.oidc.tenant-b.client-id=xxxx Then you need to add elytron-security-properties-file or elytron- Cookie path parameter. quarkus.oidc.tenant-b.credentials.secret=yyyy security-jdbc . quarkus.oidc.tenant-b.token.issuer=https://accounts.google. proxy.host com Security with Properties File The host (name or IP address) of the Proxy. quarkus.oidc.tenant-b.authentication.scopes=email,profile,o penid You can also protect endpoints and store identities (user, roles) in proxy.port the le system. The port number of the Proxy. (default: 80 ) OAuth2 mvn quarkus:add-extension proxy.username -Dextensions="elytron-security-properties-file" The username to authenticate. Quarkus integrates with OAuth2 to be used in case of opaque tokens (none JWT) and its validation against an introspection proxy.password endpoint. You need to congure the extension with users and roles les: The password to authenticate. And conguration in src/main/resources/application.properties : mvn quarkus:add-extension end-session-path -Dextensions="security-oauth2" quarkus.security.users.file.enabled=true Relative path of the OIDC end_session_endpoint . quarkus.security.users.file.users=test-users.properties quarkus.security.users.file.roles=test-roles.properties logout.path And conguration in src/main/resources/application.properties : quarkus.security.users.file.auth-mechanism=BASIC The relative path of the logout endpoint at the application. quarkus.security.users.file.realm-name=MyRealm quarkus.oauth2.client-id=client_id quarkus.security.users.file.plain-text=true logout.post-logout-path quarkus.oauth2.client-secret=secret Relative path of the application endpoint where the user should quarkus.oauth2.introspection-url=http://oauth-server/intros pect be redirected to after logging out. Then users.properties and roles.properties : tls.verification scott=jb0ss Sets the TLs verication. Possible values: REQUIRED , NONE . And you can map roles to be used in security annotations. jdoe=p4ssw0rd (default: REQUIRED ). @RolesAllowed("Subscriber") With Keycloak OIDC server https://host:port/auth/realms/{realm} where {realm} has scott=Admin,admin,Tester,user to be replaced by the name of the Keycloak realm. jdoe=NoRolesUser Conguration options: You can use quarkus.http.cors property to enable consuming form different domain. quarkus.oauth2.enabled Determine if the OAuth2 extension is enabled. (default: true ) IMPORTANT: If plain-text is set to false (or omitted) then Multi-tenancy passwords must be stored in the form MD5 username quarkus.oauth2.client-id ( :`realm`:`password`). Multi-tenancy is supported by adding a sub-category to OIDC conguration properties (ie quarkus.oidc.{tenent_id}.property ). The OAuth2 client id used to validate the token. Elytron File Properties conguration properties. Prex quarkus.security.users is skipped. quarkus.oauth2.client-secret The OAuth2 client secret used to validate the token. file.enabled The le realm is enabled. (default: false ) quarkus.oauth2.introspection-url URL used to validate the token and gather the authentication file.auth-mechanism claims. The authentication mechanism. ( default: BASIC )

quarkus.oauth2.role-claim file.realm-name The claim that is used in the endpoint response to load the roles The authentication realm name. (default: Quarkus ) ((default: scope ) file.plain-text If passwords are in plain or in MD5. (default: false ) You still need to add the database driver (ie jdbc-h2 ). principal-query.bcrypt-password-mapper.salt-index file.users You need to congure JDBC and Elytron JDBC Realm: The index column containing the Bcrypt salt. (default: 0 ) Classpath resource of user/password. (default: users.properties ) quarkus.datasource.url= principal-query.bcrypt-password-mapper.salt-encoding quarkus.datasource.driver=org.h2.Driver A string referencing the salt encoding ( BASE64 or HEX ). (default: quarkus.datasource.username=sa file.roles BASE64 ) quarkus.datasource.password=sa Classpath resource of user/role. (default: roles.properties )

principal-query.bcrypt-password-mapper.iteration-count-index quarkus.security.jdbc.enabled=true Embedded Realm quarkus.security.jdbc.principal-query.sql= The index column containing the Bcrypt iteration count. (default: 0 ) You can embed user/password/role in the same SELECT u.password, u.role FROM test_user u WHERE u.user =? application.properties : quarkus.security.jdbc.principal-query For multiple datasources you can use the datasource name in the .clear-password-mapper.enabled=true properties: quarkus.security.users.embedded.enabled=true quarkus.security.jdbc.principal-query quarkus.security.users.embedded.plain-text=true .clear-password-mapper.password-index=1 quarkus.datasource.url= quarkus.security.users.embedded.users.scott=jb0ss quarkus.security.jdbc.principal-query quarkus.security.jdbc.principal-query.sql= quarkus.security.users.embedded.roles.scott=admin,tester,us .attribute-mappings.0.index=2 er quarkus.security.jdbc.principal-query quarkus.datasource.permissions.url= quarkus.security.users.embedded.auth-mechanism=BASIC .attribute-mappings.0.to=groups quarkus.security.jdbc.principal-query.permissions.sql=

IMPORTANT: If plain-text is set to false (or omitted) then You need to set the index (1-based) of password and role. passwords must be stored in the form MD5 Security with JPA ( username :`realm`:`password`). Elytron JDBC Realm conguration properties. Prex You can also protect endpoints and store identities in a database quarkus.security.jdbc is skipped. Prex quarkus.security.users.embedded is skipped. using JPA. auth-mechanism algorithm The authentication mechanism. (default: BASIC ) mvn quarkus:add-extension Determine which algorithm to use. Possible values: DIGEST_MD5 , -Dextensions="security-jpa" DIGEST_SHA DIGEST_SHA_256 DIGEST_SHA_384 DIGEST_SHA_512 , , , , realm-name DIGEST_SHA_512_256 . (default: DIGEST_MD5 ) The authentication realm name. (default: Quarkus ) Also you might require jdbc-postgresql , resteasy , file.enabled enabled hibernate-orm-panache . The le realm is enabled. (default: false ) If the properties store is enabled. (default: false ) file.auth-mechanism principal-query.sql The authentication mechanism. (default: BASIC ) The sql query to nd the password. file.realm-name principal-query.datasource The authentication realm name. (default: Quarkus ) The data source to use. file.plain-text principal-query.clear-password-mapper.enabled If passwords are in plain or in MD5. (default: false ) If the clear-password-mapper is enabled. (default: false ) file.users.* principal-query.clear-password-mapper.password-index * is user and value is password. The index of column containing clear password. (default: 1 ) file.roles.* principal-query.bcrypt-password-mapper.enabled * is user and value is role. If the bcrypt-password-mapper is enabled. (default: false )

Security with a JDBC Realm principal-query.bcrypt-password-mapper.password-index The index of column containing password hash. (default: 0 ) You can also protect endpoints and store identities in a database.

principal-query.bcrypt-password-mapper.hash-encoding mvn quarkus:add-extension A string referencing the password hash encoding ( BASE64 or HEX ). -Dextensions="elytron-security-jdbc" (default: BASE64 ) The identier ( baseFilter ) which correlates to the provided user @io.quarkus.security.jpa.UserDefinition quarkus.security.ldap.enabled=true (default: uid ) @Table(name = "test_user") quarkus.security.ldap.dir-context.principal=uid=tool,ou=acc @Entity ounts,o=YourCompany,c=DE public class User extends PanacheEntity { quarkus.security.ldap.dir-context.url=ldaps://ldap.server.l identity-mapping.search-base-dn @io.quarkus.security.Username ocal The dn where we look for users. public String name; quarkus.security.ldap.dir-context.password=PASSWORD quarkus.security.ldap.identity-mapping.rdn-identifier=uid identity-mapping.attribute-mappings..from @io.quarkus.security.Password quarkus.security.ldap.identity-mapping.search-base-dn=ou=us The roleAttributeId from which is mapped public String pass; ers,ou=tool,o=YourCompany,c=DE

quarkus.security.ldap.identity-mapping.attribute-mapping identity-mapping.attribute-mappings..to @ManyToMany s."0".from=cn The identier whom the attribute is mapped to (default: gropus ) @Roles quarkus.security.ldap.identity-mapping.attribute-mapping public List roles = new ArrayList<>(); s."0".to=groups quarkus.security.ldap.identity-mapping.attribute-mapping identity-mapping.attribute-mappings..filter public static void add(String username, String passwor s."0".filter=(member=uid={0}) The lter ( roleFilter ) d) { quarkus.security.ldap.identity-mapping.attribute-mapping User user = new User(); s."0".filter-base-dn=ou=roles,ou=tool,o=YourCompany,c=DE identity-mapping.attribute-mappings..filter-base-dn user.username = username; The lter base dn ( rolesContextDn ) user.password = BcryptUtil.bcryptHash(password); user.persist(); Testing } Vault } There is a Quarkus Test Resource that starts and stops InMemory Quarkus integrates with Vault to manage secrets or protecting LDAP server before and after test suite. It is running in localhost sensitive data. @Entity with dc=quarkus,dc=io and binding credentials public class Role extends PanacheEntity { ( "uid=admin,ou=system", "secret" ). Imports LDIF from a le located at root of the classpath named quarkus-io.ldif . mvn quarkus:add-extension @ManyToMany(mappedBy = "roles") -Dextensions="vault" public List users; Register dependency io.quarkus:quarkus-test-ldap:test.

@io.quarkus.security.RolesValue And annotate the test: And conguring Vault in application.properties : public String role; } @QuarkusTestResource(io.quarkus.test.ldap.LdapServerTestRes # vault url ource.class) quarkus.vault.url=http://localhost:8200 public class ElytronLdapExtensionTestResources {

} You need to congure JDBC: quarkus.vault.authentication.userpass.username= bob quarkus.datasource.url=jdbc:postgresql:security_jpa quarkus.vault.authentication.userpass.password= quarkus.datasource.driver=org.postgresql.Driver Elytron LDAP Realm conguration properties. Prex sinclair quarkus.datasource.username=quarkus quarkus.security.ldap is skipped. quarkus.datasource.password=quarkus # path within the kv secret engine enabled quarkus.vault.secret-config-kv-path= quarkus.hibernate-orm.database.generation=drop-and-create Enable the LDAP elytron module (default: false ) myapps/vault-quickstart/config quarkus.vault.secret-config-kv-prefix.singer.paths= realm-name multi/singer1, multi/singer2 Security with LDAP The elytron realm name (default: Quarkus )

You can also protect endpoints and store identities in a database direct-verification vault kv put secret/myapps/vault-quickstart/config a-private- key=123456 using LDAP. Provided credentials are veried against LDAP (default: true )

vault kv put secret/multi/singer1 firstname=paul mvn quarkus:add-extension dir-context.url -Dextensions="elytron-security-ldap" The url of the LDAP server. @ConfigProperty(name = "a-private-key") String privateKey; dir-context.principal User ( bindDn ) which is used to connect to LDAP server. @ConfigProperty(name = "singer.firstname") String firstName; dir-context.password The password ( bindCredential ) which belongs to the principal. You can access the KV engine programmatically: identity-mapping.rdn-identifier @Inject @Inject @Inject VaultKVSecretEngine kvSecretEngine; VaultTransitSecretEngine transit; VaultSystemBackendEngine vaultSystemBackendEngine;

kvSecretEngine.readSecret("myapps/vault-quickstart/" + vaul transit.encrypt("my_encryption", text); @Inject tPath).toString(); transit.decrypt("my_encryption", text).asString(); VaultKubernetesAuthService vaultKubernetesAuthService; transit.sign("my-sign-key", text); Map secrets; String rules = "path \"transit/*\" {\n" + kvSecretEngine.writeSecret("myapps/vault-quickstart/crud", " capabilities = [ \"create\", \"read\", \"updat secrets); Transit Key e\" ]\n" + "}"; kvSecretEngine.deleteSecret("myapps/vault-quickstart/crud" String policyName = "sys-test-policy"; ); @Inject VaultTransitSecretEngine transit; vaultSystemBackendEngine.createUpdatePolicy(policyName, rul es); transit.createKey(KEY_NAME, new KeyCreationRequestDetail(). Fetching credentials DB setExportable(true)); vaultKubernetesAuthService transit.readKey(KEY_NAME); With the next kv vault kv put secret/myapps/vault-quickstart/db .createRole(roleName, new VaultKubernetesAuthRole() transit.listKeys(); password=connor .setBoundServiceAccountNames(boundServiceAccountN transit.exportKey(KEY_NAME, VaultTransitExportKeyType.encry ames) ption, null); .setBoundServiceAccountNamespaces(boundServiceAcc quarkus.vault.credentials-provider.mydatabase.kv-path= transit.updateKeyConfiguration(KEY_NAME, new KeyConfigReque ountNamespaces) myapps/vault-quickstart/db stDetail().setDeletionAllowed(true)); .setTokenPolicies(tokenPolicies)); transit.deleteKey(KEY_NAME); quarkus.datasource.db-kind= postgresql quarkus.datasource.username= Vault conguration properties. Prex quarkus.vault is skipped. Vault TOTP sarah url quarkus.datasource.credentials-provider= TOTP secret engine is supported by using mydatabase Vault server URL io.quarkus.vault.VaultTOTPSecretEngine class: quarkus.datasource.jdbc.url= jdbc:postgresql://localhost:5432/mydatabase authentication.client-token @Inject Vault token to access VaultTOTPSecretEngine vaultTOTPSecretEngine;

No password is set as it is fetched from Vault. CreateKeyParameters createKeyParameters = new CreateKeyPara authentication.app-role.role-id meters("Google", "[email protected]"); Role Id for AppRole auth Dynamic credentials are also supported: createKeyParameters.setPeriod("30m"); Running the following dynamic database cong in Vault: authentication.app-role.secret-id /** Generate Key (QR code) */ Secret Id for AppRole auth vault write database/config/mydb plugin_name=postgresql-database- final Optional myKey = vaultTOTPSecretEngine .createKey("my_ plugin … .. authentication.app-role.secret-id-wrapping-token key_2", createKeyParameters); Wrapping token containing a Secret Id. secret-id and secret-id- You can congure as: /** Generate key number to login */ wrapping-token are exclusive. final String keyCode = vaultTOTPSecretEngine.generateCode( quarkus.vault.credentials-provider "my_key_2"); authentication.userpass.username .mydatabase.database-credentials-role=mydbrole Username for userpass auth

/** Login logic */ quarkus.datasource.db-kind= boolean valid = vaultTOTPSecretEngine.validateCode("my_key_ authentication.userpass.password postgresql 2", keyCode); quarkus.datasource.credentials-provider= Password for userpass auth mydatabase quarkus.datasource.jdbc.url= authentication.userpass.password-wrapping-token jdbc:postgresql://localhost:5432/mydatabase Vault Provisioning Wrapping token containing a password. password and password- wrapping-token are exclusive. Vault extension offers façade classes to Vault provisioning functions: Username and password are fetched from Vault authentication.kubernetes.role Kubernetes authentication role Transit

authentication.kubernetes.jwt-token-path Location of the le containing the Kubernetes JWT token

renew-grace-period Renew grace period duration (default: 1H ) quarkus.kms.endpoint-override=http://localhost:8011 quarkus.kms.aws.region=us-east-1 software.amazon.awssdk secret-config-cache-period quarkus.kms.aws.credentials.type=static url-connection-client Vault cong source cache period (default: 10M ) quarkus.kms.aws.credentials.static-provider.access-key-id=t est-key secret-config-kv-path quarkus.kms.aws.credentials.static-provider.secret-access-k Vault path in kv store. List of paths is supported in CSV ey=test-secret or Apache HTTP: log-confidentiality-level Used to hide condential infos. low , medium , high (default: You need to set a HTTP client either URL Connection : software.amazon.awssdk medium ) apache-client kv-secret-engine-version software.amazon.awssdk Kv secret engine version (default: 1) url-connection-client And you need to add the asynchronous Netty client: kv-secret-engine-mount-path Kv secret engine path (default: secret )

tls.skip-verify or Apache HTTP: software.amazon.awssdk Allows to bypass certicate validation on TLS communications netty-nio-client (default: false ) software.amazon.awssdk tls.ca-cert apache-client Certicate bundle used to validate TLS communications @Inject tls.use-kubernetes-ca-cert IamClient client;

TLS will be active (default: true ) quarkus.sqs.sync-client.type=apache @Inject IamAsyncClient async; connect-timeout Tiemout to establish a connection (default: 5S ) You can go async by using Mutiny: read-timeout quarkus.iam.endpoint-override=${iam.url} @Inject quarkus.iam.aws.region=us-east-1 Request timeout (default: 1S ) software.amazon.awssdk.services.kms.KmsAsyncClient kms; quarkus.iam.aws.credentials.type=static quarkus.iam.aws.credentials.static-provider.access-key-id=t credentials-provider."credentials-provider".database-credentials- Uni.createFrom().completionStage( est-key role kms.encrypt(req -> req.keyId(keyArn).plaintext(SdkByte quarkus.iam.aws.credentials.static-provider.secret-access-k Database credentials role s.fromUtf8String(data)) ey=test-secret )) credentials-provider."credentials-provider".kv-path A path in vault kv store, where we will nd the kv-key Conguration properties are the same as Amazon DynamoDB but And you need to add the asynchronous Netty client: changing the prex from dynamodb to iam . credentials-provider."credentials-provider".kv-key

Key name to search in vault path kv-path (default: password ) software.amazon.awssdk Amazon KMS netty-nio-client

mvn quarkus:add-extension -Dextensions="amazon-kms" Conguration properties are the same as Amazon DynamoDB but changing the prex from dynamodb to kms .

@Inject Amazon IAM KmsClient kms;

mvn quarkus:add-extension kms.encrypt(req -> req.keyId(keyArn).plaintext( -Dextensions="quarkus-amazon-iam" SdkBytes.fromUtf8String(data))).ciphertextBlob();

You need to set a HTTP client either URL Connection : HTTP Conguration The le path to a service certicate or certicate chain in PEM enable-compression format. Relative to src/main/resources . If responses should be compressed. You can congure HTTP parameters. Using quarkus.http prex: ssl.certificate.key-file read-timeout cors The le path to the corresponding certicate private key in PEM Http connection read timeout for blocking IO. (default: 60s ) Enable CORS. (default: false ) format. Relative to src/main/resources . body.handle-file-uploads cors.origins ssl.certificate.key-store-file If the les sent using multipart/form-data will be stored locally. CSV of origins allowed. (dedault: Any request valid.) The key store contains the certicate information. Relative to (default: true ) src/main/resources .

cors.methods body.uploads-directory ssl.certificate.key-store-file-type CSV of methods valid. (default: Any method valid.) The directory where the les sent using multipart/form-data The key store type. It is automatically detected based on the le should be stored. (default: file-uploads ) cors.headers name or can be set manually. Supported values are: JKS , JCEKS , P12 , PKCS12 or PFX . CSV of valid allowed headers. (default: Any requested header body.merge-from-attributes valid.) If the form attributes should be added to the request parameters. ssl.certificate.key-store-password (default: true ) cors.exposed-headers The password to open the key store le. CSV of valid exposed headers. body.delete-uploaded-files-on-end ssl.certificate.trust-store-file The trust store location which If the uploaded les should be removed after serving the request. contains the certicate information of the certicates to trust. port Relative to src/main/resources . The HTTP port. (default: 8080 ) body.preallocate-body-buffer ssl.certificate.trust-store-file-type If the body buffer should pre-allocated based on the Content- test-port The trust store type. It is automatically detected based on the le Length header value. (default: 1K ) The HTTP test port. (default: 8081 ) name or can be set manually. auth.session.encryption-key host ssl.certificate.trust-store-password The encryption key that is used to store persistent logins. The HTTP host. (default: 0.0.0.0 ) The password to open the trust store le. so-reuse-port host-enabled ssl.cipher-suites Enable socket reuse port. Enable listening to host:port. (default: true ) A list of strings of cipher suites to use. If not provided, a reasonable default is selected. tcp-quick-ack ssl-port Enable tcp quick ack. The HTTPS port. (default 8443 ) ssl.protocols The list of protocols to explicitly enable. (default: TLSv1.3 and tcp-cork test-ssl-port TLSv1.2 ). Enable tcp cork. The HTTPS port used to run tests. (default 8444 ) ssl.client-auth tcp-fast-open proxy-address-forwarding Congures the engine to require/request client authentication. Enable tcp fast open. The address, scheme etc will be set from headers forwarded by Possible values are: none , request and required . (default: none ). the proxy server. domain-socket io-threads Path to a unix domain socket. (default: allow-forwarded The number if IO threads used to perform IO. /var/run/io.quarkus.app.socket ) Proxy address forwarding is enabled then the standard Forwarded header will be used, rather than the more common but not limits.max-header-size domain-socket-enabled standard X-Forwarded-For . The maximum length of all headers. (default: 20k ) Enables domain socket.

insecure-requests limits.max-body-size record-request-start-time If insecure requests are allowed. Possible values: enabled , The maximum size of a request body. (default: 10M ) If enabled then start time will be recorded to enable logging of redirect , disable . (default: enabled ) total request time. (default: false ) limits.max-chunk-size http2 The max HTTP chunk size. access-log.enabled Enables HTTP/2. (default: true ) If access logging is enabled. (default: false ) limits.max-initial-line-length ssl.port The maximum length of the initial line. (default: 4096 ) access-log.pattern The HTTPS port. (default: 8443 ) The access log pattern. (default: common ) idle-timeout ssl certificate file Htt ti idl ti t (d f lt ) l l t fil If logging should be done to a separate le. (default: false ) @Path("/book") @Target({ElementType.METHOD}) public class BookResource { @Retention(RetentionPolicy.RUNTIME) access-log.base-file-name @HttpMethod("LOCK") The access log le base name. (default: quarkus ) @GET public @interface LOCK { @Produces(MediaType.APPLICATION_JSON) } access-log.log-directory public List getAllBooks() {} The log directory to use when logging access to a le. @LOCK @POST public void lockIt() {} access-log.log-directory @Produces(MediaType.APPLICATION_JSON) } public Response createBook(Book book) {} The log directory to use when logging access to a le.

@DELETE Injecting access-log.log-suffix @Path("{isbn}") The log le sux. (default: .log ) @Produces(MediaType.APPLICATION_JSON) Using @Context annotation to inject JAX-RS and Servlet information. public Response deleteBook( access-log.category @PathParam("isbn") String isbn) {} @GET

The log category to use if logging is being done via the standard public String getBase(@Context UriInfo uriInfo) {

log mechanism. (default: io.quarkus.http.access-log ) return uriInfo.getBaseUri(); @GET } access-log.rotate @Produces(MediaType.APPLICATION_JSON) @Path("search") If the log should be rotated daily. (default: true ) public Response searchBook( @QueryParam("description") String description) {} Possible injectable objects: SecurityContext , Request , Application , same-site-cookie..case-sensitive } Configuration , Providers , ResourceContext , ServletConfig , If the cookie pattern is case sensitive. ServletContext , HttpServletRequest , HttpServletResponse , HttpHeaders , Urinfo , SseEventSink and Sse . same-site-cookie..value To get information from request: HTTP Filters The value to set in the samesite attribute. @PathParam HTTP request and response can be intercepted to manipulate the same-site-cookie..enable-client-checker Gets content from request URI. (example: /book/{id} metadata (ie headers, parameters, media type, … ) or abort a Some User Agents break when sent SameSite=None, this will @PathParam("id") ) request. You only need to implement the next detect them and avoid sending the value. (default: true ) ContainerRequestFilter and ContainerResponseFilter JAX-RS @QueryParam interfaces respectively. same-site-cookie..add-secure-for-none Gets query parameter. (example: /book?desc="" If this is true then the 'secure' attribute will automatically be sent @QueryParam("desc) ) @Provider on cookies with a SameSite attribute of None. (default: true ) public class LoggingFilter @FormParam implements ContainerRequestFilter { If metrics extension is registered, you can enable to get HTTP Gets form parameter. metrics by setting quarkus.resteasy.metrics.enabled to true. @Context @MatrixParam UriInfo info;

JAX-RS Get URI matrix parameter. (example: @Context /book;author=mkyong;country=malaysia ) Quarkus uses JAX-RS to dene REST-ful web APIs. Under the HttpServletRequest request; covers, Rest-EASY is working with Vert.X directly without using any @CookieParam Servlet. @Override Gets cookie param by name. public void filter(ContainerRequestContext context) { It is important to know that if you want to use any feature that final String method = context.getMethod(); implies a Servlet (ie Servlet Filters) then you need to add the @HeaderParam final String path = info.getPath(); quarkus-undertow extension to switch back to the Servlet Gets header parameter by name. final String address = request.getRemoteAddr(); ecosystem but generally speaking, you don’t need to add it as System.out.println("Request %s %s from IP %s", method, path, address); everything else is well-supported. Valid HTTP method annotations provided by the spec are: @GET , } @POST , @PUT , @DELETE , @PATCH , @HEAD and @OPTIONS .

You can create new annotations that bind to HTTP methods not } dened by the spec.

Exception Mapper

You can map exceptions to produce a custom output by implementing ExceptionMapper interface: @Provider import io.quarkus.vertx.http.runtime.filters.Filters; @ApplicationScoped public class ErrorMapper import io.vertx.ext.web.Router; public class MyDeclarativeRoutes { implements ExceptionMapper { import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; @Route(path = "/hello", methods = HttpMethod.GET) @Override public void greetings(RoutingContext rc) { public Response toResponse(Exception exception) { @ApplicationScoped String name = rc.request().getParam("name"); int code = 500; public class MyBean { if (name == null) { if (exception instanceof WebApplicationException) { name = "world"; code = ((WebApplicationException) exception) public void filters( } .getResponse().getStatus(); @Observes Filters filters) { rc.response().end("hello " + name); } filters } return Response.status(code) .register( .entity( rc -> { @RouteFilter(20) Json.createObjectBuilder() rc.response() void filter(RoutingContext rc) { .add("error", exception.getMessage()) .putHeader("X-Filter", "filter 1"); rc.response().putHeader("X-Filter", "filter 2"); .add("code", code) rc.next(); rc.next(); .build() }, } ) 10); .build(); } @Route } String hello(@Param Optional name) {} } public void routes( @Observes Router router) { @Route router String helloFromHeader(@Header("My-Header") String head Caching .get("/") er) {} .handler(rc -> rc.response().end("OK")); Annotations to set Cache-Control headers: } @Route } String createPerson(@Body Person person) {}

@Produces(MediaType.APPLICATION_JSON) } @org.jboss.resteasy.annotations.cache.NoCache public User me() {} Declarative

@Produces(MediaType.APPLICATION_JSON) You can use @Route annotation to use reactive routes and GraphQL @org.jboss.resteasy.annotations.cache.Cache( @RouteFilter to sue reactive lters in a declarative way: maxAge = 2000, Quarkus integrates with GraphQL using MicroProle GraphQL noStore = false ./mvnw quarkus:add-extension integration. ) -Dextensions="quarkus-vertx-web" public User you() {} ./mvnw quarkus:add-extension -Dextensions="graphql" Vert.X Filters and Routes

Programmatically @GraphQLApi public class FilmResource { You can also register Vert.X Filters and Router programmatically inside a CDI bean: @Query("allFilms") public List films() { }

@Query public String getFilm(@Name("filmId") int id)) {}

@Query public List getHeroesWithSurname( @DefaultValue("Skywalker") String surname) { }

@Mutation public Greetings load(Greetings greetings) { }

} If name not provided, then query name is resolved from method extendig io.smallrye.mutiny.vertx.core.AbstractVerticle . ssl.key name. The le path to the corresponding certicate private key le in GZip Support PEM format. You can see the full schema at /graphql/schema.graphql . Also GraphiQL UI is enabled at dev and test mode at /graphql-ui/ . You can congure Quarkus to use GZip in the ssl.key-store Extension can be congured with the follwoing paramters prexed application.properties le using the next properties with An optional key store which holds the certicate information with quarkus.smallrye-graphql . quarkus.resteasy sux: instead of specifying separate les.

gzip.enabled root-path ssl.key-store-type The rootPath under which queries will be served. (default: EnableGZip. (default: false ) An optional parameter to specify the type of the key store le. /graphql ) gzip.max-input ssl.key-store-password root-path-ui Congure the upper limit on deated request body. (default: 10M ) A parameter to specify the password of the key store le. The path where GraphQL UI is available. (default: /graphql-ui ) (default: password ) GRPC always-include-ui ssl.trust-store The path where GraphQL UI is available. (default: /graphql-ui ) Quarkus integrates with gRPC: Trust store which holds the certicate information of the certicates to trust root-path-ui ./mvnw quarkus:add-extension Always include the UI. By default this will only be included in dev -Dextensions="quarkus-grpc" ssl.trust-store-type and test. (default: false ) Parameter to specify type of the trust store le.

enable-ui Then you need to congure build tool with gRPC plugins. In the ssl.trust-store-password If GraphQL UI should be enabled. (default: false ) case of Maven, the kr.motd.maven:os-maven-plugin extension and A parameter to specify the password of the trust store le. org.xolstice.maven.plugins:protobuf-maven-plugin

metrics.enabled ssl.cipher-suites Protos les are stored at src/main/proto . Enable metrics. (default: false ) A list of the cipher suites to use. When java les are created two service implementations are Vert.X Verticle provided: one with default gRPC API and other with Mutiny support. ssl.protocols The list of protocols to explicitly enable. (default: With quarkus.grpc.server prex, the next conguration properties Vert.X Verticles are also supported: TLSv1.3,TLSv1.2 ) can be set:

transport-security.certificate @ApplicationScoped port public class VerticleDeployer { The path to the certicate le. The gRPC Server port. (default: 9000 )

@Inject transport-security.key host Vertx vertx; The path to the private key le. The gRPC server host. (default: 0.0.0.0 ) public void init(@Observes StartupEvent ev) { To consume the service: CountDownLatch latch = new CountDownLatch(1); handshake-timeout vertx.deployVerticle(BareVerticle::new, The gRPC handshake timeout. new DeploymentOptions() @GrpcService("hello") GreeterGrpc.GreeterBlockingStub client; .setConfig( max-inbound-message-size new JsonObject() The max inbound message size in bytes. .put("id", "bare") @GrpcService("hello") ) io.grpc.Channel channel; plain-text ) .thenAccept(x -> latch.countDown()); Use plain text. (default: true ) Some conguration example to set the host and the SSL latch.countDown(); alpn parameters: } TWhether ALPN should be used. (default: true ) } quarkus.grpc.clients.hello.host=localhost enable-reflection-service quarkus.grpc.clients.hello.plain-text=false Enables the gRPC Reection Service. (default: false ) quarkus.grpc.clients.hello.ssl.certificate=src/main/resourc Verticles can be: es/tls/client.pem ssl.certificate quarkus.grpc.clients.hello.ssl.key=src/main/resources/tls/c bare The le path to a server certicate or certicate chain in PEM lient.key extending io.vertx.core.AbstractVerticle . format. quarkus.grpc.clients.hello.ssl.trust-store=src/main/resourc es/tls/ca.pem mutiny If 3 (4 x 0.75) failures occur among the rolling window of 4 Fault Tolerance org.acme.quickstart.WorldClock/getNow/Retry/enabled=false consecutive invocations then the circuit is opened for 1000 ms and # Disable everything except fallback then be back to half open. If the invocation succeeds then the Quarkus uses MicroProle Fault Tolerance spec: MP_Fault_Tolerance_NonFallback_Enabled=false circuit is back to closed again.

./mvnw quarkus:add-extension You can use bulkahead pattern to limit the number of concurrent -Dextensions="io.quarkus:quarkus-smallrye-fault-toleranc access to the same resource. If the operation is synchronous it MicroProle Fault Tolerance integrates with MicroProle e" uses a semaphore approach, if it is asynchronous a thread-pool Metrics spec. You can disable it by setting one. When a request cannot be processed BulkheadException is MP_Fault_Tolerance_Metrics_Enabled to false. thrown. It can be used together with any other fault tolerance MicroProle Fault Tolerance spec uses CDI interceptor and it can annotation. Observability be used in several elements such as CDI bean, JAX-RS resource or MicroProle Rest Client. @Bulkhead(5) Health Checks @Retry(maxRetries = 4, To do automatic retries on a method: delay = 1000, Quarkus relies on MicroProle Health spec to provide health retryOn = BulkheadException.class) checks. @Path("/api") WorldClock getNow(){} @RegisterRestClient ./mvnw quarkus:add-extension public interface WorldClockService { -Dextensions="io.quarkus:quarkus-smallrye-health" @GET @Path("/json/cet/now") Fault tolerance annotations: @Produces(MediaType.APPLICATION_JSON) @Retry(maxRetries = 2) Annotation Properties WorldClock getNow(); By just adding this extension, an endpoint is registered to /q/health } providing a default health check. @Timeout unit

{ "status": "UP", You can set fallback code in case of an error by using @Fallback maxRetries , delay , delayUnit , annotation: maxDuration , durationUnit , "checks": [ @Retry jitter , jitterDelayUnit , retryOn , ] abortOn } @Retry(maxRetries = 1) @Fallback(fallbackMethod = "fallbackMethod") WorldClock getNow(){} @Fallback fallbackMethod To create a custom health check you need to implement the public WorldClock fallbackMethod() { HealthCheck interface and annotate either with @Readiness (ready to return new WorldClock(); process requests) or @Liveness (is running) annotations. waitingTaskQueue (only valid in @Bulkhead } asynchronous) @Readiness public class DatabaseHealthCheck implements HealthCheck { @Override fallbackMethod must have the same parameters and return type as failOn , delay , delayUnit , public HealthCheckResponse call() { the annotated method. @CircuitBreaker requestVolumeThreshold , HealthCheckResponseBuilder responseBuilder = failureRatio , successThreshold You can also set logic into a class that implements FallbackHandler HealthCheckResponse.named("Database conn"); interface: @Asynchronous try { checkDatabaseConnection(); public class RecoverFallback responseBuilder.withData("connection", true); implements FallbackHandler { You can override annotation parameters via conguration le using responseBuilder.up(); @Override property [classname/methodname/]annotation/parameter : } catch (IOException e) { public WorldClock handle(ExecutionContext context) { // cannot access the database } responseBuilder.down() } org.acme.quickstart.WorldClock/getNow/Retry/maxDuration=30 # Class scope .withData("error", e.getMessage()); org.acme.quickstart.WorldClock/Retry/maxDuration=3000 } # Global return responseBuilder.build(); And set it in the annotation as value Retry/maxDuration=3000 } @Fallback(RecoverFallback.class) . }

In case you want to use circuit breaker pattern: You can also enable/disable policies using special parameter Builds the next output: @CircuitBreaker(requestVolumeThreshold = 4, enabled . failureRatio=0.75, delay = 1000) WorldClock getNow(){} Health groups are supported to provide custom health checks { quarkus.smallrye-health.root-path=/hello groups: "status": "UP", quarkus.smallrye-health.liveness-path=/customlive "checks": [ quarkus.smallrye-health.readiness-path=/customready { @io.smallrye.health.HealthGroup("mygroup1") "name": "Database conn", public class SimpleHealthGroupCheck implements HealthCheck { "status": "UP", Automatic readiness probes "data": { } "connection": true Some default readiness probes are provided by default if any of the } next features are added: } You can ping grouped health checks by querying /group/mygroup1 . ] datasource } A probe to check database connection status. Group root path can be congured:

kafka quarkus.smallrye-health.group-path=/customgroup Since health checks are CDI beans, you can do: A probe to check kafka connection status. In this case you need to enable manually by setting quarkus.kafka.health.enabled to @ApplicationScoped true . Metrics public class DatabaseHealthCheck { mongoDB Quarkus can utilize the MicroProle Metrics spec to provide metrics @Liveness A probe to check MongoDB connection status. support. HealthCheck check1() { return io.smallrye.health.HealthStatus neo4j ./mvnw quarkus:add-extension .up("successful-live"); -Dextensions="io.quarkus:quarkus-smallrye-metrics" } A probe to check Neo4J connection status.

@Readiness artemis HealthCheck check2() { A probe to check Artemis JMS connection status. The metrics can be read with JSON or the OpenMetrics format. An return HealthStatus endpoint is registered automatically at /q/metrics providing default metrics. .state("successful-read", this::isReady) kafka-streams } Liveness (for stream state) and Readiness (topics created) MicroProle Metrics annotations: probes. private boolean isReady() {} @Timed } vault Tracks the duration. A probe to check Vault conection status. @SimplyTimed You can ping liveness or readiness health checks individually by gRPC Tracks the duration without mean and distribution calculations. querying /q/health/live or /q/health/ready . A readiness probe for the gRPC services. Quarkus comes with some HealthCheck implementations for @Metered checking service status. Cassandra Tracks the frequency of invocations. A readiness probe to check Cassandra connection status. SocketHealthCheck: checks if host is reachable using a @Counted socket. Redis Counts number of invocations. UrlHealthCheck: checks if host is reachable using a Http URL A readiness probe to check Redis connection status. connection. @Gauge You can disable the automatic generation by setting Samples the value of the annotated object. InetAddressHealthCheck: checks if host is reachable using .health.enabled to false. InetAddress.isReachable method. @ConcurrentGauge quarkus.kafka-streams.health.enabled=false Gauge to count parallel invocations. @Liveness quarkus.mongodb.health.enabled=false HealthCheck check1() { quarkus.neo4j.health.enabled=false @Metric return new UrlHealthCheck("https://www.google.com") Used to inject a metric. Valid types Meter , Timer , Counter , .name("Google-Check"); Histogram . Gauge only on producer methods/elds. } In the case of Vault you can pass parameters to modify the call of the status endpoint in Vault.

If you want to override or set manually readiness/liveness probes, quarkus.vault.health.enabled=true you can do it by setting health properties: quarkus.vault.health.stand-by-ok=true quarkus.vault.health.performance-stand-by-ok=true export.prometheus.path @GET @Stereotype //... @Retention(RetentionPolicy.RUNTIME) The path for the prometheus metrics endpoint (produces @Timed(name = "checksTimer", @Target({ ElementType.TYPE, ElementType.METHOD, ElementTyp text/plain). (default: /q/metrics ) description = "A measure of how long it takes e.FIELD }) to perform a hello.", @Timed(name = "checksTimer", export.azuremonitor.enabled unit = MetricUnits.MILLISECONDS) description = "A measure of how long it takes Support for export to Azure Monitor. public String hello() {} to perform a hello.", unit = MetricUnits.MILLISECONDS) export.azuremonitor.instrumentation-key @Counted(name = "countWelcome", public @interface TimedMilliseconds { The path for the azure monitor instrumentationKey. description = "How many welcome have been performed.") } public String hello() {} export.statsd.enabled Support for export to StatsD. There is a tight integration with Micrometer in the form of an @Gauge annotation returning a measure as a gauge. extension: export.stackdriver.enabled Micrometer metrics support. (default: true ) @Gauge(name = "hottestSauce", unit = MetricUnits.NONE, ./mvnw quarkus:add-extension description = "Hottest Sauce so far.") -Dextensions="micrometer" export.signalfx.enabled public Long hottestSauce() {} Micrometer metrics support. (default: true ) Add a micrometer dependency for the registry of your choosing: export.signalfx.uri Injecting a histogram using @Metric . Signalfx URI. @Inject io.micrometer export.signalfx.access-token @Metric(name = "histogram") micrometer-registry-prometheus Histogram historgram; Access Token.

binder.vertx.match-patterns

You can congure Metrics: You can congure Micrometer. Prex is quarkus.micrometer : Comma-separated case-sensitive list of regular expressions dening Paths that should be matched and used as tags enabled quarkus.smallrye-metrics.path=/mymetrics Micrometer metrics support. (default: true ) binder.vertx.ignore-patterns Comma-separated case-sensitive list of regular expressions registry-enabled-default dening Paths that should be ignored / not measured. Prex is quarkus.smallrye-metrics . Micrometer MeterRegistry discovery. (default: true ) export.datadog path Datadog MeterRegistry conguration in Map The path to the metrics handler. (default: /q/metrics ) binder-enabled-default format. Micrometer MeterBinder discovery. (default: true ) extensions.enabled export.jmx Metrics are enabled or not. (default: true ) binder.vertx.enabled Vert.x metrics support. JMX registry conguration properties in Map format. micrometer.compatibility Apply Micrometer compatibility mode. (default: false ) binder.mp-metrics.enabled export.prometheus Microprole Metrics support. Prometheus registry conguration properties in Map format. Hibernate metrics under vendor scope. binder.jvm Micrometer JVM metrics support. (default: true ) quarkus.mongodb.metrics.enabled set to true exposes MongoDB export.stackdriver metrics under vendor scope. Stackdriver registry conguration properties in Map format. You can apply metrics annotations via CDI stereotypes: Micrometer System metrics support. (default: true ) Tracing export.datadog.enabled Support for export to Datadog Support for Datadog. Quarkus can utilize the MicroProle OpenTracing spec.

export.jmx.enabled ./mvnw quarkus:add-extension Support for export to JMX Support for JMX. -Dextensions="io.quarkus:quarkus-smallrye-opentracing"

export.prometheus.enabled Support for export to Prometheus. Requests sent to any endpoint are traced automatically. This extension includes OpenTracing support and Jaeger tracer. Kafka Tracer Native Executable Jaeger tracer conguration: Adds a span for each message sent to or received from a Kafka You can build a native image by using GraalVM. The common use topic. case is creating a Docker image so you can execute the next quarkus.jaeger.service-name=myservice commands: quarkus.jaeger.sampler-type=const quarkus.jaeger.sampler-param=1 io.opentracing.contrib ./mvnw package -Pnative -Dquarkus.native.container-build=tr quarkus.jaeger.endpoint=http://localhost:14268/api/traces opentracing-kafka-client< ue quarkus.jaeger.metrics.enabled=true

docker build -f src/main/docker/Dockerfile.native -t quarkus/getting-started . @Traced annotation can be set to disable tracing at class or method And congure it: docker run -i --rm -p 8080:8080 quarkus/getting-started level. ... Tracer class can be injected into the class. mp.messaging.outgoing.generated-price.topic=prices You can use quarkus.native.container-runtime to select the container runtime to use. Now docker (default) and podman are the @Inject # For Produces valid options. Tracer tracer; mp.messaging.outgoing.generated-price.interceptor.classes=i o.opentracing.contrib.kafka.TracingProducerInterceptor ./mvnw package -Pnative -Dquarkus.native.container-runtime= tracer.activeSpan().setBaggageItem("key", "value"); ... podman # For consumers mp.messaging.incoming.prices.interceptor.classes=io.opentra You can disable Jaeger extension by using quarkus.jaeger.enabled cing.contrib.kafka.TracingConsumerInterceptor property. To congure native application, you can create a config directory at the same place as the native le and place an application.properties le inside. config/application.properties . You can log the traceId , spanId and sampled in normal log: AWS XRay SSL quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{tra If you are building native images, and want to use AWS X-Ray ceId}, Tracing with your lambda you will need to include quarkus-amazon- To create a native image with SSL you need to copy SunEC library spanId=%X{spanId}, sampled lambda-xray as a dependency in your pom. and certicates: =%X{sampled} [%c{2.}] (%t) %s%e%n Java 8:

Additional tracers FROM quay.io/quarkus/ubi-quarkus-native-image:{-vers ion}-java8 as nativebuilder JDBC Tracer RUN mkdir -p /tmp/ssl-libs/lib \ && cp /opt/graalvm/jre/lib/security/cacerts /tmp/ssl-libs Adds a span for each JDBC queries. \ && cp /opt/graalvm/jre/lib/amd64/libsunec.so /tmp/ssl-lib s/lib/ io.opentracing.contrib opentracing-jdbc FROM registry.access.redhat.com/ubi8/ubi-minimal WORKDIR /work/ COPY --from=nativebuilder /tmp/ssl-libs/ /work/ COPY target/*-runner /work/application Congure JDBC driver apart from tracing properties seen before: RUN chmod 775 /work /work/application EXPOSE 8080 CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Djav # add ':tracing' to your database URL a.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/wor quarkus.datasource.url= k/cacerts"] jdbc:tracing:postgresql://localhost:5432/mydatabase quarkus.datasource.driver= io.opentracing.contrib.jdbc.TracingDriver quarkus.hibernate-orm.dialect= Java 11: org.hibernate.dialect.PostgreSQLDialect

OpenTelemetry

Quarkus integrates with the OpenTelemetry project. For exporting traces to a Jaeger collector, use the quarkus-opentelemetry- exporter-jaeger extension If all character sets should be added to the native image. full-stack-traces FROM quay.io/quarkus/ubi-quarkus-native-image:{graalvm-vers ion}-java11 as nativebuilder If full stack traces are enabled in the resulting image. RUN mkdir -p /tmp/ssl-libs/lib \ graalvm-home && cp /opt/graalvm/lib/security/cacerts /tmp/ssl-libs \ The location of the Graal distribution. enable-reports && cp /opt/graalvm/lib/libsunec.so /tmp/ssl-libs/lib/ If the reports on call paths and included java-home packages/classes/methods should be generated. FROM registry.access.redhat.com/ubi8/ubi-minimal The location of the JDK. WORKDIR /work/ report-exception-stack-traces COPY --from=nativebuilder /tmp/ssl-libs/ /work/ native-image-xmx If exceptions should be reported with a full stack trace. COPY target/*-runner /work/application The maximum Java heap to be used during the native image RUN chmod 775 /work /work/application generation. report-errors-at-runtime EXPOSE 8080 CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Djav If errors should be reported at runtime. a.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/wor debug-build-process k/cacerts"] If the native image build should wait for a debugger to be enable-dashboard-dump attached before running. Generate the report les for GraalVM Dashboard.

Inclusion of resources publish-debug-build-process-port resources.includes If the debug port should be published when building with docker A comma separated list of globs to match resource paths that By default, no resources are included in native executable. and debug-build-process. (default: true ) should be added to the native image. quarkus.native.resources.includes allows to set glob expressions to src/main/resources include resources based on path. cleanup-server resources.excludes If the native image server should be restarted. Given src/main/resources/foo/selected.png : A comma separated list of globs to match resource paths that should exclude to the native image. enable-isolates quarkus.native.resources.includes=foo/** If isolates should be enabled. (default: true ) debug.enabled If debug is enabled and debug symbols are generated. enable-fallback-images Exclusion of resources If a JVM based 'fallback image' should be created if native image Container Images Creation By default, no resources are excluded. fails. You can levarage to Quarkus to generation and release of Docker enable-server quarkus.native.resources.excludes = foo/** containers. It provides several extensions to make it so. If the native image server should be used. mvn clean package auto-service-loader-registration -Dquarkus.container-image.build=true Native conguration properties prexed with quarkus.native : If all META-INF/services entries should be automatically -Dquarkus.container-image.push=true additional-build-args registered. -Dquarkus.container-image.registry=quay.io Additional arguments to pass to the build process. dump-proxies

enable-http-url-handler If the bytecode of all proxies should be dumped for inspection. Prex is quarkus.container-image : If the HTTP url handler should be enabled. (default: true ) container-build group The group/repository of the image. (default: the ${user.name} ) enable-https-url-handler If this build should be done using a container runtime. If the HTTPS url handler should be enabled. remote-container-build name The name of the image. (default: the application name) enable-all-security-services If this build is done using a remote docker daemon. If all security services should be added to the native image. builder-image tag The tag of the image. (default: the application version) user-language The docker image to use to do the image build. Denes the user language used for building the native additional-tags executable. container-runtime The container runtime that is used to do an image based build. Additional tags of the container image. user-country ( docker , podman ) registry Denes the user country used for building the native executable. container-runtime-options The registry to use for pushing. (default: docker.io )

file-encoding Options to pass to the container runtime. username Denes the le encoding. enable-vm-inspection The registry username. If the resulting image should allow VM introspection password ports Running ./mvnw package the Kubernetes resources are created at The registry password. The ports to expose. target/kubernetes/ directory. insecure user Container Images Creation integrates with Kubernetes extension, so no need of extra Kubernetes properties. Flag to allow insecure registries. (default: false ) The user to use in generated image. Generated resource is integrated with MicroProle Health build always-cache-base-image annotations. Boolean to set if image should be built. (default: false ) Controls the optimization which skips downloading base image layers that exist in a target registry (default: false ). Also, you can customize the generated resource by setting the new push values in application.properties : Boolean to set if image should be pushed. (default: false ) appcds-builder-image When AppCDS generation is enabled, if this property is set, then quarkus.kubernetes.namespace=mynamespace Jib the JVM used to generate the AppCDS le will be the JVM present in the container image. quarkus.kubernetes.replicas=3

./mvnw quarkus:add-extensions quarkus.kubernetes.labels.foo=bar -Dextensions="quarkus-container-image-jib" platforms

List of target platforms. (ie linux/amd64 ). quarkus.kubernetes.readiness-probe.period-seconds=45

Docker Quarkus copies any le under src/main/jib into the built container quarkus.kubernetes.mounts.github-token.path=/deployment/git image. hub ./mvnw quarkus:add-extensions quarkus.kubernetes.mounts.github-token.read-only=true Prex is quarkus.container-image-jib : -Dextensions="quarkus-container-image-docker" quarkus.kubernetes.secret-volumes.github-token.volume-name= base-jvm-image github-token The base image to use for the jib build. (default: fabric8/java- Prex is quarkus.container-image-s2i : quarkus.kubernetes.secret-volumes.github-token.secret-name= alpine-openjdk8-jre ) greeting-security dockerfile-jvm-path quarkus.kubernetes.secret-volumes.github-token.default-mode base-native-image Path to the JVM Dockerle. (default: =420

The base image to use for the native build. (default: ${project.root}/src/main/docker/Dockerfile.jvm ) registry.access.redhat.com/ubi8/ubi-minimal ) quarkus.kubernetes.config-map-volumes.github-token.config-m ap-name=my-secret dockerfile-native-path jvm-arguments Path to the native Dockerle. (default: quarkus.kubernetes.expose=true The arguments to pass to java. (default: - ${project.root}/src/main/docker/Dockerfile.native ) quarkus.kubernetes.ingress.expose=true Dquarkus.http.host=0.0.0.0,- quarkus.kubernetes.ingress.host=example.com Djava.util.logging.manager=org.jboss.logmanager.LogManager ) S2I quarkus.kubernetes.env.vars.my-env-var=foobar native-arguments ./mvnw quarkus:add-extensions quarkus.kubernetes.env.configmaps=my-config-map,another-con The arguments to pass to the native application. (default: - -Dextensions="quarkus-container-image-s2i" fig-map Dquarkus.http.host=0.0.0.0 ) quarkus.kubernetes.env.secrets=my-secret,my-other-secret environment-variables quarkus.kubernetes.resources.requests.memory=64Mi Prex is quarkus.container-image-docker : Map of environment variables. quarkus.kubernetes.resources.requests.cpu=250m base-jvm-image quarkus.kubernetes.resources.limits.memory=512Mi quarkus.kubernetes.resources.limits.cpu=1000m jvm-entrypoint The base image to use for the s2i build. (default: fabric8/java- A custom entry point of the container image in JVM mode. alpine-openjdk8-jre ) native-entrypoint base-native-image All possible values are explained at https://quarkus.io/guides/kubernetes#conguration-options. A custom entry point of the container image in native mode. The base image to use for the native build. (default: registry.access.redhat.com/ubi8/ubi-minimal ) Labels and Annotations labels Custom labels to add to the generated image. Kubernetes The generated manifest use the Kubernetes recommended labels and annotations. base-registry-username Quarkus can use Dekorate to generate Kubernetes resources. The username to use to authenticate with the registry used to pull the base JVM image. ./mvnw quarkus:add-extensions -Dextensions="quarkus-kubernetes" base-registry-password The password to use to authenticate with the registry used to pull openshift Datasource conguration part is absent as it is aut-discovered by "labels" : { Quarkus. "app.kubernetes.io/part-of" : "todo-app", https://quarkus.io/guides/kubernetes#openshift "app.kubernetes.io/name" : "todo-rest", "app.kubernetes.io/version" : "1.0-rc.1" Knative Minikube } https://quarkus.io/guides/kubernetes#knative Quarkus has a Minikube extension which creates Kubernetes "annotations": { Using Existing Resources manifests that are tailored for Minikube. "app.quarkus.io/vcs-url" : "", "app.quarkus.io/commit-id" : "", You an provide your Kubernetes resources in form of yaml/json and ./mvnw quarkus:add-extension } they will provide additional resources or be used as base for the -Dextensions="minikube" generation process:

Resources are added in src/main/kubernetes directory with the You can override the labels by using the next properties: target name ( kubernetes.json , openshift.json , knative.json , or the Remember to execute eval $(minikube -p minikube docker- yml equivalents) with one orm ore Kubernetes resources. Any env) to build images directly inside Minkube cluster. quarkus.kubernetes.part-of=todo-app resource found will be added in the generated manifests. If one of quarkus.kubernetes.name=todo-rest the provided resources has the same name as one of the generated OpenShift quarkus.kubernetes.version=1.0-rc.1 ones, then the generated resource will be created on top of the provided resource, respecting existing content. Instead of adding Kubernetes extension, set container image s2i and the target to openshift for working with OpenShift, an Or add new labels and/or annotations: To override the name of the generated resource you can use: extension grouping all of the is created: quarkus.kubernetes.name , quarkus.openshift.name and quarkus.knative.name . quarkus.kubernetes.labels.foo=bar ./mvnw quarkus:add-extension quarkus.kubernetes.annotations.foo=bar Deployment -Dextensions="openshift"

To deploy automatically the generated resources, you need to set metrics quarkus.container.deploy ag to true . Kubernetes Conguration Extension When using metrics extension, Prometheus annotations are mvn clean package -Dquarkus.kubernetes.deploy=true Integration between MicroProle Cong spec and CongMaps & generated: Secrets:

prometheus.io/scrape: "true" If you set this ag to true , the build and push ags from ./mvnw quarkus:add-extensions prometheus.io/path: /metrics container-image are set to true too. -Dextensions="quarkus-kubernetes-config" prometheus.io/port: "8080" To deploy the application, the extension uses the https://github.com/fabric8io/kubernetes-client. All options Kubernetes Deployment Targets described at Kubernetes Client are valid here. quarkus.kubernetes-config.enabled=true quarkus.kubernetes-config.config-maps=cmap1,cmap2 You can generate different resources setting the property Kubernetes Service Binding quarkus.kubernetes.deployment-target . Quarkus supports binding services to applications via the Service Possible values are kubernetes , openshift and knative . The default Binding Specication for Kubernetes. @ConfigProperty(name = "some.prop1") value is kubernetes . String someProp1; The following Quarkus extensions support this feature: Knative Properties @ConfigProperty(name = "some.prop2") quarkus-jdbc-mariadb String someProp2; Most of the Kubernetes properties are valid in Knative output by just changing the kubernetes prex to knative prex (ie quarkus-jdbc-mssql quarkus.kubernetes.readiness-probe.period-seconds to quarkus.knative.readiness-probe.period-seconds ). quarkus-jdbc-mysql If the cong key is a Quarkus conguration le application.properties / application.yaml , the content is parsed and There are also specic properties for Knative: quarkus-jdbc-postgresql each key of the conguration le is used as cong property.

quarkus-kafka-client List of Kubernetes Cong parameters. quarkus.kubernetes.deployment-target=knative quarkus.knative.revision-name=my-revision quarkus-smallrye-reactive-messaging-kafka quarkus.kubernetes-config as prex is skipped in the next table. quarkus.knative.traffic.my-revision.percentage=80

./mvnw quarkus:add-extensions enabled -Dextensions="quarkus-kubernetes-service-binding" The application will attempt to look up the conguration from the List of conguration options: API server. (default: false ) kubernetes fail-on-missing-config https://quarkus io/guides/kubernetes#conguration options The application will not start if any of the congured cong watch-reconnect-interval @Inject sources cannot be located. (default: true ) Watch reconnect interval. (default: PT1S ) KubernetesClient client; config-maps watch-reconnect-limit ServiceList myServices = client.services().list(); CongMaps to look for in the namespace that the Kubernetes Maximum reconnect attempts. (default: -1 ) Client has been congured for. Supports CSV. Service myservice = client.services() connection-timeout .inNamespace("default") namespace .withName("myservice") Maximum amount of time to wait for a connection. (default: .get(); Access to CongMaps from a specic namespace. PT10S )

CustomResourceDefinitionList crds = client secrets.enabled request-timeout .customResourceDefinitions() Whether or not conguration can be read from secrets. (default: Maximum amount of time to wait for a request. (default: PT10S ) .list(); false )

rolling-timeout dummyCRD = new CustomResourceDefinitionBuilder() Kubernetes Client Maximum amount of time to wait for a rollout. (default: PT15M ) ... .build() Quarkus integrates with Fabric8 Kubernetes Client. http-proxy client.customResourceDefinitions() .create(dummyCRD); HTTP proxy used to access the Kubernetes. ./mvnw quarkus:add-extension -Dextensions="quarkus-kubernetes-client" https-proxy Testing HTTPS proxy used to access the Kubernetes. Quarkus provides a Kubernetes Mock test resource that starts a List of Kubernetes client parameters. proxy-username mock of Kubernetes API server and sets the proper environment Proxy username. quarkus.kubernetes-client as prex is skipped in the next table. variables needed by Kubernetes Client. trust-certs proxy-password Register next dependency: io.quarkus:quarkus-test-kubernetes- client:test . Trust self-signed certicates. (default: false ) Proxy password.

@QuarkusTestResource(KubernetesMockServerTestResource.clas master-url no-proxy s) IP addresses or hosts to exclude from proxying URL of Kubernetes API server. @QuarkusTest public class KubernetesClientTest { Or programmatically: namesapce Default namespace. @MockServer @Dependent private KubernetesMockServer mockServer; ca-cert-file public class KubernetesClientProducer { CA certicate data. @Test @Produces public void test() { public KubernetesClient kubernetesClient() { final Pod pod1 = ... client-cert-file Config config = new ConfigBuilder() mockServer Client certicate le. .withMasterUrl("https://mymaster.com") .expect() .build(); .get() client-cert-data return new DefaultKubernetesClient(config); .withPath("/api/v1/namespaces/test/pods") Client certicate data. } .andReturn(200, } new PodListBuilder() client-key-data .withNewMetadata() Client key data. .withResourceVersion("1") And inject it on code: .endMetadata() .withItems(pod1, pod2) client-key-algorithm .build()) Client key algorithm. .always(); } client-key-passphrase } Client key passphrase. username AWS Lambda Username. Quarkus integrates with Amazon Lambda. password Password The Cloud Event type that triggers the function is defaultChain . It ./mvnw quarkus:add-extension mvn archetype:generate \ generates a response that triggers a new Cloud Event whose type is -Dextensions="io.quarkus:quarkus-amazon-lambda" -DarchetypeGroupId=io.quarkus \ defaultChain.output and the event source is defaultChain . -DarchetypeArtifactId=quarkus-azure-functions-http-archet ype \ It can be changed by using the next properties: And then implement -DarchetypeVersion={version} com.amazonaws.services.lambda.runtime.RequestHandler interface. quarkus.funqy.knative-events.mapping.defaultChain.trigger=c onfigChain.output public class TestLambda Funqy quarkus.funqy.knative-events.mapping.defaultChain.response- implements RequestHandler { type=annotated @Override Quarkus Funqy is part of Quarkus’s serverless strategy and aims to quarkus.funqy.knative-events.mapping.defaultChain.response- public MyInput handleRequest(MyOutput input, provide a portable Java API to write functions deployable to various source=configChain Context context) { FaaS environments like AWS Lambda, Azure Functions, Knative, and } Knative events. } The properties are of form: quarkus.funqy.knative-events.mapping. public class GreetingFunction { {function name}. .

The interface @Inject Also can be overriden with com.amazonaws.services.lambda.runtime.RequestStreamHandler is also GreetingService service; @io.quarkus.funqy.knative.events.CloudEventMapping annotation. supported. @io.quarkus.funqy.Funq @Funq The interface com.amazon.ask.SkillStreamHandler is also supported. public String greet(String name) {} @CloudEventMapping(trigger = "annotated", responseSource = "annotated", responseType = "lastChainLink") You can set the handler name by using quarkus.lambda.handler @io.quarkus.funqy.Funq("HelloCustomer") public String annotatedChain(String input) {} property or by annotating the Lambda with the CDI @Named public String greet(Customer name) {} annotation. @Funq Test responseType chains annotatedChain response to lastChainLink public Greeting greet(Friend friend, function. You can write tests for Amazon lambdas: @io.quarkus.funqy.Context AwsContext ctx) {} } @Funq public void lastChainLink(String input, io.quarkus @Context io.quarkus.funqy.knative.events.CloudE In case of Amazon Lambda, only one Funqy function can be quarkus-test-amazon-lambda vent event) {} test exported per Amazon Lambda deployment. If there is only one method annotated with @Funq then no prob, if not, you need to set the function name with quarkus.funqy.export property. A K-Native Trigger looks like: Funqy HTTP @Test apiVersion: eventing.knative.dev/v1alpha1 public void testLambda() { You can invoke on Funqy functions in a pure HTTP environment kind: Trigger MyInput in = new MyInput(); with simple adding the Funqy HTTP extension. metadata: in.setGreeting("Hello"); name: defaultchain in.setName("Stu"); spec: MyOutput out = LambdaClient.invoke(MyOutput.class, in); filter: io.quarkus } attributes: quarkus-funqy-http type: defaultChain subscriber: To scaffold a AWS Lambda run: ref: apiVersion: serving.knative.dev/v1 Funqy Cloud Events kind: Service mvn archetype:generate \ name: funqy-knative-events-quickstart -DarchetypeGroupId=io.quarkus \ Add the extension: -DarchetypeArtifactId=quarkus-amazon-lambda-archetype \ -DarchetypeVersion={version} And to curl from inside the Kubernetes cluster: io.quarkus quarkus-funqy-knative-events Azure Functions

Quarkus can make a microservice be deployable to the Azure Functions. @Funq To scaffold a deployable microservice to the Azure Functions run: public String defaultChain(String input) {} Possible Swagger UI options with quarkus.swagger-ui prex: curl -v "http://default-broker.knativetutorial.svc.cluster. local" \ urls -X POST \ Apache Camel Quarkus has its own site: -H "Ce-Id: 1234" \ https://github.com/apache/camel-quarkus The urls that will be included as options. (ie quarkus.swagger- -H "Ce-Specversion: 1.0" \ ui.urls.petstore=https://petstore.swagger.io/v2/swagger.json ) -H "Ce-Type: defaultChain" \ WebSockets -H "Ce-Source: curl" \ urls-primary-name -H "Content-Type: application/json" \ Quarkus can be used to handling web sockets. If urls option is used, this will be the name of the default -d '"Start"' selection.

./mvnw quarkus:add-extension title -Dextensions="quarkus-websockets" The html title for the page.

And web sockets classes can be used: theme Swagger UI theme to be used.

@ServerEndpoint("/chat/{username}") footer @ApplicationScoped public class ChatSocket { A footer for the html page. Nothing by default.

@OnOpen deep-linking public void onOpen(Session session, Enables deep linking for tags and operations. @PathParam("username") String username) {} display-operation-id @OnClose Controls the display of operationId in operations list. public void onClose(..) {}

default-models-expand-depth @OnError public void onError(..., Throwable throwable) {} The default expansion depth for models.

@OnMessage default-model-expand-depth public void onMessage(...) {} The default expansion depth for the model on the model-example section. } default-model-rendering Controls how the model is shown when the API is rst rendered. OpenAPI display-request-duration Quarkus can expose its API description as OpenAPI spec and test it Controls the display of the request duration (in milliseconds) for using Swagger UI. "Try it out" requests.

./mvnw quarkus:add-extension doc-expansion -Dextensions="io.quarkus:quarkus-smallrye-openapi" Controls the default expansion setting for the operations and tags.

Then you only need to access to /openapi to get OpenAPI v3 spec filter of services. Enables ltering.

quarkus.smallrye- You can update the OpenApi path by setting max-displayed-tags openapi.path property. Limits the number of tagged operations displayed to at most this Also, in case of starting Quarkus application in dev or test mode, many. Swagger UI is accessible at /swagger-ui . If you want to use it in production mode you need to set quarkus.swagger-ui.always- operations-sorter include property to true . Apply a sort to the operation list of each API. ( alpha , method , function ) You can update the Swagger UI path by setting quarkus.swagger- ui.path property. show-extensions Controls the display of vendor extension. quarkus.swagger-ui.path=/my-custom-path

show-common-extensions Controls the display of extensions. presets Add a Security Scheme name to the generated OpenAPI A list of presets to use in Swagger UI. document. (default: SecurityScheme ) tag-sorter Apply a sort to the tag list of each API. You can customize the output by using Open API v3 annotations. security-scheme-description Add a description to the Security Scheme. (default: on-complete @Schema(name="Developers", Authentication ) Provides a mechanism to be notied when Swagger UI has description="POJO that represents a developer.") nished rendering a newly provided denition. public class Developer { basic-security-scheme-value @Schema(required = true, example = "Alex") Add a scheme value to the Basic HTTP Security Scheme. syntax-highlight private String name; (default: basic ) Set to false to deactivate syntax highlighting of payloads and } cURL command. jwt-security-scheme-value @POST Add a scheme value to the JWT Security Scheme. (default: @Path("/developer") oauth2-redirect-url bearer ) @Operation(summary = "Create deeloper", OAuth redirect URL. description = "Only be done by admin.") jwt-bearer-format public Response createDeveloper( request-interceptor @RequestBody(description = "Developer object", Add a bearer format to the JWT Security Scheme. (default: JWT ) Function to intercept remote denition, "Try it out", and OAuth 2.0 required = true, requests. content = @Content(schema = oidc-open-id-connect-url @Schema(implementation = Developer.class))) Add a openIdConnectUrl value to the OIDC Security Scheme request-curl-options Developer developer) Array of command line options available to the curl command. oauth2-implicit-refresh-url Add a implicit ow refreshUrl value to the OAuth2 Security response-interceptor All possible annotations can be seen at Scheme Function to intercept remote denition, "Try it out", and OAuth 2.0 org.eclipse.microprole.openapi.annotations package. responses. oauth2-implicit-authorization-url You can also serve OpenAPI Schema from static les instead of Add an implicit ow authorizationUrl value to the OAuth2 Security dynamically generated from annotation scanning. show-mutated-request Scheme

Uses the mutated request returned from a requestInterceptor to You need to put OpenAPIdocumentation under META-INF directory oauth2-implicit-token-url produce the curl command in the UI. (ie: META-INF/openapi.yaml ). Add an implicit ow tokenUrl value to the OAuth2 Security supported-submit-methods A request to /openapi will serve the combined OpenAPI document Scheme from the static le and the generated from annotations. You can List of HTTP methods that have the "Try it out" feature enabled. disable the scanning documents by adding the next conguration Mail Sender property: mp.openapi.scan.disable=true . validator-url You can send emails by using Quarkus Mailer extension: Swagger UI attempts to validate specs against swagger.io’s Other valid document paths are: META-INF/openapi.yml , META- online validator. INF/openapi.json , WEB-INF/classes/META-INF/openapi.yml , WEB- INF/classes/META-INF/openapi.yaml , WEB-INF/classes/META- ./mvnw quarkus:add-extension with-credentials INF/openapi.json . -Dextensions="io.quarkus:quarkus-mailer" Enables passing credentials, as dened in the Fetch standard, in CORS requests that are sent by the browser. You can store generated OpenAPI schema if quarkus.swagger- ui.store-schema-directory is set. You can inject two possible classes io.quarkus.mailer.Mailer for model-property-macro synchronous API or io.quarkus.mailer.reactive.ReactiveMailer for Possible OpenAPI options with quarkus.smallrye-openapi prex: Function to set default values to each property in model. asynchronous/reactive API. path parameter-macro The path at which to register the OpenAPI Servlet. (default: @Inject Function to set default value to parameters. openapi ) Mailer mailer; persist-authorization store-schema-directory It persists authorization data and it would not be lost on browser The generated OpenAPI schema documents will be stored here And then you can use them to send an email: close/refresh. on build. mailer.send( layout security-scheme Mail.withText("[email protected]", "Subject", "Body") The name of a component available via the plugin system to use Add a certain SecurityScheme with cong. ( basic , jwt , oidc , ); as the top-level layout for Swagger UI. oauth2Implicit ) plugins security-scheme-name Reactive Mail client A list of plugin functions to use in Swagger UI. @Inject Parameter Default Description @Inject ReactiveMailer reactiveMailer; MockMailbox mailbox; mailer.password The password. CompletionStage stage = @BeforeEach reactiveMailer.send( void init() { Mail.withText("[email protected]", "Subject", "Body") mailer.ssl false Enables SSL. mailbox.clear(); ) } .subscribeAsCompletionStage() mailer.trust-all false Trust all certicates. .thenApply(x -> Response.accepted().build()); List sent = mailbox .getMessagesSentTo("[email protected]"); Max open mailer.max-pool-size 10 If you are using quarkus-resteasy-mutiny , you can return connections . io.smallrye.mutiny.Uni type. Scheduled Tasks

Mail class contains methods to add cc , bcc , headers , bounce Hostname for You can schedule periodic tasks with Quarkus. address , reply to , attachments , inline attachments and html body . mailer.own-host-name HELO/EHLO and Message-ID @ApplicationScoped mailer.send(Mail.withHtml("[email protected]", "Subject", body) public class CounterBean { .addInlineAttachment("quarkus.png", Connection pool new File("quarkus.png"), mailer.keep-alive true enabled. @Scheduled(every="10s", delayed="1s") "image/png", "")); void increment() {}

mailer.disable-esmtp false Disable ESMTP. @Scheduled(cron="0 15 10 * * ?") If you need deep control you can inject Vert.x mail client void morningTask() {} @Inject MailClient client; } TLS security mode. You need to congure SMTP properties to be able to send an email: mailer.start-tls OPTIONAL DISABLED , OPTIONAL , REQUIRED . every and cron parameters can be surrounded with {} and the [email protected] value is used as cong property to get the value. quarkus.mailer.host=smtp.sendgrid.net Login mode. NONE , quarkus.mailer.port=465 mailer.login NONE @Scheduled(cron = "{morning.check.cron.expr}") OPTIONAL , REQUIRED . quarkus.mailer.ssl=true void morningTask() {} quarkus.mailer.username=.... quarkus.mailer.password=.... mailer.auth-methods All methods. Space-separated list. And congure the property into application.properties :

morning.check.cron.expr=0 15 10 * * ? List of Mailer parameters. quarkus. as a prex is skipped in the next mailer.key-store Path of the key store. table.

Parameter Default Description mailer.key-store- Key store password. By default Quarkus expresion is used, but you can change that by password setting quarkus.scheduler.cron-type property. mailer.from Default address. if you enable SSL for the mailer and you want to build a native executable, you will need to enable the SSL support quarkus.scheduler.cron-type=unix Emails not sent, just quarkus.ssl.native=true . false in prod , true in mailer.mock printed and stored in dev and test . a MockMailbox . Testing org.quartz.Scheduler can be injected as any other bean and scehdule jobs programmatically. If quarkus.mailer.mock is set to true , which is the default value in dev and test mode, you can inject MockMailbox to get the sent mailer.bounce- @Inject Default address. messages. address org.quartz.Scheduler quartz;

quartz.scheduleJob(job, trigger); mailer.host mandatory SMTP host.

mailer.port 25 SMTP port. Kogito

Quarkus integrates with Kogito, a next-generation business mailer.username The username. automation toolkit from Drools and jBPM projects for adding business automation capabilities. To start using it you only need to add the next extension: try (Git git = Git.cloneRepository() import org.jboss.stm.annotations.ReadLock; .setDirectory(tmpDir) import org.jboss.stm.annotations.State; ./mvnw quarkus:add-extension .setURI(url) import org.jboss.stm.annotations.WriteLock; -Dextensions="kogito" .call()) { return tmpDir.toString(); public class FlightServiceImpl } implements FlightService { @State Apache Tika private int numberOfBookings;

Quarkus integrates with Apache Tika to detect and extract When running in native mode, make sure to congure SSL @ReadLock metadata/text from different le types: access correctly quarkus.ssl.native=true (Native and SSL). public int getNumberOfBookings() { return numberOfBookings; ./mvnw quarkus:add-extension Web Resources } -Dextensions="quarkus-tika" You can serve web resources with Quarkus. You need to place web @WriteLock resources at src/main/resources/META-INF/resources and then they public void makeBooking(String details) { are accessible (ie http://localhost:8080/index.html) numberOfBookings += 1; @Inject } io.quarkus.tika.TikaParser parser; By default static resources as served under the root context. You } can change this by using quarkus.http.root-path property. @POST @Path("/text") Transactional Memory @Consumes({ "text/plain", "application/pdf", Any member is saved/restored automatically ( @State is not "application/vnd.oasis.opendocument.text" }) mandatory). You can use @NotState to avoid behaviour. Quarkus integrates with the Software Transactional Memory (STM) @Produces(MediaType.TEXT_PLAIN) implementation provided by the Narayana project. Transaction boundaries public String extractText(InputStream stream) { return parser.parse(stream).getText(); Declarative } ./mvnw quarkus:add-extension -Dextensions="narayana-stm" @NestedTopLevel : Denes that the container will create a new top-level transaction for each method invocation. You can congure Apache Tika in application.properties le by @Nested : Denes that the container will create a new top-level using next properties prexed with quarkus : Transactional objects must be interfaces and annotated with org.jboss.stm.annotations.Transactional . or nested transaction for each method invocation. Parameter Default Description Programmatically @Transactional Path to the Tika @NestedTopLevel tika.tika-config- AtomicAction aa = new AtomicAction(); tika-config.xml conguration public interface FlightService { path resource. int getNumberOfBookings(); aa.begin(); void makeBooking(String details); { } CSV of the try { abbreviated or full flightService.makeBooking("BA123 ..."); quarkus.tika.parsers parser class to be taxiService.makeBooking("East Coast Taxis ..."); The pessimistic strategy is the default one, you can change to loaded by the optimistic by using @Optimistic . extension. aa.commit(); } catch (Exception e) { Then you need to create the object inside org.jboss.stm.Container . aa.abort(); The document may } tika.append-embedded- have other embedded Container container = new Container<>(); } true content documents. Set if FlightServiceImpl instance = new FlightServiceImpl(); autmatically append. FlightService flightServiceProxy = container.create(instanc e); Quartz JGit Quarkus integrates with Quartz to schedule periodic clustered The implementation of the service sets the locking and what needs tasks. Quarkus integrates with JGit to integrate with Git repositories: to be saved/restored:

./mvnw quarkus:add-extension ./mvnw quarkus:add-extension -Dextensions="quartz" -Dextensions="quarkus-jgit"

And then you can start using JGit: instance-name @ApplicationScoped public class TaskBean { The name of the Quartz instance. (default: QuarkusQuartzScheduler ) @Transactional Simple Include @Scheduled(every = "10s") thread-count void schedule() { The size of scheduler thread pool. (default: 25 ) Task task = new Task(); {#include foo limit=10 /} task.persist(); thread-priority } Thread priority of worker threads in the pool. (default: 5 ) }

force-start To render the template: The scheduler will be started even if no scheduled business To congure in clustered mode vida DataSource: methods are found. public class Item { quarkus.datasource.url=jdbc:postgresql://localhost/quarkus_ start-mode public String name; test public BigDecimal price; Scheduler can be started in different modes: normal , forced or quarkus.datasource.driver=org.postgresql.Driver } halted . (default: normal ) # ... @Inject quarkus.quartz.clustered=true Qute io.quarkus.qute.Template item; quarkus.quartz.store-type=db Qute is a templating engine designed specically to meet the @GET Quarkus needs. Templates should be placed by default at @Path("{id}") src/main/resources/templates aand subdirectories. @Produces(MediaType.TEXT_HTML) You need to dene the datasource used by clustered mode public TemplateInstance get(@PathParam("id") Integer id) { and also import the database tables following the Quartz return item.data("item", service.findItem(id)); schema. ./mvnw quarkus:add-extension -Dextensions="quarkus-resteasy-qute" }

Quartz can be congured usinf the following properties with @TemplateExtension quarkus.quartz prex: static BigDecimal discountedPrice(Item item) { Templates can be dened in any format, in case of HTML: return item.price.multiply(new BigDecimal("0.9")); clustered item.html } Enable cluster mode or not. {@org.acme.Item item} @TemplateExtension(namespace = "str") store-type public static class StringExtensions { The type of store to use. Possible values: ram , db (default: ram ) static String reverse(String val) { return new StringBuilder(val).reverse().toString(); datasource } The name of the datasource to use. {item.name} } table-prefix

{item.name ?: 'Unknown'}

The prex for quartz job store tables. (default: QRTZ_ ) If @ResourcePath is not used in Template then the name of the eld is

{str:reverse('Hello')}

used as le name. In this case the le should be
Price: {item.price}
src/main/resources/templates/item.{} . Extension of the le is not trigger-listeners..class {#if item.price > 100} required to be set. Class name for the trigger.
Discounted Price: {item.discountedPrice}
{/if} discountedPrice is not a eld of the POJO but a method call. trigger-listeners..property-name Method denition must be annotated with @TemplateExtension and The properties passed to the class. be static method. First parameter is used to match the base object ( Item ). @TemplateExtension can be used at class level: job-listeners..class Class name for the job. First line is not mandatory but helps on doing property checks at @TemplateExtension compilation time. public class MyExtensions { job-listeners..property-name static BigDecimal discountedPrice(Item item) { Including templates passing parameters: return item.price.multiply(new BigDecimal("0.9")); The properties passed to the class. } } plugins..class Class name for the plugin. Methods with multiple parameters are supported too: plugins..property-name The properties passed to the class Message Bundling Value resolvers are invoked when evaluating expressions. {item.discountedPrice(2)}

@io.quarkus.qute.i18n.MessageBundle void configureEngine(@Observes EngineBuilder builder) { public interface AppMessages { builder.addValueResolver(ValueResolver.builder() static BigDecimal discountedPrice(Item item, int scale) { @io.quarkus.qute.i18n.Message("Hello {name}!") .appliesTo(ctx -> ctx.getBase() instanceof Long && ct return item.price.multiply(scale); String hello_name(String name); x.getName().equals("tenTimes")) } } .resolveSync(ctx -> (Long) ctx.getBase() * 10) .build()); }

Qute for syntax supports any instance of Iterable , Map.EntrySet , There are 3 methods to inject the message: Stream or Integer . MessageBundles.get(AppMessages.class).hello_name("Lucie"); Content Filters {#for i in total} Content lters can be used to modify the template contents before {i}: parsing. {/for} or

void configureEngine(@Observes EngineBuilder builder) { @Inject AppMessages app; builder.addParserHook(new ParserHook() { The next map methods are supported: @Override app.hello_name("Lucie"); public void beforeParsing(ParserHelper parserHelper) {#for key in map.keySet} { {#for value in map.values} parserHelper.addContentFilter(contents -> content {map.size} or s.replace("${", "$\\{")); {#if map.isEmpty} } {map['foo'] });

{msg:hello_name('Lucie')}

}

The next list methods are supported: Localization Reactive and Async {list[0]} There are two ways to set localized message: CompletionStage async = report.renderAsync(); Multi publisher = report.createMulti(); @io.quarkus.qute.i18n.Localized("de")

The next number methods are supported: public interface GermanAppMessages { Uni content = io.smallrye.mutiny.Uni.createFrom()

.completionStage(() -> report.r {#if counter.mod(5) == 0} @Override enderAsync()); @io.quarkus.qute.i18n.Message("Hallo {name}!") String hello_name(String name); } Switch/When Qute Mail Integration

{#switch person.name} or @Inject {#case 'John'} MailTemplate hello; Hey John! msg_de.properties {#case 'Mary'} CompletionStage c = hello.to("[email protected]") Hey Mary! hello_name=Hallo {name}! .subject("Hello from Qute template") {/switch} .data("name", "John") .send(); You can render programmaticaly the templates too:

{#when items.size} {#is 1} (1) // file located at src/main/resources/templates/reports/v1/ INFO: Template located at src/main/resources/templates/hello. There is exactly one item! report_01.{} [html|txt] . {#is > 10} (2) @ResourcePath("reports/v1/report_01") There are more than 10 items! Template report; Sentry {#else} (3) String output = report There are 2 -10 items! Quarkus integrates with Sentry for logging errors into an error .data("samples", service.get()) {/when} monitoring system. .render();

./mvnw quarkus:add-extension Following operators can be used either in when and switch : not, ne, -Dextensions="quarkus-logging-sentry" != , gt, > , ge, >= , lt, < , le, <= , in , ni, !in . Value Resolvers And the conguration to send all errors occuring in the package quarkus.banner.enabled @ApplicationScoped org.example to Sentrty with DSN https://[email protected]/1234 : public class CachedBean { Enables banner. (default : true )

quarkus.log.sentry=true @CacheResult(cacheName = "foo") OptaPlanner quarkus.log.sentry.dsn=https://[email protected]/1234 public Object load(Object key) {} quarkus.log.sentry.level=ERROR Quarkus integrates with OptaPlanner. quarkus.log.sentry.in-app-packages=org.example @CacheInvalidate(cacheName = "foo") public void invalidate(Object key) {} ./mvnw quarkus:add-extension

-Dextensions="quarkus-optaplanner, quarkus-optaplanner-ja @CacheInvalidateAll(cacheName = "foo") Full list of conguration properties having quarkus.log as prex: ckson" public void invalidateAll() {} sentry.enable } Enable the Sentry logging extension (default: false) @PlanningSolution sentry.dsn You can disable the caching system by setting public class TimeTable { Where to send events. quarkus.cache.enabled property to false . }

This extension uses Caffeine as its underlying caching provider. @Inject sentry.level private SolverManager solverManager; Log level (default: WARN ) Each cache can be congured individually: UUID problemId = UUID.randomUUID(); sentry.server-name quarkus.cache.caffeine."foo".initial-capacity=10 SolverJob solverJob = solverManager.solve Sets the server name that will be sent with each event. quarkus.cache.caffeine."foo".maximum-size=20 (problemId, problem); quarkus.cache.caffeine."foo".expire-after-write TimeTable solution = solverJob.getFinalBestSolution(); sentry.in-app-packages quarkus.cache.caffeine."bar".maximum-size=1000 Congure which package prexes your application uses. Possible conguration options prexed with quarkus.optaplanner : JSch Full list of conguration properties having quarkus.cache.caffeine. [cache-name] as prex: solver-config-xml Quarkus integrates with Jsch for SSH communication. A classpath resource to read the solver conguration XML. Not initial-capacity mandatory. Minimum total size for the internal data structures. ./mvnw quarkus:add-extension solver.environment-mode -Dextensions="quarkus-jsch" maximum-size Enable runtime assertions to detect common bugs in your Maximum number of entries the cache may contain. implementation during development. Possible values: FAST_ASSERT , FULL_ASSERT , NON_INTRUSIVE_FULL_ASSERT , JSch jsch = new JSch(); expire-after-write NON_REPRODUCIBLE , REPRODUCIBLE . (default: REPRODUCIBLE ) Session session = jsch.getSession(null, host, port); Species that each entry should be automatically removed from session.setConfig("StrictHostKeyChecking", "no"); the cache once a xed duration has elapsed after the entry’s solver.move-thread-count session.connect(); creation, or last write. Enable multithreaded solving for a single problem. Possible values: MOVE_THREAD_COUNT_NONE , MOVE_THREAD_COUNT_AUTO , a number expire-after-access or formula based on the available processors. (default: Cache Species that each entry should be automatically removed from MOVE_THREAD_COUNT_NONE ) the cache once a xed duration has elapsed after the entry’s Quarkus can cache method calls by using as key the tuple (method creation, or last write. solver.termination.spent-limit + arguments). How long the solver can run. (ie 5s ) You can multiple cache annotations on a single method. ./mvnw quarkus:add-extension solver.termination.unimproved-spent-limit -Dextensions="cache" How long the solver can run without nding a new best solution If you see a javax.enterprise.context.ContextNotActiveException , after nding a new best solution. (ie 2h ) you need to add the quarkus-smallrye-context-propagation extension. solver.termination.best-score-limit @io.quarkus.cache.CacheResult(cacheName = "weather-cache") Terminates the solver when a specic or higher score has been public String getDailyForecast(LocalDate date, String city) Banner reached. (ie 0hard/-1000soft ) {} Banner is printed by default. It is not an extension but placed in the solver-manager.parallel-solver-count core. The number of solvers that run in parallel. (default: @CacheInvalidate removes the element represented by the quarkus.banner.path PARALLEL_SOLVER_COUNT_AUTO ) calculated cache key from cache. @CacheInvalidateAll removes all entries from the cache. @CacheKey to specically set the arguments Path is relative to root of the classpath. (default: b d k d f ll ) Context Propagation Keys whose value is a raw string. The keys that end up in the user To change how you can refer to webjars skipping the version part ./mvnw quarkus:add-extension conguration are the keys specied her with '/' replaced by '.' you can use WebJars locator extension. -Dextensions="quarkus-smallrye-context-propagation"

properties-value-keys ./mvnw quarkus:add-extension Keys whose value represents a properties-like le conttent. -Dextensions="webjars-locator" If using mutiny extension together you already get context propagation for ArC, RESTEasy and transactions. With fail-on-missing-key CompletionStage you need to: If the application will not start if any of the congured cong Then the JavaScript location is changed from sources cannot be located. (default: true ) /webjars/jquery/3.1.1/jquery.min.js to @Inject ThreadContext threadContext; /webjars/jquery/jquery.min.js in your HTML les. @Inject ManagedExecutor managedExecutor; trust-store threadContext.withContextCapture(..) TrustStore to be used containing the SSL certicate used by Amazon SES .thenApplyAsync(r -> {}, managedExecutor); Consul agent. mvn quarkus:add-extension trust-store-password -Dextensions="amazon-ses" If you are going to use security in a reactive environment you will Password of TrustStore to be used containing the SSL certicate likely need Smallrye Content Propagation to propagate the identity used by Consul agent. throughout the reactive callback. key-password @Inject Conguration from HasiCorp Consul Password to recover key from KeyStore for SSL client software.amazon.awssdk.services.ses.SesClient sesClient; authentication with Consul agent. @Inject You can read runtime conguration from HashiCorp Consul. software.amazon.awssdk.services.ses.SesAsyncClient sesClien agent.host-port t; ./mvnw quarkus:add-extension Consul agent host. (default: localhost:8500 ) -Dextensions="consul-config" agent.use-https quarkus.ses.endpoint-override=http://localhost:8012 Use HTTPS when communicating with the agent. (default: false ) You need to congure Consul: quarkus.ses.aws.region=us-east-1 quarkus.ses.aws.credentials.type=static agent.token quarkus.ses.aws.credentials.static-provider.access-key-id=t quarkus.consul-config.enabled=true Consul token to be provided when authentication is enabled. est-key quarkus.consul-config.agent.host-port=localhost:8500 quarkus.ses.aws.credentials.static-provider.secret-access-k quarkus.consul-config.properties-value-keys=config/consul-t agent.key-store ey=test-secret est KeyStore (classpath or lesystem) to be used containing the SSL certicate used by Consul agent.

You need to set a HTTP client either URL Connection : agent.key-store-password @ConfigProperty(name = "greeting.message") Password of KeyStore. String message; software.amazon.awssdk agent.trust-certs url-connection-client In Consul: To trust all certicates or not.

agent.connection-timeout "Key": "config/consul-test", "Value": "greeting.message=Hello from Consul" Connection timeout. (default: 10S ) or Apache HTTP:

agent.read-timeout Possible conguration parameters, prexed with quarkus.consul- Reading timeout. (default: 60S ) software.amazon.awssdk config : apache-client Amazon Alexa enabled The application will attempt to look up the conguration from You can use Amazon Alexa by adding the extension: Consul. (default: false ) quarkus.ses.sync-client.type=apache ./mvnw quarkus:add-extension prefix -Dextensions="quarkus-amazon-alexa" Common prex that all keys share when looking up the keys from Or async: Consul. The prex is not included in the keys of the user conguration WebJar Locator raw-value-keys Spring DI Spring Boot Conguration software.amazon.awssdk netty-nio-client Quarkus provides a compatibility layer for Spring dependency Quarkus provides a compatibility layer for Spring Boot injection. ConfigurationProperties .

./mvnw quarkus:add-extension ./mvnw quarkus:add-extension Conguration properties are the same as Amazon DynamoDB but -Dextensions="quarkus-spring-di" -Dextensions="quarkus-spring-boot-properties" changing the prex from dynamodb to ses .

Jbang Some examples of what you can do. Notice that annotations are @ConfigurationProperties("example") the Spring original ones. public final class ClassProperties { Creating an initial script:

@Configuration private String value; public class AppConfiguration { jbang scripting/quarkusapp.java private AnotherClass anotherClass;

@Bean(name = "capitalizeFunction") // getters/setters public StringFunction capitalizer() { } Adding Quarkus dependencies in script: return String::toUpperCase; } //DEPS io.quarkus:quarkus-resteasy:{quarkus-version} } example.value=class-value example.anotherClass.value=true Put some Quarkus CLI code: Or as a component:

@Component("noopFunction") @Path("/hello") public class NoOpSingleStringFunction Spring Cloud Cong Client @ApplicationScoped implements StringFunction { public class quarkusapp { } Quarkus integrates Spring Cloud Cong Client and MicroProle @GET Cong spec. public String sayHello() { return "hello"; ./mvnw quarkus:add-extension } Also as a service and injection properties from -Dextensions="quarkus-spring-cloud-config-client" public static void main(String[] args) { application.properties . Quarkus.run(args); } @Service } public class MessageProducer { You need to congure the extension:

@Value("${greeting.message}") quarkus.spring-cloud-config.uri=http://localhost:8089 To run the script: String message; quarkus.spring-cloud-config.username=user quarkus.spring-cloud-config.password=pass } quarkus.spring-cloud-config.enabled=true jbang quarkusapp.java

And you can inject using Autowired or constructor in a component A Maven goal is provided to scaffold a project: @ConfigProperty(name = "greeting.message") and in a JAX-RS resource too. String greeting; mvn io.quarkus:quarkus-maven-plugin::create-jbang @Component public class GreeterBean { Prex is quarkus.spring-cloud-config .

private final MessageProducer messageProducer; uri

@Autowired @Qualifier("noopFunction") Base URI where the Spring Cloud Cong Server is available. StringFunction noopStringFunction; (default: localhost:8888 )

public GreeterBean(MessageProducer messageProducer) { username this.messageProducer = messageProducer; Username to be used if the Cong Server has BASIC Auth } enabled. } password Password to be used if the Cong Server has BASIC Auth enabled. enabled The next return types are supported: @Query("select m from Movie m where m.rating = ?1") org.springframework.http.ResponseEntity and java.util.Map . Enables read conguration from Spring Cloud Cong Server. Iterator findByRating(String rating); (default: false ) The next parameter types are supported: An Exception argument @Modifying and ServletRequest / HttpServletRequest (adding quarkus-undertow fail-fast dependency). @Query("delete from Movie where rating = :rating") True to not start application if cannot access to the server. void deleteByRating(@Param("rating") String rating); (default: false ) Spring Data JPA @Query(value = "SELECT COUNT(*), publicationYear FROM Book connection-timeout GROUP BY publicationYear") While users are encouraged to use Hibernate ORM with Panache List findAllByPublicationYear2(); The amount of time to wait when initially establishing a for Relational Database access, Quarkus provides a compatibility connection before giving up and timing out. (default: 10S ) layer for Spring Data JPA repositories. interface BookCountByYear { int getPublicationYear(); read-timeout ./mvnw quarkus:add-extension The amount of time to wait for a read on a socket before an -Dextensions="quarkus-spring-data-jpa" Long getCount(); exception is thrown. (default: 60S ) } label INFO: Of course you still need to add the JDBC driver, and congure The label to be used to pull remote conguration properties. it in application.properties . What is currently unsupported:

Methods of Spring Web public interface FruitRepository org.springframework.data.repository.query.QueryByExampleExec extends CrudRepository { utor Quarkus provides a compatibility layer for Spring Web. List findByColor(String color); } QueryDSL support ./mvnw quarkus:add-extension -Dextensions="quarkus-spring-web" Customizing the base repository And then you can inject it either as shown in Spring DI or in Spring Web. java.util.concurrent.Future as return type Specically supports the REST related features. Notice that Interfaces supported: Native and named queries when using @Query infrastructure things like BeanPostProcessor will not be executed.

org.springframework.data.repository.Repository Spring Data Rest @RestController @RequestMapping("/greeting") org.springframework.data.repository.CrudRepository While users are encouraged to use REST Data with Panache for the public class GreetingController { REST data access endpoints generation, Quarkus provides a org.springframework.data.repository.PagingAndSortingReposito compatibility layer for Spring Data REST in the form of the spring- private final GreetingBean greetingBean; ry data-rest extension.

public GreetingController(GreetingBean greetingBean) { org.springframework.data.jpa.repository.JpaRepository . ./mvnw quarkus:add-extension this.greetingBean = greetingBean; INFO: Generated repositories are automatically annotated with -Dextensions="spring-data-rest" } @Transactional .

@GetMapping("/{name}") Repository fragments is also supported: public Greeting hello(@PathVariable(name = "name") import java.util.Optional; String name) { import org.springframework.data.repository.CrudRepository; return new Greeting(greetingBean.greet(name)); public interface PersonRepository import org.springframework.data.rest.core.annotation.Reposi } extends JpaRepository, PersonFragment { toryRestResource; } void makeNameUpperCase(Person person); import org.springframework.data.rest.core.annotation.RestRe } source;

Supported annotations are: RestController , RequestMapping , @RepositoryRestResource(exported = false, path = "/my-fruit GetMapping , PostMapping , PutMapping , DeleteMapping , PatchMapping , s") RequestParam , RequestHeader , MatrixVariable , PathVariable , User dened queries: public interface FruitsRepository extends CrudRepository { RestControllerAdvice . @RestResource(exported = true) Optional findById(Long id); If you scaffold the project with spring-web extension, then @RestResource(exported = true) Spring Web annotations are sed in the generated project. Iterable findAll(); mvn io.quarkus:quarkus-maven-plugin:1.13.0.Final:create … - } Dextensions="spring-web" . The spring-data-jpa extension will generate an implementation for Checks if the current logged in user is the same as the @org.springframework.scheduling.annotation.Scheduled(cron= this repository. Then the spring-data-rest extension will generate a username method parameter: "*/5 * * * * ?") REST CRUD resource for it. void cronJob() { @PreAuthorize("#person.name == authentication.principal.use The following interfaces are supported: System.out.println("Cron expression hardcoded"); rname") } public void doSomethingElse(Person person){} org.springframework.data.repository.CrudRepository @Scheduled(fixedRate = 1000) org.springframework.data.repository.PagingAndSortingReposito @Scheduled(cron = "{cron.expr}") ry Checks if calling a method if user can access:

org.springframework.data.jpa.repository.JpaRepository @PreAuthorize("@personChecker.check(#person, authenticatio n.principal.username)") Spring Security public void doSomething(Person person){}

Quarkus provides a compatibility layer for Spring Security. @Component public class PersonChecker { ./mvnw quarkus:add-extension public boolean check(Person person, String username) { -Dextensions="spring-security" return person.getName().equals(username); } } You need to choose a security extension to dene user, roles, … such as openid-connect , oauth2 , properties-file or security-jdbc as seen at RBAC. Combining expressions:

Then you can use Spring Security annotations to protect the @PreAuthorize("hasAnyRole('user', 'admin') AND #user == pri methods: ncipal.username") public void allowedForUser(String user) {} @Secured("admin") @GetMapping public String hello() { return "hello"; Spring Cache } Quarkus provides a compatibility layer for Spring dependency injection. Quarkus provides support for some of the most used features of Spring Security’s @PreAuthorize annotation. ./mvnw quarkus:add-extension -Dextensions="spring-cache" Some examples: hasRole @org.springframework.cache.annotation.Cacheable("someCache" @PreAuthorize("hasRole('admin')") ) public Greeting greet(String name) {} @PreAuthorize("hasRole(@roles.USER)") where roles is a bean dened with @Component annotation and USER is a public eld of the class. Quarkus provides compatibility with the following Spring Cache hasAnyRole annotations:

@PreAuthorize("hasAnyRole(@roles.USER, 'view')") @Cacheable

Permit and Deny All @CachePut

@PreAuthorize("permitAll()") @CacheEvict

@PreAuthorize("denyAll()") Spring Schedule

Anonymous and Authenticated Quarkus provides a compatibility layer for Spring Scheduled annotation. @PreAuthorize("isAnonymous()")

@PreAuthorize("isAuthenticated()") ./mvnw quarkus:add-extension -Dextensions="spring-scheduled" Resources Authors : 1.13.0.Final

https://quarkus.io/guides/ @alexsotob Java Champion and Director of DevExp at Red Hat https://www.youtube.com/user/lordofthejars