Quarkus Cheat-Sheet: What Is Quarkus? Command Mode
Quarkus Cheat-Sheet: What Is Quarkus? Command Mode
Cheat-Sheet
There is no way to scaffold a project in Gradle but you only need to To compile to native, you need to set GRAALVM_HOME environment
do: variable and run the native pro le. @CommandLineArguments
String[] args;
prod : The default pro le when not running in development or YAML Con g
test mode
This class maps greeting.message property de ned in
application.properties . YAML con guration is also supported. The con guration le is
You can create custom pro le names by enabling the pro le either called application.yaml and you need to register a dependency to
setting quarkus.profile system property or QUARKUS_PROFILE enable its support:
You can inject this class by using CDI @Inject GreetingConfiguration
environment variable. greeting; .
pom.xml
greeting.message = hello
Is equivalent to:
greeting.hidden.recipients=Jane,John
Special properties are set in prod mode:
quarkus.application.version and quarkus.application.name to get quarkus.http.cors=true
them available at runtime. quarkus.http.cors.methods=GET,PUT,POST
Bean Validation is also supported so properties are validated at
startup time, for example @Size(min = 20) public String message; .
@ConfigProperty(name = "quarkus.application.name")
String applicationName; Custom Loader
prefix attribute is not mandatory. If not provided, attribute
is determined by class name (ie GreeetingConfiguration is
translated to greeting or GreetingExtraConfiguration to You can implement your own ConfigSource to load con guration
@Con gProperties from different places than the default ones provided by Quarkus.
greeting-extra ). The su x of the class is always removed.
For example, database, custom XML, REST Endpoints, …
As an alternative to injecting multiple related con guration values, Naming strategy can be changed with property namingStrategy .
you can also use the @io.quarkus.arc.config.ConfigProperties You need to create a new class and implement ConfigSource
KEBAB_CASE (whatever.foo-bar) or VERBATIM (whatever.fooBar).
annotation to group properties. interface:
Then you need to register the Converter as Java service. Create a Quali ers
package com.acme.config;
le with the following content:
public class InMemoryConfig implements ConfigSource {
You can use quali ers to return different implementations of the
/META-INF/services/org.eclipse.microprofile.config.spi.Converter
same interface or to customize the con guration of the bean.
private Map<String, String> prop = new HashMap<>();
com.acme.config.CustomInstantConverter
public InMemoryConfig() { @Qualifier
// Init properties @Retention(RUNTIME)
} @Target({TYPE, METHOD, FIELD, PARAMETER})
Undertow Properties public @interface Quote {
@Override @Nonbinding String value();
public int getOrdinal() { Possible parameters with pre x quarkus.servlet : }
// The highest ordinal takes precedence
context-path @Produces
return 900;
} The context path to serve all Servlet context from. (default: / ) @Quote("")
Message message(InjectionPoint msg) {
@Override default-charset Message m = new Message();
m.setMsn(
public Map<String, String> getProperties() { The default charset to use for reading and writing requests.
msg.getAnnotated()
return prop; (default: UTF-8 )
} .getAnnotation(Quote.class)
.value()
@Override
Injection );
public String getValue(String propertyName) {
return prop.get(propertyName);
Quarkus is based on CDI 2.0 to implement injection of code. It is return m;
}
not fully supported and only a subset of the speci cation is }
implemented.
@Override @Inject
public String getName() { @ApplicationScoped @Quote("Aloha Beach")
return "MemoryConfigSource"; public class GreetingService { Message message;
}
} public String message(String message) {
return message.toUpperCase();
Quarkus breaks the CDI spec by allowing you to inject
}
quali ed beans without using @Inject annotation.
}
Then you need to register the ConfigSource as Java service. Create
a le with the following content: @Quote("Aloha Beach")
Message message;
/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource
Scope annotation is mandatory to make the bean discoverable.
com.acme.config.InMemoryConfig
@Inject
Quarkus breaks the CDI spec by skipping the @Produces
GreetingService greetingService;
annotation completely if the producer method is annotated
Custom Converters with a scope annotation, a stereotype or a quali er.
You can implement your own conversion types from String. Quarkus is designed with Substrate VM in mind. For this @Quote("")
Implement org.eclipse.microprofile.config.spi.Converter reason, we encourage you to use package-private scope Message message(InjectionPoint msg) {
interface: instead of private. }
@Priority(DEFAULT_QUARKUS_CONVERTER_PRIORITY + 100) Produces @Quote("Aloha Beach")
public class CustomInstantConverter Message message;
implements Converter<Instant> { You can also create a factory of an object by using
@javax.enterprise.inject.Produces annotation.
@Override
Alternatives
public Instant convert(String value) { @Produces
if ("now".equals(value.trim())) { @ApplicationScoped It is also possible to select alternatives for an application using
return Instant.now(); Message message() { application.properties .
} Message m = new Message();
return Instant.parse(value); m.setMsn("Hello");
quarkus.arc.selected-alternatives=org.acme.Foo,org.acme.*,B
} return m;
ar
} }
@Inject
Message msg; Beans by Quarkus Pro le
@Priority annotation is used to override the default
InstantConverter .
Using @io.quarkus.arc.profile.IfBuildProfile and By default the class is in write mode (so no concurrent calls
@ApplicationScoped
@io.quarkus.arc.profile.UnlessBuildProfile annotations, you can allowed) except when lock type is READ where the method can be public class CustomObjectMapperConfig {
conditionally enable a bean. called concurrently if no write operation in process.
@Singleton
@Produces
@Dependent JSON Marshalling/Unmarshalling public ObjectMapper objectMapper() {
public class TracerConfiguration { ObjectMapper objectMapper = new ObjectMapper();
@Produces To work with JSON-B you need to add a dependency: // perform configuration
@IfBuildProfile("prod") return objectMapper;
public Tracer realTracer(Reporter reporter, Configurati ./mvnw quarkus:add-extension }
on configuration) { -Dextensions="io.quarkus:quarkus-resteasy-jsonb" }
return new RealTracer(reporter, configuration);
}
@Produces
@DefaultBean Any POJO is marshaled/unmarshalled automatically.
Default media type in Quarkus RestEasy is JSON.
public Tracer noopTracer() {
return new NoopTracer(); public class Sauce {
} private String name; XML Marshalling/Unmarshalling
} private long scovilleHeatUnits;
To work with JAX-B you need to add a dependency:
// getter/setters
}
Using @io.quarkus.arc.profile.IfBuildProperty annotation, you can ./mvnw quarkus:add-extension
conditionally enable a bean. @io.quarkus.arc.DefaultBean sets the -Dextensions="quarkus-resteasy-jaxb"
default bean.
JSON equivalent:
@Dependent
Then annotated POJOs are converted to XML.
public class TracerConfiguration { {
@Produces "name":"Blair's Ultra Death",
@IfBuildProperty(name = "some.tracer.enabled", stringVa "scovilleHeatUnits": 1100000 @XmlRootElement
lue = "true") } public class Message {
public Tracer realTracer(Reporter reporter, Configurati }
on configuration) {}
@GET
In a POST endpoint example: @Produces(MediaType.APPLICATION_XML)
@Produces
@DefaultBean public Message hello() {
public Tracer noopTracer() {} @POST return message;
} @Consumes(MediaType.APPLICATION_JSON) }
public Response create(Sauce sauce) {
// Create Sauce
return Response.created(URI.create(sauce.getId()))
Properties set at runtime have absolutely no effect on the .build(); JAXP
bean resolution using @IfBuildProperty . }
To work with JAX-P you need to add a dependency:
Container-managed Concurrency
./mvnw quarkus:add-extension
To work with Jackson you need to add:
Quarkus provides @io.quarkus.arc.Lock and a built-in interceptor for -Dextensions="jaxp"
concurrency control.
./mvnw quarkus:add-extension
-Dextensions="quarkus-resteasy-jackson"
@Lock
final DocumentBuilder dBuilder = DocumentBuilderFactory.new
@ApplicationScoped
Instance().newDocumentBuilder();
class SharedService {
If you don’t want to use the default ObjectMapper you can customize final Document doc = dBuilder.parse(in);
it by: return doc.getDocumentElement().getTextContent();
void addAmount(BigDecimal amout) {
}
@Lock(value = Lock.Type.READ, time = 1, unit = TimeUni Validator
t.SECONDS)
BigDecimal getAmount() {
Quarkus uses Hibernate Validator to validate input/output of REST
}
services and business services using Bean validation spec.
}
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-hibernate-validator"
Annotate POJO objects with validator annotations such as: You can con gure how Quarkus logs:
@NotExpired
@NotNull , @Digits , @NotBlank , @Min , @Max , …
@JsonbDateFormat(value = "yyyy-MM-dd")
private LocalDate expired; quarkus.log.console.enable=true
public class Sauce { quarkus.log.console.level=DEBUG
quarkus.log.console.color=false
@NotBlank(message = "Name may not be blank") quarkus.log.category."com.lordofthejars".level=DEBUG
private String name;
Manual Validation
@Min(0)
You can call the validation process manually instead of relaying to
private long scovilleHeatUnits;
@Valid by injecting Validator class. Pre x is quarkus.log .
// getter/setters category."<category-name>".level
} @Inject
Validator validator; Minimum level category (default: INFO )
level
To validate an object use @Valid annotation: Default minimum level (default: INFO )
And use it:
public Response create(@Valid Sauce sauce) {} console.enabled
Set<ConstraintViolation<Sauce>> violations =
validator.validate(sauce); Console logging enabled (default: true )
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, Allow color rendering (default: true )
PARAMETER, TYPE_USE })
ValidationMessages_ca_ES.properties file.enable
@Retention(RUNTIME)
@Documented
pattern.message=No conforme al patro File logging enabled (default: false )
@Constraint(validatedBy = { NotExpiredValidator.class})
public @interface NotExpired { file.format
Format pattern to use for logging. Default value:
String message() default "Sauce must not be expired"; @Pattern(regexp = "A.*", message = "{pattern.message}") %d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n
Class<?>[] groups() default { }; private String name;
Class<? extends Payload>[] payload() default { };
file.level
} Minimum log level (default: ALL )
Bean Validation can be con gured . The pre x is:
quarkus.hibernate-validator . file.path
json.pretty-print
org.acme.quickstart.WorldClockService/mp-rest/url=
Reactive import
http://worldclockapi.com org.jboss.resteasy.annotations.providers.multipart.Mult
Rest Client also integrates with reactive library named Mutiny. To
ipartForm;
start using it you need to add the quarkus-rest-client-mutiny .
After that, a methodon a client interface can return a @Path("/echo")
Injecting the client:
io.smallrye.mutiny.Uni instance. @RegisterRestClient
public interface MultipartService {
@RestClient
WorldClockService worldClockService; @GET @Path("/json/cet/now")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA)
Uni<WorldClock> getNow();
@Produces(MediaType.TEXT_PLAIN)
If invokation happens within JAX-RS, you can propagate headers String sendMultipartData(@MultipartForm
from incoming to outgoing by using next property. MultipartBody data);
Multipart
}
org.eclipse.microprofile.rest.client.propagateHeaders=
It is really easy to send multipart form-data with Rest Client.
Authorization,MyCustomHeader
<dependency> SSL
<groupId>org.jboss.resteasy</groupId>
You can still use the JAX-RS client without any problem <artifactId>resteasy-multipart-provider</artifactId> You can con gure Rest Client key stores.
ClientBuilder.newClient().target(…
) </dependency>
org.acme.quickstart.WorldClockService/mp-rest/trustStore=
Adding headers
classpath:/store.jks
You can customize the headers passed by implementing The model object: org.acme.quickstart.WorldClockService/mp-rest/trustStorePas
MicroPro le ClientHeadersFactory annotation: sword=
import java.io.InputStream; supersecret
@RegisterForReflection
public class BaggageHeadersFactory import javax.ws.rs.FormParam;
implements ClientHeadersFactory { import javax.ws.rs.core.MediaType; Possible con guration properties:
@Override
public MultivaluedMap<String, String> update( import %s/mp-rest/trustStore
MultivaluedMap<String, String> incomingHeaders, org.jboss.resteasy.annotations.providers.multipart.Part Trust store location de ned with classpath: or file: pre x.
MultivaluedMap<String, String> outgoingHeaders) {} Type;
} %s/mp-rest/trustStorePassword
public class MultipartBody {
Trust store password.
@FormParam("file")
And registering it in the client using RegisterClientHeaders
@PartType(MediaType.APPLICATION_OCTET_STREAM) %s/mp-rest/trustStoreType
annotation. private InputStream file; Trust store type (default: JKS )
@RegisterClientHeaders(BaggageHeadersFactory.class) @FormParam("fileName") %s/mp-rest/hostnameVerifier
@RegisterRestClient @PartType(MediaType.TEXT_PLAIN) Custom hostname veri er class name. To disable SSL veri cation
public interface WorldClockService {} private String name; you can use io.quarkus.restclient.NoopHostnameVerifier .
// getter/setters
%s/mp-rest/keyStore
}
Or statically set: Key store location de ned with classpath: or file: pre x.
@GET %s/mp-rest/keyStorePassword
@ClientHeaderParam(name="X-Log-Level", value="ERROR") And the Rest client interface:
Key store password.
Response getNow();
%s/mp-rest/keyStoreType
Key store type (default: JKS )
Asynchronous
Timeout
A method on client interface can return a CompletionStage class to
be executed asynchronously. You can de ne the timeout of the Rest Client:
@GET @Path("/json/cet/now")
@Produces(MediaType.APPLICATION_JSON)
CompletionStage<WorldClock> getNow();
org.acme.quickstart.WorldClockService/mp-rest/connectTimeou @QuarkusTest
You need to create a class implementing
t= @TestHTTPEndpoint(GreetingResource.class)
QuarkusTestResourceLifecycleManager interface and register it in the
1000 public class GreetingResourceTest {
test via @QuarkusTestResource annotation.
org.acme.quickstart.WorldClockService/mp-rest/readTimeout= @Test
2000 public void testHelloEndpoint() {
given() public class MyCustomTestResource
.when().get() implements QuarkusTestResourceLifecycleManager {
.then()
Instantiate client programmatically @Override
.statusCode(200)
.body(is("hello")); public Map<String, String> start() {
MovieReviewService reviewSvc = RestClientBuilder.newBuilder } // return system properties that
() } // should be set for the running test
.baseUri(apiUri) return Collections.emptyMap();
.build(WorldClockService.class); }
Root path is calculated automatically, not necessary to explicitly @Override
set. public void stop() {
Testing }
If you want any changes made to be rolled back at the end ofthe
Quarkus archetype adds test dependencies with JUnit 5 and Rest- test you can use the io.quarkus.test.TestTransaction annotation.
// optional
Assured library to test REST endpoints. @Override
QuarkusTestPro le
public void inject(Object testInstance) {
@QuarkusTest You can de ne for each Test class a different con guration options. }
public class GreetingResourceTest {
// optional
@Test This implies that the Quarkus service is restarted. @Override
public void testHelloEndpoint() { public int order() {
given() return 0;
.when().get("/hello") public class MyProfile implements io.quarkus.test.junit.Qua }
.then() rkusTestProfile { }
.statusCode(200)
.body(is("hello")); @Override
} public Map<String, String> getConfigOverrides() {
} return Map.of("greetings.message", "This is a Test" Returning new system properties implies running parallel
); tests in different JVMs.
}
And the usage:
Test port can be set in quarkus.http.test-port property. Timeout @Override
can be set in quarkus.http.test-timeout property. public String getConfigProfile() { @QuarkusTestResource(MyCustomTestResource.class)
return "my-test-profile"; public class MyTest {
You can also inject the URL where Quarkus is started: } }
}
@TestHTTPResource("index.html")
URL url; @QuarkusTest
@TestProfile(MyProfile.class) Testing Callbacks
public class MyTestClass {
You can enrich all your @QuarkusTest classes by implementing the
}
@TestHTTPEndpoint(GreetingResource.class) following callback interfaces:
@TestHTTPResource
URL url; io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback
Quarkus Test Resource
io.quarkus.test.junit.callback.QuarkusTestAfterConstructCall
You can execute some logic before the rst test run ( start ) and back
execute some logic at the end of the test suite ( stop ).
io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback
io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback
password
Mock is automatically injected and only valid for the de ned test Password to access.
class.
driver
Also spy is supported:
JDBC Driver class. It is not necessary to set if db-kind used.
@InjectSpy
credentials-provider
GreetingService greetingService;
Sets a custom credential provider name.
Mockito.verify(greetingService, Mockito.times(1)).greet();
credentials-provider-name
It is the @Named value of the credentials provider bean. Not
REST Client necessary if only one implementation.
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
The timeout before cancelling the acquisition of a new associations. Should quote all identi ers. (default: false )
connection. (default: 5 )
multitenant
metrics-enabled
jdbc.leak-detection-interval De nes 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
The interval at which we try to remove idle connections. (default: De nes the name of the data source to use in case of SCHEMA Enable/Disable 2nd level cache. (default: true )
5M )
approach.
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 developer.name = "Alex";
jdbc.transaction-isolation-level
The transaction isolation level. Possible values: UNDEFINED , NONE , Default precedence of null values in ORDER BY . Possible values: developer.persist();
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");
smallrye-metrics extension.
Default Schema.
database.charset
jdbc.additional-jdbc-properties.<extraProperty>
Remember to annotate methods with @Transactional annotation to
Unspeci ed properties to be passed to the JDBC driver when Charset.
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 con guration properties. Pre x 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 …
<columnName> which expands to from EntityName where count : String , [ Object… , Map<String, Object> , Parameters ] If entities are de ned in external JAR, you need to enable in these
<columnName>=? Number of entities meeting given query with parameters set. projects the Jandex plugin in project.
count
Number of entities You cannot mix pagination and range
You can implement your custom credentials provider (ie Azure
@ApplicationScoped @QuarkusTestResource(H2DatabaseTestResource.class)
public class DeveloperRepository public class FlywayTestResources {
KeyVault) to provide a username/password for the database
connection. Name information is not necessary if there is only one
implements PanacheRepository<Person> { }
custom credential provider.
public Person findByName(String name){
return find("name", name).firstResult();
} @ApplicationScoped
Transactions
} @Unremovable
@Named("my-credentials-provider")
The easiest way to de ne your transaction boundaries is to use the
public class CustomCredentialsProvider implements Credentia
@Transactional annotation.
lsProvider {
EntityManager You can inject EntityManager in your classes: @Inject
Transactions are mandatory in case of none idempotent
operations. Config config;
@Inject
EntityManager em; @Override
@Transactional
public Properties getCredentials(String credentials
em.persist(car); public void createDeveloper() {}
ProviderName) {
properties.put(CredentialsProvider.USER_PROPERTY_NA
Multiple datasources You can control the transaction scope: ME, "hibernate_orm_test");
properties.put(CredentialsProvider.PASSWORD
You can register more than one datasource. @Transactional(REQUIRED) (default): starts a transaction if none _PROPERTY_NAME, "hibernate_orm_test");
was started, stays with the existing one otherwise.
}
# default @Transactional(REQUIRES_NEW) : starts a transaction if none was
}
quarkus.datasource.db-kind=h2 started; if an existing one was started, suspends it and starts a
quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:def new one for the boundary of that method.
ault
.... @Transactional(MANDATORY) : fails if no transaction was started ; quarkus.datasource.credentials-provider=
# users datasource works within the existing transaction otherwise. custom
quarkus.datasource.users.db-kind=h2
quarkus.datasource.credentials-provider-name=
quarkus.datasource.users..jdbc.url=jdbc:h2:tcp://localhost/ @Transactional(SUPPORTS) : if a transaction was started, joins it ;
my-credentials-provider
mem:users otherwise works with no transaction.
@Transactional(NOT_SUPPORTED) :
if a transaction was started,
suspends it and works with no transaction for the boundary of Hibernate Multitenancy
Notice that after datasource you set the datasource name, in
the method; otherwise works with no transaction.
previous case users . Multitenancy is supported using Schema or Database approach.
@Transactional(NEVER) : if a transaction was started, raises an First you need to de ne how tenant is identi ed:
You can inject then AgroalDataSource with
exception; otherwise works with no transaction.
io.quarkus.agroal.DataSource .
@RequestScoped
You can con gure the default transaction timeout using
@Unremovable
@DataSource("users") quarkus.transaction-manager.default-transaction-timeout
public class CustomTenantResolver implements TenantResolver
AgroalDataSource dataSource1; con guration property. By default it is set to 60 seconds.
{
You can set a timeout property, in seconds, that applies to
@Inject
transactions created within the annotated method by using
Flushing RoutingContext context;
@TransactionConfiguration annotation.
You can force ush operation by calling .flush() or @Override
.persistAndFlush() to make it in a single call. @Transactional public String getDefaultTenantId() {
@TransactionConfiguration(timeout=40) return "base";
This ush is less e cient and you still need to commit public void createDeveloper() {} }
transaction.
@Override
Testing If you want more control over transactions you can inject public String resolveTenantId() {
UserTransaction and use a programmatic way. }
There is a Quarkus Test Resource that starts and stops H2 server
before and after test suite. }
@Inject UserTransaction transaction
Register dependency io.quarkus:quarkus-test-h2:test .
transaction.begin();
And annotate the test: transaction.commit(); Schema approach
transaction.rollback();
quarkus.hibernate-orm.database.generation=none public interface DeveloperResource extends PanacheRepositor @Entity
yResource<DeveloperRepository, Developer, Long> { @Table(name = "dev")
quarkus.hibernate-orm.multitenant=SCHEMA } public class Developer {
}
@Inject
Database approach Quarkus will generate automatically the implementation for you
CompletionStage<Stage.Session> stageSession;
following the next rules:
quarkus.hibernate-orm.database.generation=none @Inject
Default path is a hyphenated lowercase resource name
without a su x of resource or controller . Uni<Mutiny.Session> mutinySession;
quarkus.hibernate-orm.multitenant=DATABASE
get(@PathParam("id")) , list , add(Developer) , public Uni<Long> reactivePersist() {
# default tenant
update(@PathParam("id"), Developer) , delete(@PathParam("id")) return mutinySession
quarkus.datasource.base.db-kind=postgresql .flatMap(s -> s.persist(new Developer(1, "Alex"))
quarkus.datasource.base.username=quarkus_test You can customize these defaults by using @ResourceProperties and .flatMap(v -> session.flush())
... @MethodProperties annotations. ....
# Tenant 'mycompany'
quarkus.datasource.mycompany.db-kind=postgresql }
@ResourceProperties(hal = true, path = "my-developer")
quarkus.datasource.mycompany.username=mycompany
public interface DeveloperResource extends PanacheEntityRes
quarkus.flyway.mycompany.locations=classpath:database/mycom public CompletionStage<Developer> reactiveFind() {
ource<Developer, Long> {
pany return stageSession
@MethodProperties(path = "all")
... .thenCompose(session -> {
List<Developer> list();
@MethodProperties(exposed = false) session.find(Developer.class, 1);
void delete(Long id); });
If you need more dynamic approach implement: @ApplicationScoped } }
io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver
Hibernate Envers If hal is true , you need to send the Accept: application/hal+json In nispan
HTTP header to get the response.
Quarkus supports Hibernate Envers. Quarkus integrates with In nispan:
Hibernate Reactive
./mvnw quarkus:add-extension
./mvnw quarkus:add-extension
-Dextensions="hibernate-envers"
./mvnw quarkus:add-extension -Dextensions="infinispan-client"
-Dextensions="quarkus-hibernate-reactive, quarkus-resteas
y-mutiny, "
REST Data Panache Serialization uses a library called Protostream.
REST Data with Panache extension can generate the basic CRUD Annotation based
Also you need to add the reactive driver (ie quarkus-reactive-pg-
endpoints for your entities and repositories. client ).
@ProtoFactory
./mvnw quarkus:add-extension You can use: org.hibernate.reactive.mutiny.Mutiny or public Author(String name, String surname) {
-Dextensions="hibernate-orm-rest-data-panache" org.hibernate.reactive.stage.Stage . this.name = name;
this.surname = surname;
}
You also need to add the JDBC driver extension and a JSON
@ProtoField(number = 1)
Marshaller (ie resteasy-jackson ).
public String getName() {
return name;
Then you can de ne interfaces for de ning endpoints:
}
In case of Active Record pattern:
@ProtoField(number = 2)
public String getSurname() {
public interface DeveloperResource extends PanacheEntityRes
return surname;
ource<Developer, Long> {
}
}
hosts connect-retries
The Redis hosts. (default: localhost:6379 ) The maximum number of retries when attempting to connect Liquibase
(default: 0)
database Quarkus integrates with Liquibase to help you on database schema
The Redis database. schemas migrations.
CSV case-sensitive list of schemas managed (default: none)
timeout ./mvnw quarkus:add-extension
The maximum delay to wait before a blocking command to redis table -Dextensions="quarkus-liquibase"
server times out. (default: 10s ) The name of Flyway’s schema history table (default:
flyway_schema_history )
ssl Then place changelog les to the ( src/main/resources/db ) folder.
Enables or disables the SSL on connect. out-of-order
You can inject org.quarkus.liquibase.LiquibaseFactory to
Allows migrations to be run "out of order". programmatically execute the migration.
clinet-type
The Redis client type. Possible values: standalone , cluster , ignore-missing-migrations
sentinel (default: standalone ) Ignore missing migrations when reading the history table.
liquibase-schema-name
@Inject public class MyQuarkusAnalysisConfigurer
LiquibaseFactory liquibaseFactory; The liquibase tables schema name. implements ElasticsearchAnalysisConfigurer {
try (Liquibase liquibase = liquibaseFactory.createLiquibase liquibase-tablespace-name @Override
()) { 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()
quarkus.liquibase.users.schemas=USERS_TEST_SCHEMA
quarkus.liquibase as pre x is skipped in the next table.
quarkus.liquibase.inventory.schemas=INVENTORY_TEST_SCHEMA
change-log
# ... Use Hibernate Search in REST service:
The change log le. XML , YAML , JSON , SQL formats supported.
public class LibraryResource {
(default: db/changeLog.xml )
Hibernate Search
@Inject
change-log-parameters."<parameter-name>"
EntityManager em;
Liquibase changelog parameters. Quarkus integrates with Elasticsearch to provide a full-featured full-
text search using Hibernate Search API.
@Transactional
migrate-at-start public List<Author> searchAuthors(
The migrate at start ag. (default: false ) ./mvnw quarkus:add-extension @QueryParam("pattern") String pattern) {
-Dextensions="quarkus-hibernate-search-elasticsearch" return Search.getSearchSession(em)
validate-on-migrate .search(Author.class)
.predicate(f ->
The validate on update ag. (default: false )
You need to annotate your model with Hibernate Search API to pattern == null || pattern.isEmpty() ?
process-
provider.async- Should fetch proxy.preemptive-
Authenticate pre-
Credentials speci c parameters pre xed with false
credential-update- credentials async. basic-authentication-
emptively.
quarkus.dynamodb.aws.credentials :
enabled enabled
static-
AWS secret access
provider.secret-
key. max-connections 50 Max connections. In case of asynchronous client, the next parameters can be
access-key con gured pre xed by quarkus.dynamodb.async-client :
./mvnw quarkus:add-extension
Endpoint of the proxy @Inject
-Dextensions="quarkus-neo4j"
proxy.endpoint
server. S3Client s3Client;
proxy.enabled false Enables HTTP proxy. You need to set a HTTP client either URL Connection : @Inject
org.neo4j.driver.Driver driver;
tls-managers- authentication.password
provider.file- Key store type.
quarkus.s3.sync-client.type=apache Password. (default: neo4j )
store.type
authentication.disabled
tls-managers- And con gure it: Disable authentication. (default: false )
provider.file- Key store password.
store.password quarkus.s3.endpoint-override=http://localhost:8008 pool.metrics-enabled
quarkus.s3.interceptors=io.quarkus.it.amazon.s3.S3ModifyRes Enable metrics. (default: false )
ponse
SSL Provider ( jdk , quarkus.s3.aws.region=us-east-1 pool.log-leaked-sessions
ssl-provider openssl , openssl-
quarkus.s3.aws.credentials.type=static
refcnt ). Enable leaked sessions logging. (default:`false`)
quarkus.s3.aws.credentials.static-provider.access-key-id=te
st-key
pool.max-connection-pool-size
quarkus.s3.aws.credentials.static-provider.secret-access-ke
Sets the HTTP Max amount of connections. (default: 100 )
protocol HTTP_1_1 y=test-secret
protocol.
pool.max-connection-lifetime
Max number of You can inject asynchronous client too: Pooled connections older will be closed and removed from the
max-http2-streams
concurrent streams. pool. (default: 1H )
pool.connection-acquisition-timeout
./mvnw quarkus:add-extension Parameter Type Description
Timout for connection adquisation. (default: 1M) -Dextensions="quarkus-mongodb-client"
max-connection-idle- Idle time of a pooled
Duration
pool.idle-time-before-connection-test time connection.
Pooled connections idled in the pool for longer than this timeout
@Inject
will be tested before they are used. (default: -1 )
com.mongodb.client.MongoClient client; max-connection-life- Life time of pooled
Duration
time connection.
As Neo4j uses SSL communication by default, to create a native
@Inject
executable you need to compile with next options GraalVM options:
io.quarkus.mongodb.reactive.ReactiveMongoClient client;
Maximum wait time
-H:EnableURLProtocols=http,https --enable-all-security-services - wait-queue-timeout Duration
for new connection.
H:+JNI
INFO: Reactive client uses exposes Mutiny API.
And Quarkus Maven Plugin with next con guration:
Time period between
maintenance-
quarkus.mongodb.connection-string=mongodb://localhost:27018 Duration runs of maintenance
<artifactId>quarkus-maven-plugin</artifactId> frequency
quarkus.mongodb.write-concern.journal=false job.
<executions>
<execution>
<id>native-image</id> Time to wait before
Multi MongoDB support maintenance-initial-
<goals> Duration running the rst
delay
<goal>native-image</goal>
You can con gure multiple MongoDB clients using same approach maintenance job.
</goals>
as with DataSource . The syntax is quarkus.mongodb.<optional name>.
<configuration>
<property> :
<enableHttpUrlHandler>true Multiplied with max-
</enableHttpUrlHandler> pool-size gives max
quarkus.mongodb.users.connection-string = mongodb://mongo2: wait-queue-multiple Int
<enableHttpsUrlHandler>true numer of threads
</enableHttpsUrlHandler> 27017/userdb waiting.
<enableAllSecurityServices>true quarkus.mongodb.inventory.connection-string = mongodb://mon
</enableAllSecurityServices> go3:27017/invdb
<enableJni>true</enableJni> connection-timeout Duration
</configuration>
</execution> Inject the instance using
</executions> socket-timeout Duration
@io.quarkus.mongodb.runtime.MongoClientName annotation:
Minimum number of
min-pool-size Int
connections.
MongoDB Client
Q k i i hM DB
Parameter Type Description MongoDB con guration comes from MongoDB Client section.
PanacheQuery<Person> livingPersons =
Person.find("status", Status.Alive);
primary , @MongoEntity(collection="ThePerson") livingPersons.page(Page.ofSize(25));
primaryPreferred , public class Person extends PanacheMongoEntity {
read-preference secondary , Read preferences. public String name; // get the first page
secondaryPreferred , List<Person> firstPage = livingPersons.list();
nearest @BsonProperty("birth") // get the second page
public LocalDate birthDate; List<Person> secondPage = livingPersons.nextPage().list();
Max number of public Status status;
concurrent }
max-wait-queue-size Int
operations allowed to Range
wait.
PanacheQuery<Person> livingPersons = Person
Possible annotations in elds: @BsonId (for custom ID), .find("status", Status.Alive);
@BsonProperty and @BsonIgnore .
Ensures are writes List<Person> secondRange = livingPersons.range(25, 49).list
write-concern.safe boolean [true]
are ack. ();
@MongoEntity is optional.
1 Entity class.
You can also use the Panache framework to write persistence part
when using MongoDB. Testing
quarkus.cassandra.contact-points=127.0.0.1:9042
DAO pattern quarkus.cassandra.local-datacenter=datacenter1
MongoDB REST Data Panache quarkus.cassandra.keyspace=k1
@ApplicationScoped quarkus.cassandra.auth.username=john
public class PersonRepository MongoDB REST Data with Panache extension can generate the quarkus.cassandra.auth.password=s3cr3t
implements PanacheMongoRepository<Person> { basic CRUD endpoints for your entities and repositories.
}
./mvnw quarkus:add-extension You can con gure other Cassandra Java driver settings using
-Dextensions="mongodb-rest-data-panache" application.conf or application.json les. They need to be located
Jandex in the classpath of your application. Driver settings reference.
If entities are de ned in external JAR, you need to enable in these If MicroPro le Metrics extension is registered, the Cassandra
You also need to add the JDBC driver extension and a JSON
projects the Jandex plugin in project. extension can provide (if enabled) metrics about the session:
Marshaller (ie resteasy-jackson ).
<plugin> Then you can de ne interfaces for de ning endpoints: quarkus.cassandra.metrics.enabled=true
<groupId>org.jboss.jandex</groupId> quarkus.cassandra.metrics.session-enabled=connected-nodes,b
<artifactId>jandex-maven-plugin</artifactId> In case of Active Record pattern: ytes-sent
<version>1.0.3</version> quarkus.cassandra.metrics.node-enabled=pool.open-connection
<executions> public interface DeveloperResource extends PanacheMongoEnti s
<execution> tyResource<Developer, Long> {
<id>make-index</id> }
<goals>
Reactive
<goal>jandex</goal>
</goals> You can also use Mutiny to de ne a reactive DAO:
</execution> In case of Repository:
</executions>
@Dao
<dependencies> public interface DeveloperResource extends PanacheMongoRepo
public interface FruitDaoReactive {
<dependency> sitoryResource<DeveloperRepository, Developer, Long> {
<groupId>org.jboss</groupId> }
@Update
<artifactId>jandex</artifactId>
Uni<Void> update(Fruit fruit);
<version>2.1.1.Final</version>
</dependency>
</dependencies> Cassandra @Select
MutinyMappedReactiveResultSet<Fruit> findById(String stor
</plugin>
Quarkus integrates with Cassandra and DataStax Object Mapper. eId);
}
<dependency>
Panache includes an annotation processor that enhance your @Mapper
<groupId>com.datastax.oss.quarkus</groupId>
entities. If you disable annotation processors you might need to public interface FruitMapper {
<artifactId>cassandra-quarkus-client</artifactId>
create a marker le on Panache archives at META-INF/panache-
</dependency>
archive.marker manually. @DaoFactory
FruitDaoReactive fruitDaoReactive();
Reactive Panache }
Enities and DAOs are generated as you have been doing with
D t St Obj t M
Reactive Programming @GET Uni<Void> uniFromCompletable = Uni.createFrom()
@Produces(MediaType.TEXT_PLAIN) .converter(UniRxConvert
Quarkus implements MicroPro le Reactive spec and uses RXJava2 public Uni<String> hello() { ers.fromCompletable(), completable);
to provide reactive programming model. return Uni.createFrom().item(() -> "hello"); Uni<String> uniFromSingle = Uni.createFrom()
} .converter(UniRxConverters.
./mvnw quarkus:add-extension fromSingle(), single);
-Dextensions="quarkus-smallrye-reactive-streams-operator @GET Uni<String> uniFromObservable = Uni.createFrom()
s" @Produces(MediaType.TEXT_PLAIN) .converter(UniRxConverters.
public Multi<String> multi() { fromObservable(), observable);
return Multi.createFrom().items("hello", "world"); Uni<String> uniFromFlowable = Uni.createFrom()
} .converter(UniRxConverters.
Asynchronous HTTP endpoint is implemented by returning Java fromFlowable(), flowable);
CompletionStage . You can create this class either manually or using
...
MicroPro le Reactive Streams spec:
Mutiny
Multi<Void> multiFromCompletable = Multi.createFrom()
@GET .converter(MultiRxC
Quarkus integrates with Mutiny as reactive programming library:
@Path("/reactive") onverters.fromCompletable(), completable);
@Produces(MediaType.TEXT_PLAIN) Multi<String> multiFromObservable = Multi.createFrom()
./mvnw quarkus:add-extension
public CompletionStage<String> getHello() { .converter(MultiRxC
-Dextensions="mutiny"
return ReactiveStreams.of("h", "e", "l", "l", "o") onverters.fromObservable(), observable);
.map(String::toUpperCase) Multi<String> multiFromFlowable = Multi.createFrom()
.toList() .converter(MultiRxC
.run() onverters.fromFlowable(), flowable);
@ApplicationScoped
.thenApply(list -> list.toString()); ...
public static class ReactiveHello {
}
public Uni<String> greeting() {
return Uni.createFrom().item(() -> "hello") To RxJava2 :
Creating streams is also easy, you just need to return Publisher .emitOn(Infrastructure.getDefaultExecutor
object. ()); Completable completable = uni.convert().with(UniRxConverter
} s.toCompletable());
@GET Single<Optional<String>> single = uni.convert().with(UniRxC
@Path("/stream") public Multi<String> stream() { onverters.toSingle());
@Produces(MediaType.SERVER_SENT_EVENTS) return Multi.createFrom().items("hello", "world") Observable<String> observable = uni.convert().with(UniRxCon
public Publisher<String> publishers() { .emitOn(Infrastructure.getDefaultExecutor verters.toObservable());
return Flowable ()); Flowable<String> flowable = uni.convert().with(UniRxConvert
.interval(500, TimeUnit.MILLISECONDS) } ers.toFlowable());
.map(s -> atomicInteger.getAndIncrement()) } ...
.map(i -> Integer.toString(i));
} Completable completable = multi.convert().with(MultiRxConve
Converting from/to RxJava2 or Reactor APIs: rters.toCompletable());
Single<Optional<String>> single = multi.convert().with(Mult
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>mutiny-reactor</artifactId>
</dependency>
From Reactor :
Uni<String> uniFromMono = Uni.createFrom().converter(UniRea
or in Mutiny: @Inject @Stream(“out”)
ctorConverters.fromMono(), mono); Publisher<String> result;
Uni<String> uniFromFlux = Uni.createFrom().converter(UniRea @ApplicationScoped
ctorConverters.fromFlux(), flux); public class ProducerData { @GET
Multi<String> multiFromMono = Multi.createFrom().converter @Outgoing("my-in-memory") @Produces(SERVER_SENT_EVENTS)
(MultiReactorConverters.fromMono(), mono); public Multi<Integer> generate() { public Publisher<String> stream() {
Multi<String> multiFromFlux = Multi.createFrom().converter return Multi.createFrom().ticks().every(Duration.of return result;
(MultiReactorConverters.fromFlux(), flux); Seconds(5)) }
.onItem().apply(n -> random.nextInt(100));
}
}
To Reactor : Message → Business Logic
reactive.trust-certificate-pfx
Trust con guration in the PFX format.
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.
reactive.key-certificate-pem
database in a reactive way, instead of using JDBC.
Key/cert con guration in the PEM format.
@ApplicationScoped
./mvnw quarkus:add-extension
reactive.key-certificate-jks public class ArtemisConsumerManager {
-Dextensions="quarkus-reactive-mysql-client"
Key/cert con guration in the JKS format.
@Inject
ServerLocator serverLocator;
reactive.key-certificate-pfx
Database con guration is the same as shown in Persistence
Key/cert con guration in the PFX format. section, but URL is different as it is not a jdbc. private ClientSessionFactory connection;
reactive.thread-local @PostConstruct
quarkus.datasource.db-kind=mysql
Use one connection pool per thread. quarkus.datasource.reactive.url=mysql:///your_database public void init() throws Exception {
connection = serverLocator.createSessionFactory();
reactive.reconnect-attempts }
}
The number of reconnection attempts when a pooled connection Then you can inject io.vertx.mutiny.mysqlclient.MySQLPool class.
cannot be established on rst try. (default: 0 )
Reactive DB2 Client And con gure ServerLocator in application.properties :
reactive.reconnect-interval
The interval between reconnection attempts when a pooled You can use Reactive DB2 to execute queries to DB2 database in a
connection cannot be established on rst try. (default: PT1S ) reactive way, instead of using JDBC. quarkus.artemis.url=tcp://localhost:61616
reactive.idle-timeout
./mvnw quarkus:add-extension
The maximum time without data written to or read from a -Dextensions="quarkus-reactive-db2-client" You can con gure ActiveMQ Artemis in application.properties le
connection before it is removed from the pool. by using next properties pre xed with quarkus :
Reactive PostgreSQL Client Database con guration is the same as shown in Persistence
artemis.url
Connection URL.
section, but URL is different as it is not a jdbc.
You can use Reactive PostgreSQL to execute queries to PostreSQL
database in a reactive way, instead of using JDBC way. artemis.username
quarkus.datasource.db-kind=db2
quarkus.datasource.reactive.url=vertx-reactive:db2://localh
Username for authentication.
./mvnw quarkus:add-extension ost:50005/hreact
-Dextensions="quarkus-reactive-pg-client" artemis.password
Password for authentication.
Then you can inject i i db2 li 2 l class
Artemis JMS Example of Vert.X Web Client:
quarkus.sqs.sync-client.type=apache
If you want to use JMS with Artemis, you can do it by using its
@Inject
extension:
Vertx vertx;
You can go async by using Mutiny:
./mvnw quarkus:add-extension private WebClient client;
-Dextensions="quarkus-artemis-jms" @Inject
@PostConstruct software.amazon.awssdk.services.sqs.SqsAsyncClient sqs;
void initialize() {
this.client = WebClient.create(vertx, ...); Uni.createFrom()
And then you can inject javax.jms.ConnectionFactory :
} .completionStage(
sqs.sendMessage(m -> m.queueUrl(queueUrl).messageBo
@ApplicationScoped dy(message))
public class ArtemisConsumerManager { )
Amazon SQS Client .onItem()...
@Inject
ConnectionFactory connectionFactory; return Uni.createFrom()
./mvnw quarkus:add-extension
.completionStage(
private Connection connection; -Dextensions="amazon-sqs"
sqs.receiveMessage(m -> m.maxNumberOfMessages(10).q
ueueUrl(queueUrl))
@PostConstruct )
public void init() throws JMSException { Injecting the client: .onItem()
connection = connectionFactory.createConnection();
connection.start();
@Inject
}
software.amazon.awssdk.services.sqs.SqsClient sqs; And you need to add the asynchronous Netty client:
}
SendMessageResponse response = sqs.sendMessage(m -> m.queue
<dependency>
Url(queueUrl).messageBody(message));
<groupId>software.amazon.awssdk</groupId>
Con guration options are the same as Artemis core. List<Message> messages = sqs.receiveMessage(m -> m.maxNumbe
<artifactId>netty-nio-client</artifactId>
</dependency>
rOfMessages(10).queueUrl(queueUrl)).messages();
smallrye.jwt.claims.groups JWT groups claim is directly mapped to roles to be used in security quarkus.oidc.realm=quarkus
Default groups claim value. annotations. quarkus.oidc.auth-server-url=http://localhost:8180/auth
quarkus.oidc.resource=backend-service
smallrye.jwt.jwks.refresh-interval @RolesAllowed("Subscriber") quarkus.oidc.bearer-only=true
JWK cache refresh interval in minutes. (default: 60 ). quarkus.oidc.credentials.secret=secret
t k i ti
Expiration grace period in seconds. You can use quarkus.http.cors property to enable URL used to validate the token and gather the authentication
consuming form different domain. claims.
token.principal-claim
Name of the claim which contains a principal name. Multi-tenancy quarkus.oauth2.role-claim
The claim that is used in the endpoint response to load the roles
Multi-tenancy is supported by adding a sub-category to OIDC ((default: scope )
token.refresh-expired
con guration properties (ie quarkus.oidc.{tenent_id}.property ).
If property is enabled then a refresh token request is performed.
quarkus.oidc.auth-server-url=http://localhost:8180/auth/rea
Authenticating via HTTP
credentials.secret
lms/quarkus
The client secret HTTP basic auth is enabled by the quarkus.http.auth.basic=true
quarkus.oidc.client-id=multi-tenant-client
property.
quarkus.oidc.application-type=web-app
authentication.redirect-path
HTTP form auth is enabled by the
Relative path for calculating a redirect_uri query parameter. quarkus.oidc.tenant-b.auth-server-url=https://accounts.goog
quarkus.http.auth.form.enabled=true property.
le.com
authentication.restore-path-after-redirect quarkus.oidc.tenant-b.application-type=web-app Then you need to add elytron-security-properties-file or elytron-
quarkus.oidc.tenant-b.client-id=xxxx security-jdbc .
The original request URI used before the authentication will be
quarkus.oidc.tenant-b.credentials.secret=yyyy
restored after the user has been redirected back to the
application. (default: true )
quarkus.oidc.tenant-b.token.issuer=https://accounts.google.
Security with Properties File
com
quarkus.oidc.tenant-b.authentication.scopes=email,profile,o
authentication.scopes You can also protect endpoints and store identities (user, roles) in
penid
List of scopes. the le system.
logout.path
scott=Admin,admin,Tester,user
jdoe=NoRolesUser
The relative path of the logout endpoint at the application. Con guration options:
logout.post-logout-path quarkus.oauth2.enabled
IMPORTANT: If plain-text is set to false (or omitted) then
Relative path of the application endpoint where the user should Determine if the OAuth2 extension is enabled. (default: true ) passwords must be stored in the form MD5
be redirected to after logging out.
( username :`realm`:`password`).
quarkus.oauth2.client-id
tls.verification Elytron File Properties con guration properties. Pre x
The OAuth2 client id used to validate the token.
Sets the TLs veri cation. Possible values: REQUIRED , NONE . quarkus.security.users is skipped.
(default: REQUIRED ). quarkus.oauth2.client-secret
file.enabled
The OAuth2 client secret used to validate the token.
With Keycloak OIDC server The le realm is enabled. (default: false )
https://host:port/auth/realms/{realm} where {realm} has
quarkus.oauth2.introspection-url
to be replaced by the name of the Keycloak realm file auth-mechanism
The authentication mechanism. ( default: BASIC ) You can also protect endpoints and store identities in a database. principal-query.bcrypt-password-mapper.hash-encoding
A string referencing the password hash encoding ( BASE64 or HEX ).
file.realm-name mvn quarkus:add-extension (default: BASE64 )
The authentication realm name. (default: Quarkus ) -Dextensions="elytron-security-jdbc"
principal-query.bcrypt-password-mapper.salt-index
file.plain-text The index column containing the Bcrypt salt. (default: 0 )
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-encoding
file.users You need to con gure JDBC and Elytron JDBC Realm: A string referencing the salt encoding ( BASE64 or HEX ). (default:
Classpath resource of user/password. (default: BASE64 )
users.properties ) quarkus.datasource.url=
quarkus.datasource.driver=org.h2.Driver principal-query.bcrypt-password-mapper.iteration-count-index
quarkus.datasource.username=sa
file.roles The index column containing the Bcrypt iteration count. (default:
quarkus.datasource.password=sa
Classpath resource of user/role. (default: roles.properties ) 0)
quarkus.security.jdbc.enabled=true
Embedded Realm For multiple datasources you can use the datasource name in the
quarkus.security.jdbc.principal-query.sql=
properties:
SELECT u.password, u.role FROM test_user u WHERE u.user
You can embed user/password/role in the same
=?
application.properties :
quarkus.security.jdbc.principal-query quarkus.datasource.url=
.clear-password-mapper.enabled=true quarkus.security.jdbc.principal-query.sql=
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.permissions.url=
quarkus.security.users.embedded.users.scott=jb0ss quarkus.security.jdbc.principal-query quarkus.security.jdbc.principal-query.permissions.sql=
quarkus.security.users.embedded.roles.scott=admin,tester,us .attribute-mappings.0.index=2
er quarkus.security.jdbc.principal-query
quarkus.security.users.embedded.auth-mechanism=BASIC .attribute-mappings.0.to=groups
Security with JPA
You can also protect endpoints and store identities in a database
IMPORTANT: If plain-text is set to false (or omitted) then You need to set the index (1-based) of password and role. using JPA.
passwords must be stored in the form MD5
( username :`realm`:`password`). Elytron JDBC Realm con guration properties. Pre x
mvn quarkus:add-extension
quarkus.security.jdbc is skipped.
Pre x quarkus.security.users.embedded is skipped. -Dextensions="security-jpa"
auth-mechanism
algorithm
The authentication mechanism. (default: BASIC )
Determine which algorithm to use. Possible values: DIGEST_MD5 ,
Also you might require jdbc-postgresql , resteasy ,
DIGEST_SHA , DIGEST_SHA_256 , DIGEST_SHA_384 , DIGEST_SHA_512 ,
realm-name hibernate-orm-panache .
DIGEST_SHA_512_256 . (default: DIGEST_MD5 )
The authentication realm name. (default: Quarkus )
file.enabled
enabled
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
Th i d f l t i i dh h (d f lt )
The identi er ( 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
identity-mapping.search-base-dn
public class User extends PanacheEntity { quarkus.security.ldap.dir-context.url=ldaps://ldap.server.l
@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.<id>.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.<id>.to
@ManyToMany s."0".from=cn
The identi er whom the attribute is mapped to (default: gropus )
@Roles quarkus.security.ldap.identity-mapping.attribute-mapping
public List<Role> roles = new ArrayList<>(); s."0".to=groups
identity-mapping.attribute-mappings.<id>.filter
quarkus.security.ldap.identity-mapping.attribute-mapping
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.<id>.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<ExternalRolesUserEntity> users; Register dependency io.quarkus:quarkus-test-ldap:test.
@io.quarkus.security.RolesValue And annotate the test:
And con guring 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 con gure 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 con guration properties. Pre x 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-path.singer=
realm-name multi/singer
Dynamic credentials are also supported: Vault Provisioning Location of the le containing the Kubernetes JWT token
Running the following dynamic database con g in Vault: Vault extension offers façade classes to Vault provisioning renew-grace-period
functions: Renew grace period duration (default: 1H )
vault write database/config/mydb plugin_name=postgresql-database-
plugin …
..
@Inject secret-config-cache-period
You can con gure as: VaultSystemBackendEngine vaultSystemBackendEngine; Vault con g source cache period (default: 10M )
@Inject
quarkus.vault.credentials-provider secret-config-kv-path
VaultKubernetesAuthService vaultKubernetesAuthService;
.mydatabase.database-credentials-role=mydbrole
Vault path in kv store. List of paths is supported in CSV
String rules = "path \"transit/*\" {\n" +
quarkus.datasource.db-kind= log-confidentiality-level
" capabilities = [ \"create\", \"read\", \"updat
postgresql
e\" ]\n" + Used to hide con dential infos. low , medium , high (default:
quarkus.datasource.credentials-provider=
"}"; medium )
mydatabase
String policyName = "sys-test-policy";
quarkus.datasource.jdbc.url=
kv-secret-engine-version
jdbc:postgresql://localhost:5432/mydatabase
vaultSystemBackendEngine.createUpdatePolicy(policyName, rul Kv secret engine version (default: 1)
es);
kv-secret-engine-mount-path Kv secret engine path (default: secret )
Username and password are fetched from Vault vaultKubernetesAuthService
.createRole(roleName, new VaultKubernetesAuthRole() tls.skip-verify
Transit .setBoundServiceAccountNames(boundServiceAccountN
Allows to bypass certi cate validation on TLS communications
ames)
(default: false )
.setBoundServiceAccountNamespaces(boundServiceAcc
ountNamespaces)
tls.ca-cert
.setTokenPolicies(tokenPolicies));
Certi cate bundle used to validate TLS communications
tls.use-kubernetes-ca-cert
quarkus.sqs.sync-client.type=apache @Inject
TLS will be active (default: true ) IamClient client;
connect-timeout @Inject
You can go async by using Mutiny:
Tiemout to establish a connection (default: 5S ) IamAsyncClient async;
@Inject
read-timeout
software.amazon.awssdk.services.kms.KmsAsyncClient kms;
Request timeout (default: 1S ) quarkus.iam.endpoint-override=${iam.url}
Uni.createFrom().completionStage( quarkus.iam.aws.region=us-east-1
credentials-provider."credentials-provider".database-credentials- kms.encrypt(req -> req.keyId(keyArn).plaintext(SdkByte quarkus.iam.aws.credentials.type=static
role s.fromUtf8String(data)) quarkus.iam.aws.credentials.static-provider.access-key-id=t
Database credentials role )) est-key
quarkus.iam.aws.credentials.static-provider.secret-access-k
credentials-provider."credentials-provider".kv-path ey=test-secret
A path in vault kv store, where we will nd the kv-key And you need to add the asynchronous Netty client:
credentials-provider."credentials-provider".kv-key <dependency> Con guration properties are the same as Amazon DynamoDB but
Key name to search in vault path kv-path (default: password ) <groupId>software.amazon.awssdk</groupId> changing the pre x from dynamodb to iam .
<artifactId>netty-nio-client</artifactId>
mvn quarkus:add-extension
Con guration properties are the same as Amazon DynamoDB but
-Dextensions="amazon-kms"
changing the pre x from dynamodb to kms .
Amazon IAM
@Inject
KmsClient kms; mvn quarkus:add-extension
-Dextensions="quarkus-amazon-iam"
kms.encrypt(req -> req.keyId(keyArn).plaintext(
SdkBytes.fromUtf8String(data))).ciphertextBlob();
quarkus.kms.endpoint-override=http://localhost:8011 <dependency>
quarkus.kms.aws.region=us-east-1 <groupId>software.amazon.awssdk</groupId>
quarkus.kms.aws.credentials.type=static <artifactId>url-connection-client</artifactId>
quarkus.kms.aws.credentials.static-provider.access-key-id=t </dependency>
est-key
quarkus.kms.aws.credentials.static-provider.secret-access-k
ey=test-secret
or Apache HTTP:
<dependency>
You need to set a HTTP client either URL Connection : <groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<dependency> </dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
And you need to add the asynchronous Netty client:
<dependency>
or Apache HTTP: <groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
<dependency> </dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
HTTP Con guration The le path to a service certi cate or certi cate chain in PEM enable-compression
format. Relative to src/main/resources . If responses should be compressed.
You can con gure HTTP parameters. Using quarkus.http pre x:
ssl.certificate.key-file read-timeout
cors The le path to the corresponding certi cate 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 certi cate 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 certi cate information of the certi cates 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
Exception Mapper
Extension can be con gured with the follwoing paramters pre xed application.properties le using the next properties with An optional key store which holds the certi cate information
with quarkus.smallrye-graphql . quarkus.resteasy su x: instead of specifying separate les.
root-path gzip.enabled
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 Con gure the upper limit on de ated 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 certi cate information of the
certi cates 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 con gure 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
{
maxRetries , delay , delayUnit , "status": "UP",
You can set fallback code in case of an error by using @Fallback
maxDuration , durationUnit , "checks": [
annotation: @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
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 MicroPro le 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 /metrics providing default
metrics.
.state("successful-read", this::isReady) kafka-streams
}
Liveness (for stream state) and Readiness (topics created) MicroPro le 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 /health/live or /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 <component>.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.
binder.vertx.match-patterns
You can con gure Metrics: You can con gure Micrometer. Pre x is quarkus.micrometer : Comma-separated case-sensitive list of regular expressions
de ning 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 de ning Paths that should be ignored / not measured.
Pre x is quarkus.smallrye-metrics .
Micrometer MeterRegistry discovery. (default: true )
export.datadog
path
The path to the metrics handler. (default: /metrics ) binder-enabled-default Datadog MeterRegistry con guration in Map<String, String>
Vert.x metrics support. JMX registry con guration properties in Map<String, String>
format.
micrometer.compatibility
Apply Micrometer compatibility mode. (default: false ) binder.mp-metrics.enabled
export.prometheus
Micropro le Metrics support.
Prometheus registry con guration properties in Map<String,
quarkus.hibernate-orm.metrics.enabled set to true exposes
String> format.
Hibernate metrics under vendor scope. binder.jvm
export.prometheus.enabled
Support for export to Prometheus. Requests sent to any endpoint are traced automatically.
This extension includes OpenTracing support and Jaeger tracer.
<dependency> Native Executable
<groupId>io.opentracing.contrib</groupId>
Jaeger tracer con guration:
<artifactId>opentracing-kafka-client<</artifactId> You can build a native image by using GraalVM. The common use
</dependency> 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
quarkus.jaeger.endpoint=http://localhost:14268/api/traces And con gure it: ./mvnw package -Pnative -Dquarkus.native.container-build=tr
ue
quarkus.jaeger.metrics.enabled=true
...
docker build -f src/main/docker/Dockerfile.native
mp.messaging.outgoing.generated-price.topic=prices
-t quarkus/getting-started .
@Traced annotation can be set to disable tracing at class or method docker run -i --rm -p 8080:8080 quarkus/getting-started
# For Produces
level.
mp.messaging.outgoing.generated-price.interceptor.classes=i
Tracer class can be injected into the class.
o.opentracing.contrib.kafka.TracingProducerInterceptor
... You can use quarkus.native.container-runtime to select the
# For consumers container runtime to use. Now docker (default) and podman are the
@Inject
mp.messaging.incoming.prices.interceptor.classes=io.opentra valid options.
Tracer tracer;
cing.contrib.kafka.TracingConsumerInterceptor
tracer.activeSpan().setBaggageItem("key", "value"); ./mvnw package -Pnative -Dquarkus.native.container-runtime=
podman
AWS XRay
You can disable Jaeger extension by using quarkus.jaeger.enabled If you are building native images, and want to use AWS X-Ray
property. To con gure native application, you can create a config directory at
Tracing with your lambda you will need to include quarkus-amazon- the same place as the native le and place an
lambda-xray as a dependency in your pom.
You can log the traceId , spanId and sampled in normal log: application.properties le inside. config/application.properties .
SSL
quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{tra
ceId}, To create a native image with SSL you need to copy SunEC library
spanId=%X{spanId}, sampled and certi cates:
=%X{sampled} [%c{2.}] (%t) %s%e%n
Java 8:
Kafka Tracer
By default, no resources are included in native executable. Quarkus copies any le under src/main/jib into the built container base-native-image
quarkus.native.resources.includes allows to set glob expressions to
image.
include resources based on src/main/resources path. The base image to use for the native build. (default:
registry.access.redhat.com/ubi8/ubi-minimal )
Pre x is quarkus.container-image-jib :
Given src/main/resources/foo/selected.png :
base-jvm-image Kubernetes
quarkus.native.resources.includes=foo/** The base image to use for the jib build. (default: fabric8/java-
alpine-openjdk8-jre ) Quarks can use Dekorate to generate Kubernetes resources.
name jvm-entrypoint
The name of the image. (default: the application name) A custom entry point of the container image in JVM mode.
tag native-entrypoint
The tag of the image. (default: the application version) A custom entry point of the container image in native mode.
additional-tags Docker
Additional tags of the container image.
./mvnw quarkus:add-extensions
registry -Dextensions="quarkus-container-image-docker"
ca-cert-file
CA certi cate data.
client-cert-file
@QuarkusTestResource(KubernetesMockServerTestResource.clas <dependency> public class GreetingFunction {
s) <groupId>io.quarkus</groupId>
@QuarkusTest <artifactId>quarkus-test-amazon-lambda</artifactId> @Inject
public class KubernetesClientTest { <scope>test</scope> GreetingService service;
</dependency>
@MockServer @io.quarkus.funqy.Funq
private KubernetesMockServer mockServer; public String greet(String name) {}
@Test @Test @io.quarkus.funqy.Funq("HelloCustomer")
public void test() { public void testLambda() { public String greet(Customer name) {}
final Pod pod1 = ... MyInput in = new MyInput();
mockServer in.setGreeting("Hello"); @Funq
.expect() in.setName("Stu"); public Greeting greet(Friend friend,
.get() MyOutput out = LambdaClient.invoke(MyOutput.class, in); @io.quarkus.funqy.Context AwsContext ctx) {}
.withPath("/api/v1/namespaces/test/pods") } }
.andReturn(200,
new PodListBuilder()
.withNewMetadata() To scaffold a AWS Lambda run: In case of Amazon Lambda, only one Funqy function can be
.withResourceVersion("1")
exported per Amazon Lambda deployment. If there is only one
.endMetadata()
mvn archetype:generate \ method annotated with @Funq then no prob, if not, you need to set
.withItems(pod1, pod2)
-DarchetypeGroupId=io.quarkus \ the function name with quarkus.funqy.export property.
.build())
-DarchetypeArtifactId=quarkus-amazon-lambda-archetype \
.always();
}
-DarchetypeVersion={version} Funqy HTTP
}
You can invoke on Funqy functions in a pure HTTP environment
with simple adding the Funqy HTTP extension.
Azure Functions
AWS Lambda <dependency>
Quarkus can make a microservice be deployable to the Azure
<groupId>io.quarkus</groupId>
Functions.
Quarkus integrates with Amazon Lambda. <artifactId>quarkus-funqy-http</artifactId>
To scaffold a deployable microservice to the Azure Functions run: </dependency>
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-amazon-lambda"
mvn archetype:generate \
-DarchetypeGroupId=io.quarkus \ Funqy Cloud Events
-DarchetypeArtifactId=quarkus-azure-functions-http-archet
And then implement ype \ Add the extension:
com.amazonaws.services.lambda.runtime.RequestHandler interface. -DarchetypeVersion={version}
<dependency>
public class TestLambda <groupId>io.quarkus</groupId>
implements RequestHandler<MyInput, MyOutput> {
Funqy <artifactId>quarkus-funqy-knative-events</artifactId>
@Override </dependency>
public MyInput handleRequest(MyOutput input,
Quarkus Funqy is part of Quarkus’s serverless strategy and aims to
Context context) {
provide a portable Java API to write functions deployable to various
}
FaaS environments like AWS Lambda, Azure Functions, Knative, and
} @Funq
Knative events.
public String defaultChain(String input) {}
The interface
com.amazonaws.services.lambda.runtime.RequestStreamHandler is also The Cloud Event type that triggers the function is defaultChain . It
supported. generates a response that triggers a new Cloud Event whose type is
defaultChain.output and the event source is defaultChain .
The interface com.amazon.ask.SkillStreamHandler is also supported.
It can be changed by using the next properties:
You can set the handler name by using quarkus.lambda.handler
property or by annotating the Lambda with the CDI @Named
quarkus.funqy.knative-events.mapping.defaultChain.trigger=c
annotation.
onfigChain.output
Test quarkus.funqy.knative-events.mapping.defaultChain.response-
type=annotated
You can write tests for Amazon lambdas: quarkus.funqy.knative-events.mapping.defaultChain.response-
source=configChain
The properties are of form: quarkus.funqy.knative-events.mapping. Apache Camel Possible Swagger UI options with quarkus.swagger-ui pre x:
{function name}. .
urls
Apache Camel Quarkus has its own site:
Also can be overriden with The urls that will be included as options. (ie
https://github.com/apache/camel-quarkus quarkus.swagger-
@io.quarkus.funqy.knative.events.CloudEventMapping annotation. ui.urls.petstore=https://petstore.swagger.io/v2/swagger.json )
@Funq
WebSockets
urls-primary-name
@CloudEventMapping(trigger = "annotated", responseSource = If urls option is used, this will be the name of the default
Quarkus can be used to handling web sockets.
"annotated", responseType = "lastChainLink") selection.
public String annotatedChain(String input) {}
./mvnw quarkus:add-extension
title
-Dextensions="io.quarkus:quarkus-undertow-websockets"
The html title for the page.
responseType chains annotatedChain response to lastChainLink
function. theme
And web sockets classes can be used:
Swagger UI theme to be used.
@Funq
public void lastChainLink(String input, @ServerEndpoint("/chat/{username}")
footer
@Context io.quarkus.funqy.knative.events.CloudE @ApplicationScoped
vent event) {} 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.
A K-Native Trigger looks like: @PathParam("username") String username) {}
display-operation-id
apiVersion: eventing.knative.dev/v1alpha1 @OnClose
kind: Trigger
Controls the display of operationId in operations list.
public void onClose(..) {}
metadata:
name: defaultchain default-models-expand-depth
@OnError
spec: public void onError(..., Throwable throwable) {} The default expansion depth for models.
filter:
attributes: @OnMessage default-model-expand-depth
type: defaultChain public void onMessage(...) {} The default expansion depth for the model on the model-example
subscriber: section.
ref: }
apiVersion: serving.knative.dev/v1
default-model-rendering
kind: Service
name: funqy-knative-events-quickstart 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
And to curl from inside the Kubernetes cluster:
using Swagger UI. "Try it out" requests.
curl -v "http://default-broker.knativetutorial.svc.cluster.
./mvnw quarkus:add-extension doc-expansion
local" \
-X POST \
-Dextensions="io.quarkus:quarkus-smallrye-openapi" Controls the default expansion setting for the operations and
-H "Ce-Id: 1234" \ tags.
-H "Ce-Specversion: 1.0" \
-H "Ce-Type: defaultChain" \ Then you only need to access to /openapi to get OpenAPI v3 spec filter
-H "Ce-Source: curl" \ of services. Enables ltering.
-H "Content-Type: application/json" \
-d '"Start"' You can update the OpenApi path by setting quarkus.smallrye-
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
Transactional objects must be interfaces and annotated with @Nested : De nes that the container will create a new top-level clustered
org.jboss.stm.annotations.Transactional . or nested transaction for each method invocation.
Enable cluster mode or not.
Programmatically
@Transactional store-type
@NestedTopLevel
AtomicAction aa = new AtomicAction(); The type of store to use. Possible values: ram , db (default: ram )
public interface FlightService {
int getNumberOfBookings();
aa.begin(); datasource
void makeBooking(String details);
}
{ The name of the datasource to use.
try {
flightService.makeBooking("BA123 ..."); table-prefix
taxiService.makeBooking("East Coast Taxis ...");
The pessimistic strategy is the default one, you can change to The pre x for quartz job store tables. (default: QRTZ_ )
optimistic by using @Optimistic . aa.commit();
trigger-listeners.<name>.class
} catch (Exception e) {
Then you need to create the object inside org.jboss.stm.Container . aa.abort(); Class name for the trigger.
}
Container<FlightService> container = new Container<>(); } trigger-listeners.<name>.property-name
FlightServiceImpl instance = new FlightServiceImpl(); The properties passed to the class.
FlightService flightServiceProxy = container.create(instanc
e);
Quartz job-listeners.<name>.class
plugins.<name>.property-name
@io.quarkus.qute.i18n.MessageBundle
{@org.acme.Item item}
public interface AppMessages {
<!DOCTYPE html> If @ResourcePath is not used in Template then the name of the eld is
@io.quarkus.qute.i18n.Message("Hello {name}!")
<html> used as le name. In this case the le should be
String hello_name(String name);
<head> src/main/resources/templates/item.{} . Extension of the le is not
}
<meta charset="UTF-8"> required to be set.
<title>{item.name}</title>
</head> discountedPrice is not a eld of the POJO but a method call.
<body> Method de nition must be annotated with @TemplateExtension and There are 3 methods to inject the message:
<h1>{item.name ?: 'Unknown'}</h1> be static method. First parameter is used to match the base object
<h2>{str:reverse('Hello')}</h2> ( Item ). @TemplateExtension can be used at class level: MessageBundles.get(AppMessages.class).hello_name("Lucie");
<div>Price: {item.price}</div>
{#if item.price > 100} @TemplateExtension
<div>Discounted Price: {item.discountedPrice}</div> public class MyExtensions {
or
{/if} static BigDecimal discountedPrice(Item item) {
</body> return item.price.multiply(new BigDecimal("0.9"));
</html> } @Inject AppMessages app;
}
app.hello_name("Lucie");
OptaPlanner properties-value-keys
Keys whose value represents a properties-like le conttent.
If using mutiny extension together you already get context
Quarkus integrates with OptaPlanner. propagation for ArC, RESTEasy and transactions. With
fail-on-missing-key
CompletionStage you need to:
./mvnw quarkus:add-extension If the application will not start if any of the con gured con g
-Dextensions="quarkus-optaplanner, quarkus-optaplanner-ja sources cannot be located. (default: true )
@Inject ThreadContext threadContext;
ckson" @Inject ManagedExecutor managedExecutor;
trust-store
threadContext.withContextCapture(..) TrustStore to be used containing the SSL certi cate used by
.thenApplyAsync(r -> {}, managedExecutor); Consul agent.
@PlanningSolution
public class TimeTable { trust-store-password
}
If you are going to use security in a reactive environment you will Password of TrustStore to be used containing the SSL certi cate
likely need Smallrye Content Propagation to propagate the identity used by Consul agent.
@Inject
private SolverManager<TimeTable, UUID> solverManager; throughout the reactive callback.
key-password
UUID problemId = UUID.randomUUID(); Con guration from HasiCorp Consul Password to recover key from KeyStore for SSL client
SolverJob<TimeTable, UUID> solverJob = solverManager.solve authentication with Consul agent.
(problemId, problem); You can read runtime con guration from HashiCorp Consul.
TimeTable solution = solverJob.getFinalBestSolution(); agent.host-port
solver.termination.unimproved-spent-limit Possible con guration parameters, pre xed with quarkus.consul- Reading timeout. (default: 60S )
How long the solver can run without nding a new best solution config :
after nding a new best solution. (ie 2h ) Amazon Alexa
enabled
solver.termination.best-score-limit The application will attempt to look up the con guration from You can use Amazon Alexa by adding the extension:
Terminates the solver when a speci c or higher score has been Consul. (default: false )
reached. (ie 0hard/-1000soft ) ./mvnw quarkus:add-extension
prefix -Dextensions="quarkus-amazon-alexa"
solver-manager.parallel-solver-count Common pre x that all keys share when looking up the keys from
The number of solvers that run in parallel. (default: Consul. The pre x is not included in the keys of the user
PARALLEL_SOLVER_COUNT_AUTO ) con guration
WebJar Locator
raw-value-keys
Context Propagation
To change how you can refer to webjars skipping the version part
<dependency> Spring DI
you can use WebJars locator extension. <groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId> Quarkus provides a compatibility layer for Spring dependency
./mvnw quarkus:add-extension </dependency> injection.
-Dextensions="webjars-locator"
./mvnw quarkus:add-extension
Con guration properties are the same as Amazon DynamoDB but -Dextensions="quarkus-spring-di"
Then the JavaScript location is changed from changing the pre x from dynamodb to ses .
/webjars/jquery/3.1.1/jquery.min.js to
/webjars/jquery/jquery.min.js in your HTML les. Jbang Some examples of what you can do. Notice that annotations are
the Spring original ones.
Amazon SES Creating an initial script:
@Configuration
public class AppConfiguration {
mvn quarkus:add-extension jbang scripting/quarkusapp.java
-Dextensions="amazon-ses"
@Bean(name = "capitalizeFunction")
public StringFunction capitalizer() {
Adding Quarkus dependencies in script: return String::toUpperCase;
@Inject }
software.amazon.awssdk.services.ses.SesClient sesClient; //DEPS io.quarkus:quarkus-resteasy:{quarkus-version} }
@Inject
software.amazon.awssdk.services.ses.SesAsyncClient sesClien Put some Quarkus CLI code: Or as a component:
t;
@Component("noopFunction")
@Path("/hello")
public class NoOpSingleStringFunction
@ApplicationScoped
implements StringFunction {
quarkus.ses.endpoint-override=http://localhost:8012 public class quarkusapp {
}
quarkus.ses.aws.region=us-east-1 @GET
quarkus.ses.aws.credentials.type=static public String sayHello() {
quarkus.ses.aws.credentials.static-provider.access-key-id=t return "hello";
est-key } Also as a service and injection properties from
quarkus.ses.aws.credentials.static-provider.secret-access-k public static void main(String[] args) { application.properties .
ey=test-secret Quarkus.run(args);
} @Service
} public class MessageProducer {
You need to set a HTTP client either URL Connection :
@Value("${greeting.message}")
To run the script: String message;
<dependency>
<groupId>software.amazon.awssdk</groupId> }
<artifactId>url-connection-client</artifactId> jbang quarkusapp.java
</dependency>
Interfaces supported:
Spring Cloud Con g Client Speci cally supports the REST related features. Notice that
infrastructure things like BeanPostProcessor will not be executed. org.springframework.data.repository.Repository
Quarkus integrates Spring Cloud Con g Client and MicroPro le
Con g spec. org.springframework.data.repository.CrudRepository
@RestController
@RequestMapping("/greeting")
./mvnw quarkus:add-extension org.springframework.data.repository.PagingAndSortingReposito
public class GreetingController {
-Dextensions="quarkus-spring-cloud-config-client" ry
private final GreetingBean greetingBean; org.springframework.data.jpa.repository.JpaRepository .
You need to con gure the extension: public GreetingController(GreetingBean greetingBean) { INFO: Generated repositories are automatically annotated with
this.greetingBean = greetingBean; @Transactional .
}
quarkus.spring-cloud-config.uri=http://localhost:8089
Repository fragments is also supported:
quarkus.spring-cloud-config.username=user
@GetMapping("/{name}")
quarkus.spring-cloud-config.password=pass
public Greeting hello(@PathVariable(name = "name") public interface PersonRepository
quarkus.spring-cloud-config.enabled=true
String name) { extends JpaRepository<Person, Long>, PersonFragment {
return new Greeting(greetingBean.greet(name));
} void makeNameUpperCase(Person person);
@ConfigProperty(name = "greeting.message") } }
String greeting;
hasRole
@PreAuthorize("hasRole('admin')")
Resources Authors : 1.10.2.Final
https://quarkus.io/guides/ @alexsotob
Java Champion and Director of DevExp at Red Hat
https://www.youtube.com/user/lordofthejars