Quarkus Cheat Sheet
Quarkus Cheat Sheet
Quarkus Cheat Sheet
Cheat-Sheet
quarkus.http.port=9090
Gradle extensions property supports CSV format to register more
%dev.quarkus.http.port=8181
If property does not follow getter/setter naming convention you Then you need to register the ConfigSource as Java service. Create
In case of subkeys ~ is used to refer to the unpre xed part. a le with the following content:
need to use org.eclipse.microprofile.config.inject.ConfigProperty
to set it. /META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource
You can implement your own conversion types from String. You can also create a factory of an object by using
public class Sauce {
Implement org.eclipse.microprofile.config.spi.Converter @javax.enterprise.inject.Produces annotation.
private String name;
interface:
private long scovilleHeatUnits;
@Produces
@Priority(DEFAULT_QUARKUS_CONVERTER_PRIORITY + 100) @ApplicationScoped // getter/setters
public class CustomInstantConverter Message message() { }
implements Converter<Instant> { Message m = new Message();
m.setMsn("Hello");
@Override return m;
public Instant convert(String value) { }
JSON equivalent:
if ("now".equals(value.trim())) {
return Instant.now(); @Inject {
} Message msg; "name":"Blair's Ultra Death",
return Instant.parse(value); "scovilleHeatUnits": 1100000
} }
}
Quali ers
You can use quali ers to return different implementations of the In a POST endpoint example:
@Priority annotation is used to override the default same interface or to customize the con guration of the bean.
InstantConverter . @POST
@Qualifier @Consumes(MediaType.APPLICATION_JSON)
Then you need to register the Converter as Java service. Create a @Retention(RUNTIME) public Response create(Sauce sauce) {
le with the following content: @Target({TYPE, METHOD, FIELD, PARAMETER}) // Create Sauce
/META-INF/services/org.eclipse.microprofile.config.spi.Converter public @interface Quote { return Response.created(URI.create(sauce.getId()))
@Nonbinding String value(); .build();
com.acme.config.CustomInstantConverter } }
@Produces
@Quote("")
Custom Context Path To work with Jackson you need to add:
Message message(InjectionPoint msg) {
Message m = new Message();
By default Undertow will serve content from under the root context. m.setMsn( ./mvnw quarkus:add-extension
If you want to change this you can use the quarkus.servlet.context- msg.getAnnotated() -Dextensions="quarkus-resteasy-jackson"
path con g key to set the context path. .getAnnotation(Quote.class)
.value()
Injection ); If you don’t want to use the default ObjectMapper you can customize
it by:
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 }
@ApplicationScoped
implemented.
public class CustomObjectMapperConfig {
@Inject
@Singleton
@Quote("Aloha Beach")
@ApplicationScoped @Produces
Message message;
public class GreetingService { public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
public String message(String message) { // perform configuration
return message.toUpperCase(); Quarkus breaks the CDI spec by allowing you to inject return objectMapper;
} quali ed beans without using @Inject annotation. }
} }
@Quote("Aloha Beach")
Message message;
Scope annotation is mandatory to make the bean discoverable. XML Marshalling/Unmarshalling
@Inject
JSON Marshalling/Unmarshalling To work with JAX-B you need to add a dependency:
GreetingService greetingService;
public Response create(@Valid Sauce sauce) {} Minimum log level (default: ALL )
Manual Validation
file.path
You can call the validation process manually instead of relaying to The path to log le (default: quarkus.log )
If a validation error is triggered, a violation report is
@Valid by injecting Validator class.
generated and serialized as JSON. If you want to
file.rotation.max-file-size
manipulate the output, you need to catch in the code the
ConstraintViolationException exception. @Inject The maximum le size of the log le
Validator validator;
Create Your Custom Constraints file.rotation.max-backup-index
The maximum number of backups to keep (default: 1 )
First you need to create the custom annotation:
And use it:
file.rotation.file-suffix
You can con gure how Quarkus logs: Log asynchronously (default: false )
file.async.queue-length
The queue length to use before ushing writing (default: 512 )
file.async.overflow
./mvnw quarkus:add-extension public class WorldClockOptions {
Action when queue is full (default: BLOCK ) -Dextensions="quarkus-logging-json" @HeaderParam("Authorization")
String auth;
syslog.enable
syslog logging is enabled (default: false ) And the con guration values are pre x with quarkus.log : @PathParam("where")
String where;
syslog.format json }
The format pattern to use for logging to syslog. Default value: JSON logging is enabled (default: true).
%d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n
json.pretty-print And con gure the hostname at application.properties :
syslog.level JSON output is "pretty-printed" (default: false)
The minimum log level to write to syslog (default: ALL ) org.acme.quickstart.WorldClockService/mp-rest/url=
json.date-format http://worldclockapi.com
syslog.endpoint Specify the date format to use (default: the default format)
The IP address and port of the syslog server (default:
localhost:514 ) json.record-delimiter Injecting the client:
Record delimiter to add (default: no delimiter)
syslog.app-name @RestClient
The app name used when formatting the message in RFC5424 json.zone-id WorldClockService worldClockService;
format (default: current process name) The time zone ID
syslog.hostname
json.exception-output-type If invokation happens within JAX-RS, you can propagate headers
The name of the host the messages are being sent from (default: The exception output type: detailed , formatted , detailed-and-
from incoming to outgoing by using next property.
current hostname) formatted (default: detailed )
org.eclipse.microprofile.rest.client.propagateHeaders=
syslog.facility Authorization,MyCustomHeader
json.print-details
Priority of the message as de ned by RFC-5424 and RFC-3164 Detailed caller information should be logged (default: false)
(default: USER_LEVEL )
syslog.syslog-type
Rest Client You can still use the JAX-RS client without any problem
ClientBuilder.newClient().target(…
)
The syslog type of format message (default: RFC5424 )
Quarkus implements MicroPro le Rest Client spec:
Adding headers
syslog.protocol
./mvnw quarkus:add-extension You can customize the headers passed by implementing
Protocol used (default: TCP ) -Dextensions="quarkus-rest-client" MicroPro le ClientHeadersFactory annotation:
syslog.use-counting-framing
@RegisterForReflection
Message pre xed with the size of the message (default false )
To get content from http://worldclockapi.com/api/json/cet/now public class BaggageHeadersFactory
you need to create a service interface: implements ClientHeadersFactory {
syslog.truncate
@Override
Message should be truncated (default: true ) @Path("/api") public MultivaluedMap<String, String> update(
@RegisterRestClient MultivaluedMap<String, String> incomingHeaders,
syslog.block-on-reconnect MultivaluedMap<String, String> outgoingHeaders) {}
public interface WorldClockService {
Block when attempting to reconnect (default: true ) }
@GET @Path("/json/cet/now")
syslog.async @Produces(MediaType.APPLICATION_JSON)
Log asynchronously (default: false ) WorldClock getNow(); And registering it in the client using RegisterClientHeaders
annotation.
syslog.async.queue-length
@GET
@Path("/json/{where}/now")
The queue length to use before ushing writing (default: 512 ) @Produces(MediaType.APPLICATION_JSON)
@RegisterClientHeaders(BaggageHeadersFactory.class)
@RegisterRestClient
WorldClock getSauce(@BeanParam
syslog.async.overflow public interface WorldClockService {}
WorldClockOptions worldClockOptions);
Action when queue is full (default: BLOCK )
}
JSON output Or statically set:
You can con gure the output to be in JSON format instead of plain
text.
@GET import org.acme.quickstart.WorldClockService/mp-rest/connectTimeou
@ClientHeaderParam(name="X-Log-Level", value="ERROR") org.jboss.resteasy.annotations.providers.multipart.Mult t=
Response getNow(); ipartForm; 1000
org.acme.quickstart.WorldClockService/mp-rest/readTimeout=
@Path("/echo") 2000
@RegisterRestClient
Asynchronous
public interface MultipartService {
A method on client interface can return a CompletionStage class to
be executed asynchronously. @POST Testing
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN) Quarkus archetype adds test dependencies with JUnit 5 and Rest-
@GET @Path("/json/cet/now") Assured library to test REST endpoints.
String sendMultipartData(@MultipartForm
@Produces(MediaType.APPLICATION_JSON)
MultipartBody data);
CompletionStage<WorldClock> getNow();
@QuarkusTest
} public class GreetingResourceTest {
Multipart @Test
public void testHelloEndpoint() {
It is really easy to send multipart form-data with Rest Client. SSL
given()
You can con gure Rest Client key stores. .when().get("/hello")
<dependency> .then()
<groupId>org.jboss.resteasy</groupId> .statusCode(200)
org.acme.quickstart.WorldClockService/mp-rest/trustStore=
<artifactId>resteasy-multipart-provider</artifactId> .body(is("hello"));
classpath:/store.jks
</dependency> }
org.acme.quickstart.WorldClockService/mp-rest/trustStorePas
}
sword=
supersecret
The model object:
Test port can be set in quarkus.http.test-port property.
import java.io.InputStream; Possible con guration properties: You can also inject the URL where Quarkus is started:
import javax.ws.rs.FormParam; %s/mp-rest/trustStore
import javax.ws.rs.core.MediaType; @TestHTTPResource("index.html")
Trust store location de ned with classpath: or file: pre x.
URL url;
import
%s/mp-rest/trustStorePassword
org.jboss.resteasy.annotations.providers.multipart.Part
Type; Trust store password.
Quarkus Test Resource
%s/mp-rest/trustStoreType
public class MultipartBody { You can execute some logic before the rst test run ( start ) and
Trust store type (default: JKS ) execute some logic at the end of the test suite ( stop ).
@FormParam("file")
@PartType(MediaType.APPLICATION_OCTET_STREAM) %s/mp-rest/hostnameVerifier You need to create a class implementing
private InputStream file; QuarkusTestResourceLifecycleManager interface and register it in the
Custom hostname veri er class name.
test via @QuarkusTestResource annotation.
@FormParam("fileName")
%s/mp-rest/keyStore
@PartType(MediaType.TEXT_PLAIN)
private String name; Key store location de ned with classpath: or file: pre x.
// getter/setters %s/mp-rest/keyStorePassword
} Key store password.
%s/mp-rest/keyStoreType
And the Rest client interface: Key store type (default: JKS )
Timeout
@QuarkusTestResource(MyCustomTestResource.class)
public class MyTest {
} List of datasource parameters.
password String
Interceptors
initial-size Integer
Tests are actually full CDI beans, so you can apply CDI interceptors:
background-validation-interval java.time.Duration
Parameter Type Parameter Description Values[Default] // Insert
Developer developer = new Developer();
acquisition-timeout java.time.Duration [ none ], create , drop- developer.name = "Alex";
Database schema
database.generation and-create , drop , developer.persist();
is generation.
update .
leak-detection-interval java.time.Duration // Find All
Developer.findAll().list();
Stop on the rst
idle-removal-interval java.time.Duration database.generation.halt- error when
[ flase ], true // Find By Query
on-error applying the Developer.find("name", "Alex").firstResult();
schema.
io.quarkus.agroal.runtime
transaction-isolation-level // Delete
.TransactionIsolationLevel
Developer developer = new Developer();
database.default-catalog Default catalog. developer.id = 1;
developer.delete();
enable-metrics Boolean
database.default-schema Default Schema.
// Delete By Query
xa Boolean
long numberOfDeleted = Developer.delete("name", "Alex");
database.charset Charset.
The storage engine log.sql Show SQL logs [ false ], true Static Methods
when the dialect Not necessary to
dialect.storage-engine findById :`Object`
supports multiple set.
storage engines. Collect and show Returns object or null if not found. Overloaded version with
log.jdbc-warnings [ false ], true LockModeType is provided.
JDBC warnings.
<artifactId>jandex-maven-plugin</artifactId>
streamAll @DataSource("users")
<version>1.0.3</version>
java.util.stream.Stream of all entities. <executions> AgroalDataSource dataSource1;
<execution>
streamAll :`Sort` <id>make-index</id>
java.util.stream.Stream of all entities sorted by Sort attribute/s. <goals> Flushing
<goal>jandex</goal>
count
</goals> You can force ush operation by calling .flush() or
</execution> .persistAndFlush() to make it in a single call.
Number of entities.
</executions>
<dependencies> This ush is less e cient and you still need to commit
count :`String`, [ Object… , Map<String, Object> , Parameters ]
<dependency> transaction.
Number of entities meeting given query with parameters set. <groupId>org.jboss</groupId>
<artifactId>jandex</artifactId>
Testing
deleteAll <version>2.1.1.Final</version>
Number of deleted entities. </dependency> There is a Quarkus Test Resource that starts and stops H2 server
</dependencies> before and after test suite.
delete :`String`, [ Object… , Map<String, Object> , Parameters ]
</plugin>
Register dependency io.quarkus:quarkus-test-h2:test .
Number of deleted entities meeting given query with parameters
set. And annotate the test:
DAO pattern
persist :[ Iterable , Steram , Object… ]
Also supports DAO pattern with PanacheRepository<TYPE> . @QuarkusTestResource(H2DatabaseTestResource.class)
TIP: find methods de nes a withLock(LockModeType) to de ne the public class FlywayTestResources {
lock type and withHint(QueryHints.HINT_CACHEABLE, "true") to }
@ApplicationScoped
de ne hints.
public class DeveloperRepository
implements PanacheRepository<Person> {
Pagination
public Person findByName(String name){ Transactions
return find("name", name).firstResult();
PanacheQuery<Person> livingPersons = Person } The easiest way to de ne your transaction boundaries is to use the
.find("status", Status.Alive); } @Transactional annotation.
livingPersons.page(Page.ofSize(25));
Transactions are mandatory in case of none idempotent
// get the first page operations.
List<Person> firstPage = livingPersons.list(); EntityManager You can inject EntityManager in your classes:
// get the second page @Transactional
List<Person> secondPage = livingPersons.nextPage().list(); @Inject
public void createDeveloper() {}
EntityManager em;
em.persist(car);
If entities are de ned in external JAR, you need to enable in these You can control the transaction scope:
projects the Jandex plugin in project.
@Transactional(REQUIRED) (default): starts a transaction if none
Multiple datasources was started, stays with the existing one otherwise.
You can register more than one datasource. @Transactional(REQUIRES_NEW) : starts a transaction if none was
started; if an existing one was started, suspends it and starts a
# default new one for the boundary of that method.
quarkus.datasource.driver=org.h2.Driver
quarkus.datasource.url=jdbc:h2:tcp://localhost/mem:default @Transactional(MANDATORY) : fails if no transaction was started ;
.... works within the existing transaction otherwise.
# users datasource
quarkus.datasource.users.driver=org.h2.Driver @Transactional(SUPPORTS) : if a transaction was started, joins it ;
quarkus.datasource.users.url=jdbc:h2:tcp://localhost/mem:us otherwise works with no transaction.
ers
@Transactional(NOT_SUPPORTED) :
if a transaction was started,
suspends it and works with no transaction for the boundary of
the method; otherwise works with no transaction.
Notice that after datasource you set the datasource name, in
previous case users . @Transactional(NEVER) : if a transaction was started, raises an
exception; otherwise works with no transaction.
You can con gure the default transaction timeout using User written based
public class AuthorMarshaller
quarkus.transaction-manager.default-transaction-timeout
implements MessageMarshaller<Author> {
con guration property. By default it is set to 60 seconds. There are three ways to create your schema:
Proto le @Override
You can set a timeout property, in seconds, that applies to
public String getTypeName() {
transactions created within the annotated method by using
@TransactionConfiguration annotation. Creates a .proto le in the META-INF directory. return "book_sample.Author";
}
@Transactional package book_sample;
@Override
@TransactionConfiguration(timeout=40)
public Class<? extends Author> getJavaClass() {
public void createDeveloper() {} message Author {
return Author.class;
required string name = 1;
}
required string surname = 2;
}
If you want more control over transactions you can inject @Override
UserTransaction and use a programmatic way. public void writeTo(ProtoStreamWriter writer,
Author author) throws IOException {
In case of having a Collection eld you need to use the repeated key writer.writeString("name", author.getName());
@Inject UserTransaction transaction
(ie repeated Author authors = 4 ). writer.writeString("surname", author.getSurname());
}
transaction.begin(); In code
transaction.commit();
@Override
transaction.rollback(); Setting proto schema directly in a produced bean.
public Author readFrom(ProtoStreamReader reader)
throws IOException {
@Produces String name = reader.readString("name");
In nispan FileDescriptorSource bookProtoDefinition() { String surname = reader.readString("surname");
return FileDescriptorSource return new Author(name, surname);
.fromString("library.proto",
Quarkus integrates with In nispan: }
"package book_sample;\n" + }
"message Author {\n" +
./mvnw quarkus:add-extension " required string name = 1;\n" +
-Dextensions="infinispan-client" " required string surname = 2;\n" +
"}");
And producing the marshaller:
}
Serialization uses a library called Protostream. @Produces
MessageMarshaller authorMarshaller() {
Annotation based return new AuthorMarshaller();
Marshaller }
@ProtoFactory Using org.infinispan.protostream.MessageMarshaller interface.
public Author(String name, String surname) {
this.name = name; In nispan Embedded
this.surname = surname;
}
./mvnw quarkus:add-extension
-Dextensions="infinispan-embeddedy"
@ProtoField(number = 1)
public String getName() {
return name;
}
@ProtoField(number = 2)
public String getSurname() {
return surname;
}
@AutoProtoSchemaBuilder(includeClasses =
{ Book.class, Author.class },
schemaPackageName = "book_sample")
interface BookContextInitializer
extends SerializationContextInitializer {
}
flyway.locations You need to annotate your model with Hibernate Search API to
Con guration in infinispan.xml : CSV locations to scan recursively for migrations. Supported index it:
pre xes classpath and filesystem (default:
<local-cache name="quarkus-transaction"> classpath:db/migration ). @Entity
<transaction @Indexed
transaction-manager-lookup= flyway.connect-retries public class Author extends PanacheEntity {
"org.infinispan.transaction.lookup.JBossStandaloneJ
The maximum number of retries when attempting to connect
TAManagerLookup"/> @FullTextField(analyzer = "english")
(default: 0)
</local-cache> public String bio;
flyway.schemas
@FullTextField(analyzer = "name")
CSV case-sensitive list of schemas managed (default: none) @KeywordField(name = "firstName_sort",
Set con guration le location in application.properties :
sortable = Sortable.YES,
a| flyway.table normalizer = "sort")
quarkus.infinispan-embedded.xml-config=infinispan.xml
The name of Flyway’s schema history table (default: public String firstName;
flyway_schema_history )
@OneToMany
And you can inject the main entry point for the cache: flyway.sql-migration-prefix @IndexedEmbedded
Pre x for versioned SQL migrations (default: V ) public List<Book> books;
@Inject
}
org.infinispan.manager.EmbeddedCacheManager cacheManager; flyway.repeatable-sql-migration-prefix:: Pre x for repeatable SQL
migrations (default: R )
flyway.baseline-on-migrate
Flyway Only migrations above baseline-version will then be applied It is not mandatory to use Panache.
flyway.migrate-at-start
Flyway migration automatically (default: false )
public class LibraryResource { Parameter Description Parameter Description
@Inject username Username for auth. @Indexed Register entity as full text index
EntityManager em;
@Transactional password Password for auth. Full text search. Need to set an
@FullTextField
public List<Author> searchAuthors( analyzer to split tokens.
@QueryParam("pattern") String pattern) {
connection-timeout Duration of connection timeout.
return Search.getSearchSession(em)
The string is kept as one single
.search(Author.class) @KeywordField
.predicate(f ->
token but can be normalized.
Max number of connections to
pattern == null || pattern.isEmpty() ? max-connections
servers.
f.matchAll() :
Include the Book elds into the
f.simpleQueryString() IndexedEmbedded
Author index.
.onFields("firstName",
Max number of connections to
"lastName", "books.title") max-connections-per-route
server.
.matching(pattern)
Sets how to extract a value from
) @ContainerExtraction
container, e.g from a Map .
.sort(f -> f.byField("lastName_sort") indexes Per-index speci c con guration.
.then().byField("firstName_sort"))
.fetchHits(); Map an unusual entity identi er
@DocumentId
} discovery.enabled Enables automatic discovery. to a document identi er.
discovery.refresh-interval Refresh interval of node list. Full text index for any supported
When not using Hibernate ORM, index data using @GenericField
Search.getSearchSession(em).createIndexer()
type.
.startAndWait() at startup time.
Scheme to be used for the new
discovery.default-scheme
nodes. Reference to the identi er bridge
Con gure the extension in application.properties : @IdentifierBridgeRef
to use for a @DocumentId .
Possible annotations:
l l
quarkus.dynamodb.region= Parameter Default Description Parameter Default Description
eu-central-1
quarkus.dynamodb.endpoint-override= Credentials that The amount of time
process-
http://localhost:8000 should be used between credentials
provider.credential- PT15S
quarkus.dynamodb.credentials.type=STATIC DEFAULT , STATIC , expire and
refresh-threshold
quarkus.dynamodb.credentials.static-provider SYSTEM_PROPERTY , credentials refreshed.
credentials.type DEFAULT
.access-key-id=test-key ENV_VARIABLE ,
quarkus.dynamodb.credentials.static-provider PROFILE , CONTAINER ,
.secret-access-key=test-secret INSTANCE_PROFILE , process-
PROCESS , ANONYMOUS provider.async- Should fetch
false
credential-update- credentials async.
enabled
If you want to work with an AWS account, you’d need to set it with: Credentials speci c parameters pre xed with
quarkus.dynamodb.aws.credentials :
quarkus.dynamodb.region=<YOUR_REGION> In case of synchronous client, the next parameters can be
quarkus.dynamodb.credentials.type=DEFAULT Parameter Default Description con gured pre xed by quarkus.dynamodb.sync-client :
Con guration parameters pre xed with quarkus.dynamodb : STATIC connection-time-to- Max time connection
0
live to be open.
authentication
tls-managers- tls-managers- neo4j Password.
.password
provider.file- Key store password. provider.file- Key store type.
store.password store.type
authentication Disable
false
.disabled authentication.
In case of asynchronous client, the next parameters can be tls-managers-
con gured pre xed by quarkus.dynamodb.async-client : provider.file- Key store password.
store.password pool.metrics-enabled false Enable metrics.
Parameter Default Description
Pooled connections
connection-timeout Connection timeout. Max number of pool.max-connection- older will be closed
max-http2-streams 1H
concurrent streams. lifetime and removed from
the pool.
connection-time-to- Max time connection
0
live to be open. Enable custom event
event-loop.override false
loop conf. Timout for
pool.connection-
1M connection
acquisition-timeout
Max number of adquisation.
max-concurrency 50 concurrent event-loop.number-of- Number of threads to
connections. threads use in event loop.
Parameter Default Description @Inject Parameter Type Description
com.mongodb.client.MongoClient client;
Pooled connections connection-timeout Duration
pool.idle-time- idled in the pool for @Inject
before-connection- -1 longer than this io.quarkus.mongodb.ReactiveMongoClient client;
test timeout will be tested socket-timeout Duration
before they are used.
@ApplicationScoped
public class PersonRepository
implements PanacheMongoRepository<Person> {
}
./mvnw quarkus:add-extension
-Dextensions="quarkus-reactive-mysql-client" You can con gure ActiveMQ Artemis in application.properties le
by using next properties pre xed with quarkus :
Database con guration is the same as shown in Persistence Parameter Default Description
section, but URL is different as it is not a jdbc.
artemis.url Connection URL
quarkus.datasource.url=
vertx-reactive:mysql://localhost:3306/db Username for
artemis.username
authentication.
ActiveMQ Artemis
Quarkus uses Reactive Messaging to integrate with messaging
systems, but in case you need deeper control when using Apache
ActiveMQ Artemis there is also an extension:
./mvnw quarkus:add-extension
-Dextensions="quarkus-artemis-core"
RBAC You need to provide permissions set by using the roles-allowed
Parameter Default Description
property or use the built-in ones deny , permit or authenticated . Public Key text
You can set RBAC using annotations or in application.properties .
itself to be
JWT mp.jwt.verify.publickey none
Annotations supplied as a
string.
You can de ne roles by using Quarkus implements MicroPro le JWT RBAC spec.
javax.annotation.security.RolesAllowed annotation.
You can use io.quarkus.security.Authenticated as a shortcut of Minimum JWT required claims: typ , alg , kid , iss , sub , exp , iat , iss accepted as
@RolesAllowed("*") . jti , upn , groups .
mp.jwt.verify.issuer none
valid.
To alter RBAC behaviour there are two con guration properties: You can inject token by using JsonWebToken or a claim individually by
using @Claim . Supported public key formats:
quarkus.security.deny-unannotated=true
@Inject PKCS#8 PEM
JsonWebToken jwt;
JWK
Con guration options:
@Inject
JWKS
@Claim(standard = Claims.preferred_username)
Parameter Default Description
String name; JWK Base64 URL
If true denies by
quarkus.jaxrs.deny- @Inject JWKS Base64 URL
false default to all JAX-RS
uncovered @Claim("groups")
endpoints.
Set<String> groups; To send a token to server-side you should use Authorization
header: curl -H "Authorization: Bearer eyJraWQiOi… " .
If true denies by
To inject claim values, the bean must be @RequestScoped CDI
quarkus.security.deny- default all CDI Set of supported types: String , Set<String> , Long , Boolean,
false
methods and JAX-RS scoped. If you need to inject claim values in scope with a lifetime
unannotated `javax.json.JsonValue , Optional ,
greater than @RequestScoped then you need to use
endpoints. org.eclipse.microprofile.jwt.ClaimValue .
javax.enterprise.inject.Instance interface.
quarkus.oauth2.client-id=client_id
quarkus.oauth2.client-secret=secret
Con gure application to Keycloak service in application.properties quarkus.oauth2.introspection-url=http://oauth-server/intros You need to con gure the extension with users and roles les:
le. pect
And con guration in src/main/resources/application.properties :
quarkus.oidc.realm=quarkus
quarkus.oidc.auth-server-url=http://localhost:8180/auth quarkus.security.users.file.enabled=true
And you can map roles to be used in security annotations. quarkus.security.users.file.users=test-users.properties
quarkus.oidc.resource=backend-service
quarkus.oidc.bearer-only=true quarkus.security.users.file.roles=test-roles.properties
quarkus.oidc.credentials.secret=secret @RolesAllowed("Subscriber") quarkus.security.users.file.auth-mechanism=BASIC
quarkus.security.users.file.realm-name=MyRealm
quarkus.security.users.file.plain-text=true
Parameter Default Description Parameter Default Description Then users.properties and roles.properties :
The OAuth2 client IMPORTANT: If plain-text is set to false (or omitted) then
Relative path of the
quarkus.oauth2.client-secret secret used to passwords must be stored in the form MD5
jwks-path OIDC service
validate the token. ( username :`realm`:`password`).
returning a JWK set
Elytron File Properties con guration properties. Pre x
URL used to quarkus.security.users is skipped.
Public key for the
public-key local JWT token validate the token
quarkus.oauth2.introspection- Parameter Default Description
veri cation and gather the
url
authentication
claims. The le realm is
file.enabled false
The client-id of the enabled
client-id
application.
The claim that is
used in the The authentication
quarkus.oauth2.role-claim scope file.auth-mechanism BASIC
credentials.secret The client secret endpoint response mechanism
to load the roles
With Keycloak OIDC server The authentication
https://host:port/auth/realms/{realm} where {realm} has file.realm-name Quarkus
realm name
to be replaced by the name of the Keycloak realm. Authenticating via HTTP
You can use quarkus.http.cors property to enable
consuming form different domain. HTTP basic auth is enabled by the quarkus.http.auth.basic=true
If passwords are in
property. file.plain-text false
plain or in MD5
OAuth2 HTTP form auth is enabled by the
quarkus.http.auth.form.enabled=true property.
Classpath resource
Quarkus integrates with OAuth2 to be used in case of opaque file.users users.properties
of user/password
tokens (none JWT) and its validation against an introspection Then you need to add elytron-security-properties-file or elytron-
endpoint. security-jdbc .
Classpath resource
mvn quarkus:add-extension Security with Properties File file.roles roles.properties
of user/role
-Dextensions="security-oauth2"
You can also protect endpoints and store identities (user, roles) in
the le system. Embedded Realm
You can embed user/password/role in the same Parameter Default Description
quarkus.datasource.url=
application.properties :
quarkus.datasource.driver=org.h2.Driver
quarkus.datasource.username=sa principal-
The index of column
quarkus.security.users.embedded.enabled=true quarkus.datasource.password=sa query.bcrypt-
0 containing password
quarkus.security.users.embedded.plain-text=true password-
hash
quarkus.security.users.embedded.users.scott=jb0ss quarkus.security.jdbc.enabled=true mapper.password-index
quarkus.security.users.embedded.roles.scott=admin,tester,us quarkus.security.jdbc.principal-query.sql=
er SELECT u.password, u.role FROM test_user u WHERE u.user
quarkus.security.users.embedded.auth-mechanism=BASIC =? principal- A string referencing
quarkus.security.jdbc.principal-query query.bcrypt- the password hash
BASE64
.clear-password-mapper.enabled=true password-mapper.hash- encoding ( BASE64 or
quarkus.security.jdbc.principal-query encoding HEX )
IMPORTANT: If plain-text is set to false (or omitted) then
passwords must be stored in the form MD5 .clear-password-mapper.password-index=1
( username :`realm`:`password`). quarkus.security.jdbc.principal-query
principal-
.attribute-mappings.0.index=2 The index column
query.bcrypt-
Pre x quarkus.security.users.embedded is skipped. quarkus.security.jdbc.principal-query 0 containing the Bcrypt
password-mapper.salt-
.attribute-mappings.0.to=groups salt
index
Parameter Default Description
The le realm is You need to set the index (1-based) of password and role. principal-
file.enabled false
enabled A string referencing
query.bcrypt-
Elytron JDBC Realm con guration properties. Pre x BASE64 the salt encoding
password-mapper.salt-
quarkus.security.jdbc is skipped. ( BASE64 or HEX )
encoding
The authentication
file.auth-mechanism BASIC
mechanism Parameter Default Description
principal-
The authentication query.bcrypt- The index column
The authentication auth-mechanism BASIC
mechanism
file.realm-name Quarkus password- 0 containing the Bcrypt
realm name
mapper.iteration- iteration count
count-index
The authentication
If passwords are in realm-name Quarkus
realm name
file.plain-text false
plain or in MD5 For multiple datasources you can use the datasource name in the
properties:
If the properties store
* is user and value is enabled false
file.users.* is enabled quarkus.datasource.url=
password
quarkus.security.jdbc.principal-query.sql=
The sql query to nd
* is user and value is principal-query.sql quarkus.datasource.permissions.url=
file.roles.* the password
role quarkus.security.jdbc.principal-query.permissions.sql=
principal-
If the bcrypt-
query.bcrypt-
false password-mapper is
password-
enabled
mapper.enabled
# vault url Parameter Default Description Parameter Default Description
quarkus.vault.url=http://localhost:8200
Vault token to Certi cate bundle
authentication.client-token
quarkus.vault.authentication.userpass.username= access used to validate
tls.ca-cert
bob TLS
quarkus.vault.authentication.userpass.password= communications
sinclair Role Id for
authentication.app-role.role-id
AppRole auth
# path within the kv secret engine tls.use-kubernetes-ca-cert true TLS will be active
quarkus.vault.secret-config-kv-path=
authentication.app-role.secret- Secret Id for
myapps/vault-quickstart/config
id AppRole auth Tiemout to
connect-timeout 5S establish a
connection
Then you can inject the value con gured at secret/myapps/vault- Username for
authentication.userpass.username
quickstart/a-private-key . userpass auth
read-timeout 1S Request timeout
@ConfigProperty(name = "a-private-key")
String privateKey; Password for
authentication.userpass.password
userpass auth credentials-
provider."credentials- Database
provider".database-credentials- credentials role
You can access the KV engine programmatically: Kubernetes role
authentication.kubernetes.role
authentication role
@Inject
VaultKVSecretEngine kvSecretEngine; credentials- A path in vault kv
Location of the le provider."credentials- store, where we
kvSecretEngine.readSecret("myapps/vault-quickstart/" + vaul authentication.kubernetes.jwt- containing the provider".kv-path will nd the kv-key
tPath).toString(); token-path Kubernetes JWT
token
credentials- Key name to
provider."credentials- password search in vault
Fetching credentials DB Renew grace provider".kv-key path kv-path
renew-grace-period 1H
period duration.
With the next kv vault kv put secret/myapps/vault-quickstart/db
password=connor
Vault con g
quarkus.vault.credentials-provider.mydatabase.kv-path= secret-config-cache-period 10M source cache
myapps/vault-quickstart/db period
quarkus.datasource.credentials-provider=
mydatabase
Vault path in kv
secret-config-kv-path
quarkus.datasource.url= store
jdbc:postgresql://localhost:5432/mydatabase
quarkus.datasource.driver=
org.postgresql.Driver Used to hide
quarkus.datasource.username= log-confidentiality-level medium con dential infos.
sarah low , medium , high
Kv secret engine
No password is set as it is fetched from Vault. kv-secret-engine-version 1
version
INFO: dynamic database credentials through the database-
credentials-role property.
Kv secret engine
kv-secret-engine-mount-path secret
path
Elytron JDBC Realm con guration properties. Pre x quarkus.vault
is skipped.
Allows to bypass
Parameter Default Description
certi cate
tls.skip-verify false
validation on TLS
url Vault server URL
communications
JAX-RS Property Description Example @Provider
public class LoggingFilter
Quarkus uses JAX-RS to de ne REST-ful web APIs. Under the Gets cookie implements ContainerRequestFilter {
covers, Rest-EASY is working with Vert.X directly without using any @CookieParam param by
Servlet. name. @Context
UriInfo info;
It is important to know that if you want to use any feature that
implies a Servlet (ie Servlet Filters) then you need to add the Gets header @Context
quarkus-undertow extension to switch back to the Servlet @HeaderParam parameter by HttpServletRequest request;
ecosystem but generally speaking, you don’t need to add it as name.
everything else is well-supported. @Override
public void filter(ContainerRequestContext context) {
Valid HTTP method annotations provided by the spec are: @GET ,
@Path("/book") final String method = context.getMethod();
@POST , @PUT , @DELETE , @PATCH , @HEAD and @OPTIONS .
public class BookResource { final String path = info.getPath();
final String address = request.getRemoteAddr();
You can create new annotations that bind to HTTP methods not
@GET System.out.println("Request %s %s from IP %s",
de ned by the spec.
@Produces(MediaType.APPLICATION_JSON) method, path, address);
public List<Book> getAllBooks() {} }
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) }
@POST
@HttpMethod("LOCK")
@Produces(MediaType.APPLICATION_JSON)
public @interface LOCK {
public Response createBook(Book book) {}
}
Exception Mapper
@DELETE
@LOCK
@Path("{isbn}")
public void lockIt() {}
You can map exceptions to produce a custom output by
@Produces(MediaType.APPLICATION_JSON)
}
implementing ExceptionMapper interface:
public Response deleteBook(
@PathParam("isbn") String isbn) {}
@Provider
public class ErrorMapper
Injecting
implements ExceptionMapper<Exception> {
@GET
@Produces(MediaType.APPLICATION_JSON) Using @Context annotation to inject JAX-RS and Servlet information.
@Override
@Path("search")
public Response toResponse(Exception exception) {
public Response searchBook( @GET int code = 500;
@QueryParam("description") String description) {} public String getBase(@Context UriInfo uriInfo) { if (exception instanceof WebApplicationException) {
} return uriInfo.getBaseUri(); code = ((WebApplicationException) exception)
} .getResponse().getStatus();
}
To get information from request: return Response.status(code)
Possible injectable objects: SecurityContext , Request , Application , .entity(
Property Description Example Configuration , Providers , ResourceContext , ServletConfig , Json.createObjectBuilder()
ServletContext , HttpServletRequest , HttpServletResponse , .add("error", exception.getMessage())
Gets content HttpHeaders , Urinfo , SseEventSink and Sse . .add("code", code)
@PathParam from request /book/{id} @PathParam("id") .build()
URI. HTTP Filters )
.build();
HTTP request and response can be intercepted to manipulate the }
Gets query metadata (ie headers, parameters, media type, … ) or abort a }
@QueryParam /book?desc="" @QueryParam("desc)
parameter. request. You only need to implement the next
ContainerRequestFilter and ContainerResponseFilter JAX-RS
interfaces respectively.
@FormParam
Gets form Vert.X Filters and Routes
parameter.
Programmatically
Get URI You can also register Vert.X Filters and Router programmatically
@MatrixParam matrix /book;author=mkyong;country=malaysia inside a CDI bean:
parameter.
import io.quarkus.vertx.http.runtime.filters.Filters;
You can con gure Quarkus to use GZip in the @Path("/api")
application.properties le using the next properties with
import io.vertx.ext.web.Router; @RegisterRestClient
quarkus.resteasy su x:
import javax.enterprise.context.ApplicationScoped; public interface WorldClockService {
import javax.enterprise.event.Observes; @GET @Path("/json/cet/now")
Parameter Default Description
@Produces(MediaType.APPLICATION_JSON)
@ApplicationScoped @Retry(maxRetries = 2)
public class MyBean {
gzip.enabled false EnableGZip. WorldClock getNow();
}
public void filters(
Con gure the upper
@Observes Filters filters) {
gzip.max-input 10M limit on de ated
filters
request body. You can set fallback code in case of an error by using @Fallback
.register(
annotation:
rc -> {
rc.response()
.putHeader("X-Filter", "filter 1"); CORS Filter @Retry(maxRetries = 1)
rc.next(); @Fallback(fallbackMethod = "fallbackMethod")
}, Quarkus comes with a CORS lter that can be enabled via WorldClock getNow(){}
10); con guration:
} public WorldClock fallbackMethod() {
return new WorldClock();
quarkus.http.cors=true
public void routes( }
@Observes Router router) {
router
Pre x is quarkus.http .
.get("/") fallbackMethod must have the same parameters and return type as
.handler(rc -> rc.response().end("OK"));
Property Default Description the annotated method.
}
} You can also set logic into a class that implements FallbackHandler
cors false Enable CORS.
interface:
GZip Support
Quarkus relies on MicroPro le Health spec to provide health
@Bulkhead(5) @ApplicationScoped
checks.
@Retry(maxRetries = 4, public class DatabaseHealthCheck {
delay = 1000,
retryOn = BulkheadException.class) ./mvnw quarkus:add-extension @Produces
WorldClock getNow(){} -Dextensions="io.quarkus:quarkus-smallrye-health" @Liveness
HealthCheck check1() {
return io.smallrye.health.HealthStatus
By just adding this extension, an endpoint is registered to /health .up("successful-live");
Fault tolerance annotations:
providing a default health check. }
Annotation Properties
@Produces
{
@Readiness
@Timeout unit "status": "UP",
HealthCheck check2() {
"checks": [
return HealthStatus
]
.state("successful-read", this::isReady)
maxRetries , delay , delayUnit , }
}
maxDuration , durationUnit ,
@Retry
jitter , jitterDelayUnit , retryOn ,
private boolean isReady() {}
abortOn
To create a custom health check you need to implement the }
HealthCheck interface and annotate either with @Readiness (ready to
@Fallback fallbackMethod
process requests) or @Liveness (is running) annotations.
You can ping liveness or readiness health checks individually by
@Readiness querying /health/live or /health/ready .
waitingTaskQueue (only valid in public class DatabaseHealthCheck implements HealthCheck {
@Bulkhead
asynchronous) @Override Quarkus comes with some HealthCheck implementations for
public HealthCheckResponse call() { checking service status.
HealthCheckResponseBuilder responseBuilder =
failOn , delay , delayUnit , HealthCheckResponse.named("Database conn"); SocketHealthCheck: checks if host is reachable using a
@CircuitBreaker requestVolumeThreshold , socket.
failureRatio , successThreshold try {
checkDatabaseConnection(); UrlHealthCheck: checks if host is reachable using a Http URL
responseBuilder.withData("connection", true); connection.
@Asynchronous responseBuilder.up();
} catch (IOException e) {
InetAddressHealthCheck: checks if host is reachable using
InetAddress.isReachable method.
// cannot access the database
You can override annotation parameters via con guration le using responseBuilder.down()
property [classname/methodname/]annotation/parameter : .withData("error", e.getMessage()); @Produces
} @Liveness
org.acme.quickstart.WorldClock/getNow/Retry/maxDuration=30 return responseBuilder.build(); HealthCheck check1() {
# Class scope } return new UrlHealthCheck("https://www.google.com")
org.acme.quickstart.WorldClock/Retry/maxDuration=3000 } .name("Google-Check");
# Global }
Retry/maxDuration=3000
Tracks the frequency of This extension includes OpenTracing support and Jaeger tracer.
@Metered
invocations.
Jaeger tracer con guration:
Gauge to count parallel @Traced annotation can be set to disable tracing at class or method
@ConcurrentGauge
invocations. level.
./mvnw quarkus:add-extensions
namesapce Default namespace.
-Dextensions="io.quarkus:quarkus-kubernetes" proxy-username Proxy username.
ca-cert-file CA certi cate data.
proxy-password Proxy password.
Running ./mvnw package the Kubernetes resources are created at
target/kubernetes/ directory. client-cert-file Client certi cate le.
IP addresses or hosts
Property Default Description no-proxy to exclude from
Client certi cate proxying
client-cert-data
Set Docker data.
kubernetes.group Current username
Username.
Or programmatically:
client-key-data Client key data.
Current project
quarkus.application.name Project name @Dependent
name
client-key-algorithm Client key algorithm. public class KubernetesClientProducer {
@Produces
Generated resource is integrated with MicroPro le Health
annotations. client-key- Client key public KubernetesClient kubernetesClient() {
passphrase passphrase. Config config = new ConfigBuilder()
Also, you can customize the generated resource by setting the new .withMasterUrl("https://mymaster.com")
values in application.properties : .build();
username Username. return new DefaultKubernetesClient(config);
}
kubernetes.replicas=3
}
password Password.
kubernetes.labels[0].key=foo
kubernetes.labels[0].value=bar
And inject it on code:
kubernetes.readiness-probe.period-seconds=45
@Inject ./mvnw quarkus:add-extension mvn archetype:generate \
KubernetesClient client; -Dextensions="io.quarkus:quarkus-amazon-lambda" -DarchetypeGroupId=io.quarkus \
-DarchetypeArtifactId=quarkus-azure-functions-http-archet
ServiceList myServices = client.services().list(); ype \
-DarchetypeVersion={version}
And then implement
Service myservice = client.services()
com.amazonaws.services.lambda.runtime.RequestHandler interface.
.inNamespace("default")
.withName("myservice")
.get(); public class TestLambda
implements RequestHandler<MyInput, MyOutput> {
CustomResourceDefinitionList crds = client @Override
.customResourceDefinitions() public MyInput handleRequest(MyOutput input,
.list(); Context context) {
}
dummyCRD = new CustomResourceDefinitionBuilder() }
...
.build()
client.customResourceDefinitions() You can set the handler name by using quarkus.lambda.handler
.create(dummyCRD); property or by annotating the Lambda with the CDI @Named
annotation.
Test
Testing
You can write tests for Amazon lambdas:
Quarkus provides a Kubernetes Mock test resource that starts a
mock of Kubernetes API server and sets the proper environment
variables needed by Kubernetes Client. <dependency>
<groupId>io.quarkus</groupId>
Register next dependency: io.quarkus:quarkus-test-kubernetes- <artifactId>quarkus-test-amazon-lambda</artifactId>
client:test . <scope>test</scope>
</dependency>
@QuarkusTestResource(KubernetesMockServerTestResource.clas
s)
@QuarkusTest
@Test
public class KubernetesClientTest {
public void testLambda() {
MyInput in = new MyInput();
@MockServer
in.setGreeting("Hello");
private KubernetesMockServer mockServer;
in.setName("Stu");
MyOutput out = LambdaClient.invoke(MyOutput.class, in);
@Test
}
public void test() {
final Pod pod1 = ...
mockServer
.expect() To scaffold a AWS Lambda run:
.get()
.withPath("/api/v1/namespaces/test/pods") mvn archetype:generate \
.andReturn(200, -DarchetypeGroupId=io.quarkus \
new PodListBuilder() -DarchetypeArtifactId=quarkus-amazon-lambda-archetype \
.withNewMetadata() -DarchetypeVersion={version}
.withResourceVersion("1")
.endMetadata()
.withItems(pod1, pod2)
.build()) Azure Functions
.always();
} Quarkus can make a microservice be deployable to the Azure
} Functions.
Amazon Lambda
Quarkus integrates with Amazon Lambda.
Apache Camel You can customize the output by using Open API v3 annotations.
mailer.send(
Mail.withText("[email protected]", "Subject", "Body")
Apache Camel Quarkus has its own site: @Schema(name="Developers", );
https://github.com/apache/camel-quarkus description="POJO that represents a developer.")
public class Developer { CompletionStage<Void> stage =
WebSockets @Schema(required = true, example = "Alex") reactiveMailer.send(
private String name; Mail.withText("[email protected]", "Subject", "Body")
} );
Quarkus can be used to handling web sockets.
@POST
./mvnw quarkus:add-extension
@Path("/developer")
-Dextensions="io.quarkus:quarkus-undertow-websockets" Mail class contains methods to add cc , bcc , headers , bounce
@Operation(summary = "Create deeloper",
address , reply to , attachments , inline attachments and html body .
description = "Only be done by admin.")
public Response createDeveloper(
And web sockets classes can be used: @RequestBody(description = "Developer object", mailer.send(Mail.withHtml("[email protected]", "Subject", body)
required = true, .addInlineAttachment("quarkus.png",
content = @Content(schema = new File("quarkus.png"),
@ServerEndpoint("/chat/{username}")
@Schema(implementation = Developer.class))) "image/png", "<[email protected]>"));
@ApplicationScoped
public class ChatSocket { Developer developer)
@OnOpen If you need deep control you can inject Vert.x mail client
public void onOpen(Session session, All possible annotations can be seen at @Inject MailClient client;
@PathParam("username") String username) {} org.eclipse.micropro le.openapi.annotations package.
You need to con gure SMTP properties to be able to send an email:
@OnClose You can also serve OpenAPI Schema from static les instead of
public void onClose(..) {} dynamically generated from annotation scanning. [email protected]
quarkus.mailer.host=smtp.sendgrid.net
@OnError You need to put OpenAPIdocumentation under META-INF directory
quarkus.mailer.port=465
public void onError(..., Throwable throwable) {} (ie: META-INF/openapi.yaml ).
quarkus.mailer.ssl=true
quarkus.mailer.username=....
@OnMessage A request to /openapi will serve the combined OpenAPI document
from the static le and the generated from annotations. You can quarkus.mailer.password=....
public void onMessage(...) {}
disable the scanning documents by adding the next con guration
} property: mp.openapi.scan.disable=true .
List of Mailer parameters. quarkus. as a pre x is skipped in the next
Other valid document paths are: META-INF/openapi.yml , META- table.
INF/openapi.json , WEB-INF/classes/META-INF/openapi.yml , WEB-
OpenAPI INF/classes/META-INF/openapi.yaml , WEB-INF/classes/META-
INF/openapi.json .
Quarkus can expose its API description as OpenAPI spec and test it
using Swagger UI. Mail Sender
./mvnw quarkus:add-extension You can send emails by using Quarkus Mailer extension:
-Dextensions="io.quarkus:quarkus-smallrye-openapi"
./mvnw quarkus:add-extension
-Dextensions="io.quarkus:quarkus-mailer"
Web Resources
Any member is saved/restored automatically ( @State is not You need to de ne the datasource used by clustered mode
You can serve web resources with Quarkus. You need to place web mandatory). You can use @NotState to avoid behaviour. and also import the database tables following the Quartz
resources at src/main/resources/META-INF/resources and then they schema.
are accessible (ie http://localhost:8080/index.html) Transaction boundaries
By default static resources as served under the root context. You Declarative Qute
can change this by using quarkus.http.root-path property.
@NestedTopLevel : De nes that the container will create a new Qute is a templating engine designed speci cally to meet the
top-level transaction for each method invocation. Quarkus needs. Templates should be placed by default at
Transactional Memory src/main/resources/templates aand subdirectories.
@Nested : De nes that the container will create a new top-level
Quarkus integrates with the Software Transactional Memory (STM)
or nested transaction for each method invocation. ./mvnw quarkus:add-extension
implementation provided by the Narayana project.
-Dextensions="quarkus-resteasy-qute"
Programmatically
./mvnw quarkus:add-extension
-Dextensions="narayana-stm" AtomicAction aa = new AtomicAction();
Templates can be de ned in any format, in case of HTML:
aa.begin(); item.html
Transactional objects must be interfaces and annotated with {
org.jboss.stm.annotations.Transactional . try { {@org.acme.Item item}
flightService.makeBooking("BA123 ..."); <!DOCTYPE html>
taxiService.makeBooking("East Coast Taxis ..."); <html>
@Transactional
<head>
@NestedTopLevel
aa.commit(); <meta charset="UTF-8">
public interface FlightService {
} catch (Exception e) { <title>{item.name}</title>
int getNumberOfBookings();
aa.abort(); </head>
void makeBooking(String details);
} <body>
}
} <h1>{item.name}</h1>
<div>Price: {item.price}</div>
{#if item.price > 100}
The pessimistic strategy is the default one, you can change to <div>Discounted Price: {item.discountedPrice}</div>
optimistic by using @Optimistic . Quartz {/if}
</body>
Then you need to create the object inside org.jboss.stm.Container . Quarkus integrates with Quartz to schedule periodic clustered </html>
tasks.
Container<FlightService> container = new Container<>();
FlightServiceImpl instance = new FlightServiceImpl(); ./mvnw quarkus:add-extension First line is not mandatory but helps on doing property checks at
FlightService flightServiceProxy = container.create(instanc -Dextensions="quartz" compilation time.
e);
To render the template: Full list of con guration properties having quarkus.log as pre x: Spring DI
sentry.enable
public class Item { Quarkus provides a compatibility layer for Spring dependency
public String name; Enable the Sentry logging extension (default: false) injection.
public BigDecimal price;
} sentry.dsn
./mvnw quarkus:add-extension
Where to send events. -Dextensions="quarkus-spring-di"
@Inject
io.quarkus.qute.Template item; sentry.level
Log level (default: WARN ) Some examples of what you can do. Notice that annotations are
@GET
@Path("{id}") the Spring original ones.
sentry.in-app-packages
@Produces(MediaType.TEXT_HTML)
public TemplateInstance get(@PathParam("id") Integer id) { Con gure which package pre xes your application uses. @Configuration
return item.data("item", service.findItem(id)); public class AppConfiguration {
}
@Bean(name = "capitalizeFunction")
@TemplateExtension public StringFunction capitalizer() {
static BigDecimal discountedPrice(Item item) { return String::toUpperCase;
return item.price.multiply(new BigDecimal("0.9")); }
} }
Or as a component:
If @ResourcePath is not used in Template then the name of the eld is
used as le name. In this case the le should be
@Component("noopFunction")
src/main/resources/templates/item.{} . Extension of the le is not
public class NoOpSingleStringFunction
required to be set.
implements StringFunction {
discountedPrice
is not a eld of the POJO but a method call. }
Method de nition must be annotated with @TemplateExtension . First
paramter is used to match thebase object.
Also as a service and injection properties from
You can render programmaticaly too: application.properties .
Quarkus integrates with Sentry for logging errors into an error @Component
monitoring system. public class GreeterBean {
./mvnw quarkus:add-extension private final MessageProducer messageProducer;
-Dextensions="quarkus-logging-sentry"
@Autowired @Qualifier("noopFunction")
StringFunction noopStringFunction;
And the con guration to send all errors occuring in the package
public GreeterBean(MessageProducer messageProducer) {
org.example to Sentrty with DSN https://[email protected]/1234 :
this.messageProducer = messageProducer;
}
quarkus.log.sentry=true }
quarkus.log.sentry.dsn=https://[email protected]/1234
quarkus.log.sentry.level=ERROR
quarkus.log.sentry.in-app-packages=org.example
Spring Web ./mvnw quarkus:add-extension
public interface FruitRepository -Dextensions="spring-security"
Quarkus provides a compatibility layer for Spring Web. extends CrudRepository<Fruit, Long> {
List<Fruit> findByColor(String color);
}
./mvnw quarkus:add-extension You need to choose a security extension to de ne user, roles, …
-Dextensions="quarkus-spring-web" such as openid-connect , oauth2 , properties-file or security-jdbc
as seen at RBAC.
And then you can inject it either as shown in Spring DI or in Spring
Web. Then you can use Spring Security annotations to protect the
Speci cally supports the REST related features. Notice that
infrastructure things like BeanPostProcessor will not be executed. methods:
Interfaces supported:
org.springframework.data.repository.Repository @Secured("admin")
@RestController
@GetMapping
@RequestMapping("/greeting")
org.springframework.data.repository.CrudRepository public String hello() {
public class GreetingController {
return "hello";
org.springframework.data.repository.PagingAndSortingReposito }
private final GreetingBean greetingBean;
ry
public GreetingController(GreetingBean greetingBean) {
org.springframework.data.jpa.repository.JpaRepository .
this.greetingBean = greetingBean; Quarkus provides support for some of the most used features of
} INFO: Generated repositories are automatically annotated with Spring Security’s @PreAuthorize annotation.
@Transactional .
@GetMapping("/{name}") Some examples:
public Greeting hello(@PathVariable(name = "name") Repository fragments is also supported:
String name) { hasRole
return new Greeting(greetingBean.greet(name));
public interface PersonRepository @PreAuthorize("hasRole('admin')")
}
extends JpaRepository<Person, Long>, PersonFragment {
}
@PreAuthorize("hasRole(@roles.USER)") where roles is a bean
void makeNameUpperCase(Person person); de ned with @Component annotation and USER is a public eld
} of the class.
Supported annotations are: RestController , RequestMapping ,
GetMapping , PostMapping , PutMapping , DeleteMapping , PatchMapping , hasAnyRole
RequestParam , RequestHeader , MatrixVariable , PathVariable ,
User de ned queries:
CookieValue , RequestBody , ResponseStatus , ExceptionHandler and @PreAuthorize("hasAnyRole(@roles.USER, 'view')")
RestControllerAdvice .
@Query("select m from Movie m where m.rating = ?1") Permit and Deny All
If you scaffold the project with spring-web extension, then Iterator<Movie> findByRating(String rating);
@PreAuthorize("permitAll()")
Spring Web annotations are sed in the generated project.
mvn io.quarkus:quarkus-maven-plugin:1.1.0.Final:create …
- @Modifying
@PreAuthorize("denyAll()")
Dextensions="spring-web" . @Query("delete from Movie where rating = :rating")
void deleteByRating(@Param("rating") String rating);
Anonymous and Authenticated
The next return types are supported:
org.springframework.http.ResponseEntity and java.util.Map . @PreAuthorize("isAnonymous()")
What is currently unsupported:
The next parameter types are supported: An Exception argument @PreAuthorize("isAuthenticated()")
and ServletRequest / HttpServletRequest (adding quarkus-undertow Methods of
dependency). org.springframework.data.repository.query.QueryByExampleExec Expressions
utor
Checks if the current logged in user is the same as the
Spring Data JPA username method parameter:
QueryDSL support
While users are encouraged to use Hibernate ORM with Panache
Customizing the base repository @PreAuthorize("#person.name == authentication.principal.use
for Relational Database access, Quarkus provides a compatibility
layer for Spring Data JPA repositories. rname")
java.util.concurrent.Future as return type
public void doSomethingElse(Person person){}
INFO: Of course you still need to add the JDBC driver, and con gure Quarkus provides a compatibility layer for Spring Security.
it in application.properties .
@PreAuthorize("@personChecker.check(#person, authenticatio Resources
n.principal.username)")
public void doSomething(Person person){} https://quarkus.io/guides/
@Component https://www.youtube.com/user/lordofthejars
public class PersonChecker {
public boolean check(Person person, String username) { Authors :
return person.getName().equals(username);
} @alexsotob
} Java Champion and Director of DevExp at Red Hat
1.1.0.Final
Combining expressions: