QuarkusCheat-Sheet
WhatisQuarkus?
Quarkus isaKubernetesNativeJavastacktailoredforGraalVM&OpenJDKHotSpot,craftedfromthebestofbreedJavalibrariesandstandards. Also focused on developer experience, making thingsjust work with little to no con�guration and allowing to do livecoding.
Cheat-sheettestedwithQuarkus1.13.0.Final.
GettingStarted
QuarkuscomeswithaMavenarchetype toscaffoldaverysimplestartingproject.
mvnio.quarkus:quarkus-maven-plugin:1.13.0.Final:create\
-DprojectGroupId=org.acme\
-DprojectArtifactId=getting-started\
-DclassName="org.acme.quickstart.GreetingResource"\
-Dpath="/hello"
ThiscreatesasimpleJAX-RSresourcecalledGreetingResource .
@Path("/hello")publicclassGreetingResource{
@GET@Produces(MediaType.TEXT_PLAIN)publicStringhello(){return"hello";}
}
Gradle
ThereisnowaytoscaffoldaprojectinGradlebutyouonlyneedtodo:
plugins{
id'java'
id'io.quarkus'version'0.26.1'
}
repositories{
mavenCentral()
}
dependencies{
implementation enforcedPlatform('io.quarkus:quarkus-bo
m:0.26.1')
implementation'io.quarkus:quarkus-resteasy'
}
OrinKotlin:
plugins{
java
}
apply(plugin="io.quarkus")
repositories{
mavenCentral()
}
dependencies{
implementation(enforcedPlatform("io.quarkus:quarkus-bo
m:0.26.1"))
implementation("io.quarkus:quarkus-resteasy")
}
Packaging
mvncleanpackage
You need to distribute the -runner.jar �le together with quarkus-app directory.
If quarkus.package.uber-jar propertyissettotrue,thenauber-jariscreatedwithalldependenciesbundledinsidetheJAR.
Bydefault,Quarkususesfastjarpackaging,if quarkus.package.typepropertyissetto legacy-jar thenQuarkuscreatestheoldstandardjar�le.
application.properties
quarkus.package.uber-jar=truequarkus.package.type=legacy-jar
To compile to native, you need to set GRAALVM_HOME environmentvariableandrunthenative pro�le.
mvncleanpackage-Pnative
./gradlewbuild-Dquarkus.package.type=native
Possible quarkus.package.type are: jar , legacy-jar , uber-jar andnative .
AppCDS
AutomaticallygenerateAppCDSaspartofthebuildprocesssetthenextproperty:quarkus.package.create-appcds=true .
To make use of it, just run java -jar -XX:SharedArchiveFile=app-cds.jsamyapp.jar .
Commandmode
Youcande�nethemain CLImethodtostartQuarkus.Therearetwoways, implementing io.quarkus.runtime.QuarkusApplication
interfaceorusetheJavamainmethodtolaunchQuarkus.
@io.quarkus.runtime.annotations.QuarkusMainpublicclassHelloWorldMainimplementsQuarkusApplication{@Overridepublicintrun(String...args)throwsException{System.out.println("HelloWorld");
return10;}
}
run methodcalledwhenQuarkusstarts,andstopswhenit�nishes.
AsJavamain :
@QuarkusMainpublicclassJavaMain{publicstaticvoidmain(String...args){Quarkus.run(HelloWorldMain.class,args);
}
}
Use@QuarkusMain inonlyoneplace.
Use Quarkus.waitForExit() fromthemainthreadifyouwanttorunsome logiconstartup,and then run likeanormalapplication (i.e.notexit).
You can inject command line arguments by using@CommandLineArguments annotation:
@CommandLineArgumentsString[]args;
Picocli
YoucanusePicoclitoimplementCLIapplications:
./mvnwquarkus:add-extension
-Dextensions="picocli"
@CommandLine.CommandpublicclassHelloCommandimplementsRunnable{
@CommandLine.Option(names={"-n","--name"},description="Whowillwegreet?",defaultValue="World")
Stringname;
privatefinalGreetingServicegreetingService;
publicHelloCommand(GreetingServicegreetingService){this.greetingService=greetingService;}
@Overridepublicvoidrun(){greetingService.sayHello(name);
}
}
All classes annotated with picocli.CommandLine.Command areregisteredasCDIbeans.
Ifonlyoneclassannotatedwith picocli.CommandLine.Command itwillbe used as entry point. If you want to provide your own@QuarkusMain :
@[email protected](name="demo",mixinStandardHelpOptions=true)publicclassExampleAppimplementsRunnable,QuarkusApplication{
@InjectCommandLine.IFactoryfactory;
@Overridepublicvoidrun(){}
@Overridepublicintrun(String...args)throwsException{returnnewCommandLine(this, factory).execute(args);
}
}
Use quarkus.picocli.native-image.processing.enable to false tousethepicocli-codegen annotationprocessorinsteadofbuildsteps.
Youcanalsocon�gureCDIbeanswithPicoCLIarguments:
@CommandLine.CommandpublicclassEntryCommandimplementsRunnable{@CommandLine.Option(names="-c",description="JDBCconnectionstring")
StringconnectionString;
@InjectDataSourcedataSource;
}
@ApplicationScopedclassDatasourceConfiguration{
@Produces@ApplicationScopedDataSourcedataSource(CommandLine.ParseResultparseResult){
System.out.println(parseResult.matchedOption("c").g
etValue().toString());
}
}
Extensions
Quarkus comes with extensions to integrate with some librariessuch as JSON-B, Camel orMicroPro�le spec. To list all availableextensionsjustrun:
./mvnwquarkus:list-extensions
You can use -DsearchPattern=panache to �lter out allextensionsexcepttheonesmatchingtheexpression.
Andtoregistertheextensionsintobuildtool:
./mvnwquarkus:add-extension-Dextensions=""
./mvnwquarkus:remove-extension-Dextensions=""
extensions propertysupportsCSV format to registermorethanoneextensionatonce.
ApplicationLifecycle
Youcanbenoti�edwhentheapplicationstarts/stopsbyobservingStartupEvent andShutdownEvent events.
@ApplicationScopedpublicclassApplicationLifecycle{voidonStart(@ObservesStartupEventevent){}voidonStop(@ObservesShutdownEventevent){}}
Quarkussupportsgracefulshutdown.Bydefaultthereisnotimeoutbut can be set by using the quarkus.shutdown.timeout con�g
DevMode
./mvnwcompilequarkus:dev
./gradlewquarkusDev
Endpoints are registered automatically to provide some basicdebuginfoindevmode:
HTTPGET/quarkus/arc/beans
QueryParameters:scope ,beanClass ,kind .
HTTPGET/quarkus/arc/observers
DevUI
QuarkusaddsaDevUIconsoletoexposeextensionfeatures.
The Dev UI is available in dev mode only and accessible at the/q/dev endpointbydefault.
AddingCon�gurationParameters
To add con�guration to your application, Quarkus relies onMicroPro�leCon�gspec.
@ConfigProperty(name="greetings.message")Stringmessage;
@ConfigProperty(name="greetings.message",defaultValue="Hello")
StringmessageWithDefault;
@ConfigProperty(name="greetings.message")Optional<String>optionalMessage;
Propertiescanbeset(indecreasingpriority)as:
Systemproperties(-Dgreetings.message ).
Environmentvariables(GREETINGS_MESSAGE ).
Environment �le named .env placed in the current workingdirectory(GREETING_MESSAGE= ).
External con�gdirectory under the currentworking directory:config/application.properties .
Resourcessrc/main/resources/application.properties .
greetings.message=HelloWorld
Array ,List and Set aresupported.Thedelimiteriscomma(, )charand\ istheescapechar.
Con�gurationPro�les
Quarkus allow you to havemultiple con�guration in the same�le(application.properties ).
Thesyntaxforthisis%{profile}.config.key=value .
quarkus.http.port=9090%dev.quarkus.http.port=8181
HTTPportwillbe9090,unlessthe'dev'pro�leisactive.
Defaultpro�lesare:
dev :Activatedwhenindevelopmentmode(quarkus:dev ).
test :Activatedwhenrunningtests.
prod :Thedefaultpro�lewhennot running indevelopmentortestmode
Youcancreatecustompro�lenamesbyenablingthepro�leeithersetting quarkus.profile system property or QUARKUS_PROFILE
environmentvariable.
quarkus.http.port=9090%staging.quarkus.http.port=9999
Andenableitquarkus.profile=staging .
To get the active pro�le programmatically useio.quarkus.runtime.configuration.ProfileManager.getActiveProfile() .
Youcanalsosetitinthebuildtool:
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<quarkus.test.profile>foo</quarkus.test.profile>
<buildDirectory>${project.build.directory}
</buildDirectory>
</systemPropertyVariables>
</configuration>
Sameformaven-failsafe-plugin .
test{
useJUnitPlatform()
systemProperty"quarkus.test.profile","foo"
}
Special properties are set in prod mode:quarkus.application.version and quarkus.application.name to getthemavailableatruntime.
@ConfigProperty(name="quarkus.application.name")StringapplicationName;
Additionallocations
You can use smallrye.config.locations property to set additionalcon�guration�les.
smallrye.config.locations=config.properties
or
java-jar-Dsmallrye.config.locations=config.properties
Youcanembedcon�guration�les insideadependencybyaddingMETA-INF/microprofile.properties insidetheJAR.Whendependencyis added to the application, con�guration properties are mergedwithcurrentcon�guration.
@Con�gProperties
Asanalternative to injectingmultiple relatedcon�gurationvalues,you can also use the @io.quarkus.arc.config.ConfigProperties
annotationtogroupproperties.
@ConfigProperties(prefix="greeting",namingStrategy=NamingStrategy.KEBAB_CASE)
publicclassGreetingConfiguration{privateStringmessage;//getter/setter
}
This class maps greeting.message property de�ned inapplication.properties .
YoucaninjectthisclassbyusingCDI@InjectGreetingConfigurationgreeting; .
Alsoyoucanuseaninterfaceapproach:
@ConfigProperties(prefix="greeting",namingStrategy=NamingStrategy.KEBAB_CASE)
publicinterfaceGreetingConfiguration{
@ConfigProperty(name="message")Stringmessage();StringgetSuffix();
If property does not follow getter/setter naming convention youneed to use org.eclipse.microprofile.config.inject.ConfigPropertytosetit.
Nestedobjectsarealsosupporte:
@ConfigProperties(prefix="greeting",namingStrategy=NamingStrategy.KEBAB_CASE)
publicclassGreetingConfiguration{publicStringmessage;publicHiddenConfighidden;
publicstaticclassHiddenConfig{publicList<String>recipients;}
}
Andanapplication.properties mappingpreviousclass:
greeting.message=hellogreeting.hidden.recipients=Jane,John
Bean Validation is also supported so properties are validated atstartuptime,forexample@Size(min=20)publicStringmessage; .
prefix attribute isnotmandatory. Ifnotprovided,attributeis determined by class name (ie GreeetingConfiguration istranslated to greeting or GreetingExtraConfiguration togreeting-extra ).Thesu�xoftheclassisalwaysremoved.
Naming strategy can be changed with property namingStrategy .KEBAB_CASE (whatever.foo-bar)orVERBATIM (whatever.fooBar).
@io.quarkus.arc.config.ConfigIgnore annotation can be used toignoretheinjectionofcon�gurationelements.
@ConfigIgnorepublicIntegerignored;
YAMLCon�g
YAML con�guration is also supported. The con�guration �le iscalled application.yaml and youneed to register adependency toenableitssupport:
pom.xml
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-config-yaml</artifactId>
</dependency>
quarkus:
datasource:
url:jdbc:postgresql://localhost:5432/some-database
driver:org.postgresql.Driver
Orwithpro�les:
"%dev":
quarkus:
datasource:
url:jdbc:postgresql://localhost:5432/some-database
driver:org.postgresql.Driver
Incaseofsubkeys~ isusedtorefertotheunpre�xedpart.
quarkus:
http:
cors:
~:true
methods:GET,PUT,POST
Isequivalentto:
quarkus.http.cors=truequarkus.http.cors.methods=GET,PUT,POST
CustomLoader
You can implement your own ConfigSource to load con�gurationfrom different places than the default ones provided by Quarkus.Forexample,database,customXML,RESTEndpoints,…
You need to create a new class and implement ConfigSource
interface:
packagecom.acme.config;publicclassInMemoryConfigimplementsConfigSource{
privateMap<String,String>prop=newHashMap<>();
publicInMemoryConfig(){//Initproperties
}
@OverridepublicintgetOrdinal(){//Thehighestordinaltakesprecedence
return900;}
@OverridepublicMap<String,String>getProperties(){returnprop;}
@OverridepublicStringgetValue(StringpropertyName){returnprop.get(propertyName);}
@OverridepublicStringgetName(){return"MemoryConfigSource";}
}
Thenyouneedtoregisterthe ConfigSource asJavaservice.Createa�lewiththefollowingcontent:
/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource
com.acme.config.InMemoryConfig
CustomConverters
You can implement your own conversion types from String.Implement org.eclipse.microprofile.config.spi.Converter
interface:
@Priority(DEFAULT_QUARKUS_CONVERTER_PRIORITY+100)publicclassCustomInstantConverterimplementsConverter<Instant>{
@OverridepublicInstantconvert(Stringvalue){if("now".equals(value.trim())){returnInstant.now();}
returnInstant.parse(value);}
}
@Priority annotation is used to override the defaultInstantConverter .
Thenyouneed to register the Converter asJavaservice.Createa�lewiththefollowingcontent:
/META-INF/services/org.eclipse.microprofile.config.spi.Converter
com.acme.config.CustomInstantConverter
UndertowProperties
Possibleparameterswithpre�xquarkus.servlet :
context-path
ThecontextpathtoserveallServletcontextfrom.(default:/ )
default-charset
The default charset to use for reading and writing requests.(default:UTF-8 )
Injection
Quarkus is basedonCDI2.0 to implement injectionof code. It isnot fully supported and only a subset of the speci�cation isimplemented.
@ApplicationScopedpublicclassGreetingService{
publicStringmessage(Stringmessage){returnmessage.toUpperCase();}
}
Scopeannotationismandatorytomakethebeandiscoverable.
@InjectGreetingServicegreetingService;
Quarkus is designed with Substrate VM in mind. For thisreason, we encourage you to use package-private scopeinsteadofprivate.
Produces
You can also create a factory of an object by [email protected] annotation.
@Produces@ApplicationScopedMessagemessage(){Messagem=newMessage();m.setMsn("Hello");
returnm;}
@InjectMessagemsg;
Quali�ers
You can use quali�ers to return different implementations of thesameinterfaceortocustomizethecon�gurationofthebean.
@Qualifier@Retention(RUNTIME)@Target({TYPE,METHOD,FIELD,PARAMETER})public@interfaceQuote{@NonbindingStringvalue();}
@Produces@Quote("")Messagemessage(InjectionPointmsg){Messagem=newMessage();m.setMsn(
msg.getAnnotated()
.getAnnotation(Quote.class)
.value()
);
returnm;}
@Inject@Quote("AlohaBeach")Messagemessage;
Quarkus breaks the CDI spec by allowing you to injectquali�edbeanswithoutusing@Inject annotation.
@Quote("AlohaBeach")Messagemessage;
Quarkus breaks the CDI spec by skipping the @Producesannotationcompletelyiftheproducermethodisannotatedwithascopeannotation,astereotypeoraquali�er.
@Quote("")Messagemessage(InjectionPointmsg){}
@Quote("AlohaBeach")Messagemessage;
Alternatives
It is also possible to select alternatives for an application usingapplication.properties .
quarkus.arc.selected-alternatives=org.acme.Foo,org.acme.*,Bar
BeansbyQuarkusPro�le
Using @io.quarkus.arc.profile.IfBuildProfile [email protected] annotations, you canconditionallyenableabean.
@DependentpublicclassTracerConfiguration{@Produces@IfBuildProfile("prod")publicTracerrealTracer(Reporterreporter,Configurationconfiguration){
returnnewRealTracer(reporter,configuration);}
@Produces@DefaultBeanpublicTracernoopTracer(){returnnewNoopTracer();}
}
Using @io.quarkus.arc.profile.IfBuildProperty annotation, youcanconditionally enable a bean. @io.quarkus.arc.DefaultBean sets thedefaultbean.
@DependentpublicclassTracerConfiguration{@Produces@IfBuildProperty(name="some.tracer.enabled",stringValue="true")
publicTracerrealTracer(Reporterreporter,Configurationconfiguration){}
@Produces@DefaultBeanpublicTracernoopTracer(){}}
Propertiessetat runtimehaveabsolutelynoeffecton thebeanresolutionusing@IfBuildProperty .
Container-managedConcurrency
Quarkusprovides @io.quarkus.arc.Lock andabuilt-ininterceptorforconcurrencycontrol.
@Lock@ApplicationScopedclassSharedService{
voidaddAmount(BigDecimalamout){}
@Lock(value=Lock.Type.READ,time=1,unit=TimeUnit.SECONDS)
BigDecimalgetAmount(){}
}
By default the class is in write mode (so no concurrent callsallowed)exceptwhen lock type is READ where themethodcanbecalledconcurrentlyifnowriteoperationinprocess.
JSON Marshalling/Unmarshalling
ToworkwithJSON-B youneedtoaddadependency:
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-resteasy-jsonb"
AnyPOJOismarshaled/unmarshalledautomatically.
publicclassSauce{privateStringname;privatelongscovilleHeatUnits;
//getter/setters
}
JSONequivalent:
{
"name":"Blair'sUltraDeath",
"scovilleHeatUnits":1100000
}
InaPOST endpointexample:
@POST@Consumes(MediaType.APPLICATION_JSON)publicResponsecreate(Saucesauce){//CreateSauce
returnResponse.created(URI.create(sauce.getId())).build();
}
ToprovidecustomJsonBCon�gobject:
@DependentJsonbConfig jsonConfig(Instance<JsonbConfigCustomizer> customizers){
JsonbConfigconfig=myJsonbConfig();//Custom`JsonbC
onfig`
for(JsonbConfigCustomizercustomizer:customizers){customizer.customize(config);
}
returnconfig;}
ToworkwithJackson youneedtoadd:
./mvnwquarkus:add-extension
-Dextensions="quarkus-resteasy-jackson"
Ifyoudon’twanttousethedefaultObjectMapper youcancustomizeitby:
@ApplicationScopedpublicclassCustomObjectMapperConfig{@Singleton@ProducespublicObjectMapperobjectMapper(Instance<ObjectMapperCustomizer>customizers){
ObjectMapperobjectMapper=newObjectMapper();//performconfiguration
for(ObjectMapperCustomizercustomizer:customizers){
customizer.customize(mapper);
}
returnobjectMapper;}
}
DefaultmediatypeinQuarkusRestEasyisJSON.
XMLMarshalling/Unmarshalling
ToworkwithJAX-B youneedtoaddadependency:
./mvnwquarkus:add-extension
-Dextensions="quarkus-resteasy-jaxb"
ThenannotatedPOJOsareconvertedtoXML.
@XmlRootElementpublicclassMessage{}
@GET@Produces(MediaType.APPLICATION_XML)publicMessagehello(){returnmessage;}
JAXP
ToworkwithJAX-P youneedtoaddadependency:
./mvnwquarkus:add-extension
-Dextensions="jaxp"
finalDocumentBuilderdBuilder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
finalDocumentdoc=dBuilder.parse(in);returndoc.getDocumentElement().getTextContent();
Validator
QuarkususesHibernateValidatortovalidateinput/outputofRESTservicesandbusinessservicesusingBeanvalidationspec.
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-hibernate-validator"
Annotate POJO objects with validator annotations such as:@NotNull ,@Digits ,@NotBlank ,@Min ,@Max ,…
publicclassSauce{
@NotBlank(message="Namemaynotbeblank")privateStringname;@Min(0)privatelongscovilleHeatUnits;
//getter/setters
}
Tovalidateanobjectuse@Valid annotation:
publicResponsecreate(@ValidSaucesauce){}
If a validation error is triggered, a violation report isgenerated and serialized as JSON. If you want tomanipulate the output, you need to catch in the code theConstraintViolationException exception.
CreateYourCustomConstraints
Firstyouneedtocreatethecustomannotation:
@Target({METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})
@Retention(RUNTIME)@Documented@Constraint(validatedBy={NotExpiredValidator.class})public@interfaceNotExpired{
Stringmessage()default"Saucemustnotbeexpired";Class<?>[]groups()default{};Class<?extendsPayload>[]payload()default{};
}
You need to implement the validator logic in a class thatimplementsConstraintValidator .
publicclassNotExpiredValidatorimplementsConstraintValidator<NotExpired,LocalDate>{
@OverridepublicbooleanisValid(LocalDatevalue,ConstraintValidatorContextctx){
if(value==null)returntrue;LocalDatetoday=LocalDate.now();
returnChronoUnit.YEARS.between(today,value)>0;}
}
Anduseitnormally:
@NotExpired@JsonbDateFormat(value="yyyy-MM-dd")privateLocalDateexpired;
ManualValidation
Youcancallthevalidationprocessmanuallyinsteadofrelayingto@Valid byinjectingValidator class.
@InjectValidatorvalidator;
Anduseit:
Set<ConstraintViolation<Sauce>>violations=
validator.validate(sauce);
Localization
Youcancon�gurethebasedlocaleforvalidationmessages.
quarkus.default-locale=ca-ES#SupportedlocalesresolvedbyAccept-Language
quarkus.locales=en-US,es-ES,fr-FR,ca_ES
ValidationMessages_ca_ES.properties
pattern.message=Noconformealpatro
@Pattern(regexp="A.*",message="{pattern.message}")privateStringname;
Bean Validation can be con�gured . The pre�x is:quarkus.hibernate-validator .
fail-fast
When fail fast is enabled the validation will stop on the �rstconstraintviolationdetected.(default:false )
method-validation.allow-overriding-parameter-constraints
De�ne whether overriding methods that override constraintsshouldthrowanexception.(default:false ).
method-validation.allow-parameter-constraints-on-parallel-methods
De�ne whether parallelmethods that de�ne constraints shouldthrowanexception.(default:false ).
method-validation.allow-multiple-cascaded-validation-on-return-
values
De�newhethermore thanoneconstraintona returnvaluemaybemarkedforcascadingvalidationareallowed.(default:false ).
Logging
Youcancon�gurehowQuarkuslogs:
quarkus.log.console.enable=truequarkus.log.console.level=DEBUGquarkus.log.console.color=falsequarkus.log.category."com.lordofthejars".level=DEBUG
Pre�xisquarkus.log .
category."<category-name>".level
Minimumlevelcategory(default:INFO )
level
Defaultminimumlevel(default:INFO )
console.enabled
Consoleloggingenabled(default:true )
console.format
Formatpatterntouseforlogging.Defaultvalue:%d{yyyy-MM-ddHH:mm:ss,SSS}%-5p[%c{3.}](%t)%s%e%n
console.level
Minimumloglevel(default:INFO )
console.color
Allowcolorrendering(default:true )
file.enable
Fileloggingenabled(default:false )
file.format
Formatpatterntouseforlogging.Defaultvalue:%d{yyyy-MM-ddHH:mm:ss,SSS}%h%N[%i]%-5p[%c{3.}](%t)%s%e%n
file.level
Minimumloglevel(default:ALL )
file.path
Thepathtolog�le(default:quarkus.log )
file.rotation.max-file-size
Themaximum�lesizeofthelog�le
file.rotation.max-backup-index
Themaximumnumberofbackupstokeep(default:1 )
file.rotation.file-suffix
Rotatinglog�lesu�x.
file.rotation.rotate-on-boot
Indicatesrotatelogsatbootup(default:true )
file.async
Logasynchronously(default:false )
file.async.queue-length
Thequeuelengthtousebefore�ushingwriting(default:512 )
file.async.overflow
Actionwhenqueueisfull(default:BLOCK )
syslog.enable
syslogloggingisenabled(default:false )
syslog.format
Theformatpatterntouseforloggingtosyslog.Defaultvalue:%d{yyyy-MM-ddHH:mm:ss,SSS}%h%N[%i]%-5p[%c{3.}](%t)%s%e%n
syslog.level
Theminimumlogleveltowritetosyslog(default:ALL )
syslog.endpoint
The IP address and port of the syslog server (default:localhost:514 )
syslog.app-name
The app name usedwhen formatting themessage in RFC5424format(default:currentprocessname)
syslog.hostname
Thenameofthehostthemessagesarebeingsentfrom(default:currenthostname)
syslog.facility
Priority of themessage as de�ned by RFC-5424 and RFC-3164(default:USER_LEVEL )
syslog.syslog-type
Thesyslogtypeofformatmessage(default:RFC5424 )
syslog.protocol
Protocolused(default:TCP )
syslog.use-counting-framing
Messagepre�xedwiththesizeofthemessage(defaultfalse )
syslog.truncate
Messageshouldbetruncated(default:true )
syslog.block-on-reconnect
Blockwhenattemptingtoreconnect(default:true )
syslog.async
Logasynchronously(default:false )
syslog.async.queue-length
Thequeuelengthtousebefore�ushingwriting(default:512 )
syslog.async.overflow
Actionwhenqueueisfull(default:BLOCK )
Youcaninjectloggerinstance:
importorg.jboss.logging.Logger;importio.quarkus.arc.log.LoggerName;
@InjectLoggerlog;
@LoggerName("foo")LoggerfooLog;
publicvoidping(){log.info("Simple!");
}
Gelfouput
Youcancon�guretheoutputtobeinGELFformatinsteadofplaintext.
./mvnwquarkus:add-extension
-Dextensions="quarkus-logging-gelf"
handler.gelf.enabled
EnableGELFlogginghandler(default:false )
handler.gelf.host
Hostname/IP of Logstash/Graylof. Prepend tcp: for using TCPprotocol.(default:udp:localhost )
handler.gelf.port
Theport.(default:12201 )
handler.gelf.version
GELFversion.(default:1.1 )
handler.gelf.extract-stack-trace
PostStack-TracetoStackTrace�eld.(default:true )
handler.gelf.stack-trace-throwable-reference
Getsthecauseleveltostacktrace. 0 isfullstacktrace.(default:)
handler.gelf.filter-stack-trace
Stack-Trace�ltering.(default:false )
handler.gelf.timestamp-pattern
JavaDatepattern.(default:yyyy-MM-ddHH:mm:ss,SSS )
handler.gelf.level
Logleveljava.util.logging.Level .(default:ALL )
handler.gelf.facility
Nameofthefacility.(default:jboss-logmanage )
handler.gelf.additional-field.<field>.<subfield>
Post additional �elds. quarkus.log.handler.gelf.additional-
field.field1.type=String
handler.gelf.include-full-mdc
Includeall�eldsfromtheMDC.
handler.gelf.maximum-message-size
Maximummessagesize(inbytes).(default:8192 )
handler.gelf.include-log-message-parameters
Includemessageparametersfromthelogevent.(default:true )
handler.gelf.include-location
Includesourcecodelocation.(default:true )
JSONoutput
Youcancon�guretheoutputtobeinJSONformatinsteadofplaintext.
./mvnwquarkus:add-extension
-Dextensions="quarkus-logging-json"
Andthecon�gurationvaluesarepre�xwithquarkus.log :
json
JSONloggingisenabled(default:true).
json.pretty-print
JSONoutputis"pretty-printed"(default:false)
json.date-format
Specifythedateformattouse(default:thedefaultformat)
json.record-delimiter
Recorddelimitertoadd(default:nodelimiter)
json.zone-id
ThetimezoneID
json.exception-output-type
The exception output type: detailed , formatted , detailed-and-
formatted (default:detailed )
json.print-details
Detailedcallerinformationshouldbelogged(default:false)
RestClient
QuarkusimplementsMicroPro�leRestClientspec:
./mvnwquarkus:add-extension
-Dextensions="quarkus-rest-client"
To get content from http://worldclockapi.com/api/json/cet/nowyouneedtocreateaserviceinterface:
@Path("/api")@RegisterRestClientpublicinterfaceWorldClockService{
@GET@Path("/json/cet/now")@Produces(MediaType.APPLICATION_JSON)WorldClockgetNow();
@GET@Path("/json/{where}/now")@Produces(MediaType.APPLICATION_JSON)WorldClockgetSauce(@BeanParamWorldClockOptionsworldClockOptions);
}
publicclassWorldClockOptions{@HeaderParam("Authorization")Stringauth;
@PathParam("where")Stringwhere;
}
Andcon�gurethehostnameatapplication.properties :
org.acme.quickstart.WorldClockService/mp-rest/url=http://worldclockapi.com
Injectingtheclient:
@RestClientWorldClockServiceworldClockService;
If invokation happens within JAX-RS, you can propagate headersfromincomingtooutgoingbyusingnextproperty.
org.eclipse.microprofile.rest.client.propagateHeaders=Authorization,MyCustomHeader
You can still use the JAX-RS client without any problemClientBuilder.newClient().target(…)
Addingheaders
You can customize the headers passed by implementingMicroPro�leClientHeadersFactory annotation:
@RegisterForReflectionpublicclassBaggageHeadersFactoryimplementsClientHeadersFactory{@OverridepublicMultivaluedMap<String,String>update(MultivaluedMap<String,String>incomingHeaders,
MultivaluedMap<String,String>outgoingHeaders){}
}
And registering it in the client using RegisterClientHeaders
annotation.
@RegisterClientHeaders(BaggageHeadersFactory.class)@RegisterRestClientpublicinterfaceWorldClockService{}
Orstaticallyset:
@GET@ClientHeaderParam(name="X-Log-Level",value="ERROR")ResponsegetNow();
Asynchronous
Amethodonclient interfacecanreturna CompletionStage classtobeexecutedasynchronously.
@GET@Path("/json/cet/now")@Produces(MediaType.APPLICATION_JSON)CompletionStage<WorldClock>getNow();
Reactive
Rest Client also integrateswith reactive library namedMutiny.Tostartusingityouneedtoaddthequarkus-rest-client-mutiny .
After that, a methodon a client interface can return aio.smallrye.mutiny.Uni instance.
@GET@Path("/json/cet/now")@Produces(MediaType.APPLICATION_JSON)Uni<WorldClock>getNow();
ARESTEasyReactive-basedRESTClientextension.Youonlyneedtoreplacethequarkus-rest-client toquarkus-rest-client-reactive .
Multipart
Itisreallyeasytosendmultipartform-datawithRestClient.
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
</dependency>
Themodelobject:
importjava.io.InputStream;
importjavax.ws.rs.FormParam;importjavax.ws.rs.core.MediaType;
importorg.jboss.resteasy.annotations.providers.multipart.Part
Type;
publicclassMultipartBody{
@FormParam("file")@PartType(MediaType.APPLICATION_OCTET_STREAM)privateInputStreamfile;
@FormParam("fileName")@PartType(MediaType.TEXT_PLAIN)privateStringname;
//getter/setters
}
AndtheRestclientinterface:
importorg.jboss.resteasy.annotations.providers.multipart.Mult
ipartForm;
@Path("/echo")@RegisterRestClientpublicinterfaceMultipartService{
@POST@Consumes(MediaType.MULTIPART_FORM_DATA)@Produces(MediaType.TEXT_PLAIN)StringsendMultipartData(@MultipartFormMultipartBodydata);
}
SSL
Youcancon�gureRestClientkeystores.
org.acme.quickstart.WorldClockService/mp-rest/trustStore=classpath:/store.jksorg.acme.quickstart.WorldClockService/mp-rest/trustStorePassword=supersecret
Possiblecon�gurationproperties:
%s/mp-rest/trustStore
Truststorelocationde�nedwithclasspath: orfile: pre�x.
%s/mp-rest/trustStorePassword
Truststorepassword.
%s/mp-rest/trustStoreType
Truststoretype(default:JKS )
%s/mp-rest/hostnameVerifier
Customhostnameveri�erclassname.TodisableSSLveri�cationyoucanuseio.quarkus.restclient.NoopHostnameVerifier .
%s/mp-rest/keyStore
Keystorelocationde�nedwithclasspath: orfile: pre�x.
%s/mp-rest/keyStorePassword
Keystorepassword.
%s/mp-rest/keyStoreType
Keystoretype(default:JKS )
Timeout
Youcande�nethetimeoutoftheRestClient:
org.acme.quickstart.WorldClockService/mp-rest/connectTimeout=1000
org.acme.quickstart.WorldClockService/mp-rest/readTimeout=2000
Instantiateclientprogrammatically
MovieReviewServicereviewSvc=RestClientBuilder.newBuilder
()
.baseUri(apiUri)
.build(WorldClockService.class);
Testing
QuarkusarchetypeaddstestdependencieswithJUnit5andRest-AssuredlibrarytotestRESTendpoints.
@QuarkusTestpublicclassGreetingResourceTest{
@TestpublicvoidtestHelloEndpoint(){given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("hello"));
}
}
Test port can be set in quarkus.http.test-port property. Timeoutcanbesetinquarkus.http.test-timeout property.
YoucanalsoinjecttheURLwhereQuarkusisstarted:
@TestHTTPResource("index.html")URLurl;
@TestHTTPEndpoint(GreetingResource.class)@TestHTTPResourceURLurl;
@QuarkusTest@TestHTTPEndpoint(GreetingResource.class)publicclassGreetingResourceTest{@TestpublicvoidtestHelloEndpoint(){given()
.when().get()
.then()
.statusCode(200)
.body(is("hello"));
}
}
Root path is calculated automatically, not necessary to explicitlyset.
If youwantanychangesmade tobe rolledbackat theendofthetestyoucanusetheio.quarkus.test.TestTransaction annotation.
QuarkusTestPro�le
Youcande�neforeachTestclassadifferentcon�gurationoptions.
ThisimpliesthattheQuarkusserviceisrestarted.
publicclassMyProfileimplementsio.quarkus.test.junit.QuarkusTestProfile{
@OverridepublicMap<String,String>getConfigOverrides(){returnMap.of("greetings.message","ThisisaTest");
}
@OverridepublicStringgetConfigProfile(){return"my-test-profile";}
@OverridepublicSet<String>tags(){returnCollections.singleton("test1");}
}
@QuarkusTest@TestProfile(MyProfile.class)publicclassMyTestClass{}
quarkus.test.profile.tags property can be set to limit testexecutionoftestpro�les.Ifnotsetalltestsareexecuted.
quarkus.test.profile.tags=test1
QuarkusTestResource
You can execute some logic before the �rst test run (start ) andexecutesomelogicattheendofthetestsuite(stop ).
You need to create a class implementingQuarkusTestResourceLifecycleManager interfaceand register it in thetestvia@QuarkusTestResource annotation.
publicclassMyCustomTestResourceimplementsQuarkusTestResourceLifecycleManager{
@OverridepublicMap<String,String>start(){//returnsystempropertiesthat
//shouldbesetfortherunningtest
returnCollections.emptyMap();}
@Overridepublicvoidstop(){}
//optional
@Overridepublicvoidinject(ObjecttestInstance){}
//optional
@Overridepublicintorder(){return0;}
}
Returning new system properties implies running paralleltestsindifferentJVMs.
Andtheusage:
@QuarkusTestResource(MyCustomTestResource.class)publicclassMyTest{}
When using multiple QuarkusTestResource you can set parallel
attributetotrue tostartthemconcurrently.
TestingCallbacks
Youcanenrichall your @QuarkusTest classesby implementing thefollowingcallbackinterfaces:
io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback
io.quarkus.test.junit.callback.QuarkusTestAfterConstructCall
back
io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback
io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback
publicclassSimpleAnnotationCheckerBeforeClassCallbackimplementsQuarkusTestBeforeClassCallback{@OverridepublicvoidbeforeClass(Class<?>testClass){}
}
AndneedstoberegisteredasJavaSPI:
META-INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback
io.quarkus.it.main.SimpleAnnotationCheckerBeforeClassCallba
ck
Mocking
If you need to provide an alternative implementation of a service(for testing purposes) you can do it by using CDI @Alternativeannotationusingitinthetestserviceplacedatsrc/test/java :
@Alternative@Priority(1)@ApplicationScopedpublicclassMockExternalServiceextendsExternalService{}
Thisdoesnotworkwhenusingnativeimagetesting.
Astereotypeannotation io.quarkus.test.Mock isprovideddeclaring@Alternative ,@Priority(1) and@Dependent .
Mockito
Instead of creating stubs, you can also create mocks of yourservices with mockito. Add the following dependencyio.quarkus:quarkus-junit5-mockito :
@InjectMockGreetingServicegreetingService;
@BeforeEachpublicvoidsetup(){Mockito.when(greetingService.greet()).thenReturn("Hi");
}
@Path("/hello")publicclassExampleResource{
@InjectGreetingServicegreetingService;
}
Mock is automatically injected and only valid for the de�ned testclass.
Alsospy issupported:
@InjectSpyGreetingServicegreetingService;
Mockito.verify(greetingService,Mockito.times(1)).greet();
RESTClient
To Mock REST Client, you need to de�ne the interface with@ApplicationScope :
@ApplicationScoped@RegisterRestClientpublicinterfaceGreetingService{}
@InjectMock@RestClientGreetingServicegreetingService;
Mockito.when(greetingService.hello()).thenReturn("hello fro
mmockito");
Interceptors
TestsareactuallyfullCDIbeans,soyoucanapplyCDIinterceptors:
@QuarkusTest@Stereotype@Transactional@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public@interfaceTransactionalQuarkusTest{}
@TransactionalQuarkusTestpublicclassTestStereotypeTestCase{}
TestCoverage
Due the nature of Quarkus to calculate correctly the coverageinformationwithJaCoCo,youmightneedo�ineinstrumentation.
./mvnwquarkus:add-extension
-Dextensions="quarkus-jacoco"
Possiblecon�gurationparameterspre�xedquarkus.jacoco :
data-file
Thejacocodata�le.(default:jacoco-quarkus.exec )
report
IfQuarkusshouldgeneratetheJacocoreport.(default:true )
output-encoding
Encodingofthegeneratedreports.(default:UTF-8 )
title
NameoftherootnodeHTMLreportpages.
footer
FootertextusedinHTMLreportpages.
source-encoding
Encoding of the source �les (default: UTF-8 )
includes
Alistofclass�lestoincludeinthereport.(default:** )
excludes
Alistofclass�lestoexcludefromthereport.
report-location
Thelocationofthereport�les.(default:jacoco-report )
NativeTesting
Totestnativeexecutablesannotatethetestwith@NativeImageTest .
QuarkusIntegrationTests
@QuarkusIntegrationTest should be used to launch and test theartifact produced by theQuarkus build. If the result of aQuarkusbuild is a JAR then the app is launched as java-jar , if native islaunched as ./application , if container image is created (JiB,Dockerextensions)islaunchedasdockerrun .
Persistence
Quarkus works with JPA(Hibernate) as persistence solution. Butalso provides an Active Record pattern implementation underPanacheproject.
To use database access you need to add Quarkus JDBC driversinsteadoftheoriginalones.Atthistime ApacheDerby , H2 , MariaDB ,MySQL ,MSSQL andPostgreSQL driversaresupported.
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-hibernate-orm-panache,
io.quarkus:quarkus-jdbc-mariadb"
@EntitypublicclassDeveloperextendsPanacheEntity{
//idfieldisimplicit
publicStringname;}
Andcon�gurationinsrc/main/resources/application.properties :
quarkus.datasource.jdbc.url=jdbc:mariadb://localhost:3306/mydb
quarkus.datasource.db-kind=mariadbquarkus.datasource.username=developerquarkus.datasource.password=developerquarkus.hibernate-orm.database.generation=update
Listofdatasourceparameters.
quarkus.datasource aspre�xisskippedinthenexttable.
db-kind
Built-in datasource kinds so the JDBC driver is resolvedautomatically. Possible values: derby , h2 , mariadb , mssql , mysql ,postgresql ,db2 .
username
Usernametoaccess.
password
Passwordtoaccess.
driver
JDBCDriverclass.Itisnotnecessarytosetifdb-kind used.
credentials-provider
Setsacustomcredentialprovidername.
credentials-provider-name
It is the @Named value of the credentials provider bean. Notnecessaryifonlyoneimplementation.
jdbc.url
ThedatasourceURL.
jdbc.min-size
Thedatasourcepoolminimumsize.(default:0 )
jdbc.max-size
Thedatasourcepoolmaximumsize.(default:20 )
jdbc.initial-size
Theinitialsizeofthepool.
jdbc.background-validation-interval
The interval at which we validate idle connections in thebackground.(default:2M )
jdbc.acquisition-timeout
The timeout before cancelling the acquisition of a newconnection.(default:5 )
jdbc.leak-detection-interval
Theintervalatwhichwecheckforconnectionleaks.
jdbc.idle-removal-interval
Theintervalatwhichwetrytoremoveidleconnections.(default:5M )
jdbc.max-lifetime
Themaxlifetimeofaconnection.
jdbc.transaction-isolation-level
The transaction isolation level.Possiblevalues: UNDEFINED , NONE ,READ_UNCOMMITTED ,READ_COMMITTED ,REPEATABLE_READ ,SERIALIZABLE .
jdbc.detect-statement-leaks
Warn when a connection is returned to the pool without theapplicationhavingclosedallopenstatements.(default:true )
jdbc.new-connection-sql
Queryexecutedwhen�rstusingaconnection.
jdbc.validation-query-sql
Queryexecutedtovalidateaconnection.
jdbc.pooling-enabled
DisablepoolingtopreventreuseofConnections.(default:true )
jdbc.enable-metrics
Enable datasource metrics collection when using quarkus-
smallrye-metrics extension.
jdbc.additional-jdbc-properties.<extraProperty>
Unspeci�ed properties to be passed to the JDBC driver whencreatingnewconnections.
Hibernate con�guration properties. Pre�x quarkus.hibernate-orm isskipped.
dialect
ClassnameoftheHibernateORMdialect.
dialect.storage-engine
The storage enginewhen the dialect supportsmultiple storageengines.
sql-load-script
Nameofthe�lecontainingtheSQLstatementstoexecutewhenstarts. no-file force Hibernate to skip SQL import. (default:import.sql )
batch-fetch-size
Thesizeofthebatches.(default:-1disabled)
maxFetchDepth
The maximum depth of outer join fetch tree for single-endedassociations.
multitenant
De�nesthemethodformulti-tenancy.Possiblevalues: DATABASE ,NONE ,SCHEMA .(default:NONE )
multitenant-schema-datasource
De�nesthenameofthedatasourcetouseincaseofSCHEMAapproach.
query.query-plan-cache-max-size
Themaximumsizeofthequeryplancache.
query.default-null-ordering
Default precedence of null values in ORDERBY . Possible values:none ,first ,last .(default:none )
database.generation
Database schema is generation. Possible values: none , create ,drop-and-create ,drop ,update .(default:none )
database.generation.halt-on-error
Stoponthe�rsterrorwhenapplyingtheschema.(default:false )
database.generation.create-schemas
Hibernate ORM should create the schemas automatically (fordatabasessupportingthem).
database.default-catalog
Defaultcatalog.
database.default-schema
DefaultSchema.
database.charset
Charset.
jdbc.timezone
TimeZoneJDBCdriver.
jdbc.statement-fetch-size
Numberofrowsfetchedatatime.
jdbc.statement-batch-size
Numberofupdatessentatatime.
log.sql
ShowSQLlogs(default:false )
log.jdbc-warnings
statistics
Enablestatiscscollection.(default:false )
physical-naming-strategy
Class name of the Hibernate PhysicalNamingStrategyimplementation.
globally-quoted-identifiers
Shouldquoteallidenti�ers.(default:false )
metrics-enabled
Metrics published with smallrye-metrics extension (default:false )
second-level-caching-enabledEnable/Disable2ndlevelcache.(default:true )
Databaseoperations:
//Insert
Developerdeveloper=newDeveloper();developer.name="Alex";
developer.persist();
//FindAll
Developer.findAll().list();
//HibernateFilters
Person.findAll().filter("Person.hasName", Parameters.with(
"name","Alex"));
//FindByQuery
Developer.find("name","Alex").firstResult();
//Delete
Developerdeveloper=newDeveloper();developer.id=1;
developer.delete();
Person.deleteById(id);
//DeleteByQuery
longnumberOfDeleted=Developer.delete("name","Alex");
Remembertoannotatemethodswith @Transactional annotationtomakechangespersistedinthedatabase.
Ifqueriesstartwiththekeyword from thentheyaretreatedasHQLquery,ifnotthennextshortformissupported:
orderby whichexpandstofromEntityNameorderby…
<columnName> which expands to from EntityName where
<columnName>=?
<query> whichisexpandedtofromEntityNamewhere<query>
StaticMethods
findById :ObjectReturns object or null if not found. Overloaded version withLockModeType isprovided.
findByIdOptional :Optional<Object>Returnsobjectorjava.util.Optional .
find :String ,[Object…,Map<String,Object> ,Parameters ]Lists of entities meeting given query with parameters set.ReturningaPanacheQuery .
find :String ,Sort ,[Object…,Map<String,Object> ,Parameters ]ListsofentitiesmeetinggivenquerywithparameterssetsortedbySort attribute/s.ReturningaPanacheQuery .
findAll
Findsallentities.ReturningaPanacheQuery .
findAll :SortFinds all entities sorted by Sort attribute/s. Returning aPanacheQuery .
list :String ,[Object…,Map<String,Object> ,Parameters ]Lists of entities meeting given query with parameters set.ReturningaList .
list :String ,Sort ,[Object…,Map<String,Object> ,Parameters ]ListsofentitiesmeetinggivenquerywithparameterssetsortedbySort attribute/s.ReturningaList .
listAll
Findsallentities.ReturningaList .
listAll :SortFindsallentitiessortedbySort attribute/s.ReturningaList .
stream :String ,[Object…,Map<String,Object> ,Parameters ]java.util.stream.Stream of entities meeting given query withparametersset.
stream :String ,Sort ,[Object…,Map<String,Object> ,Parameters ]java.util.stream.Stream of entities meeting given query withparameterssetsortedbySort attribute/s.
streamAll
java.util.stream.Stream ofallentities.
streamAll :Sortjava.util.stream.Stream ofallentitiessortedbySort attribute/s.
count
Number of entities
count :String ,[Object…,Map<String,Object> ,Parameters ]Numberofentitiesmeetinggivenquerywithparametersset.
EnablesaHibernate�lterduringfetchingofresultsforthisquery.
deleteAll
Numberofdeletedentities.
delete :String ,[Object…,Map<String,Object> ,Parameters ]Numberofdeletedentitiesmeetinggivenquerywithparametersset.
deleteById :boolean ,[Object ]Deletebyid.Returnsifdeletedornot.
persist :[Iterable ,Steram ,Object…]Persistobject.
In case of using streams, remember to close them or use atry/catch block:try(Stream<Person>persons=Person.streamAll()) .
find methods de�nes a withLock(LockModeType) to de�nethe lock type and withHint(QueryHints.HINT_CACHEABLE,
"true") tode�nehints.
NamedQueries
@Entity@NamedQuery(name="Person.getByName",query="fromPersonwherename=:name")
publicclassPersonextendsPanacheEntity{
publicstaticPersonfindByName(Stringname){returnfind("#Person.getByName",name).firstResult();
}
}
Pagination
PanacheQuery<Person>livingPersons=Person
.find("status",Status.Alive);
livingPersons.page(Page.ofSize(25));
//getthefirstpage
List<Person>firstPage=livingPersons.list();
//getthesecondpage
List<Person>secondPage=livingPersons.nextPage().list();
Range
PanacheQuery<Person>livingPersons=Person
.find("status",Status.Alive);
List<Person>secondRange=livingPersons.range(25,49).list
();
You cannot mix pagination and range
Ifentitiesarede�ned inexternalJAR,youneedtoenable in theseprojectstheJandex plugininproject.
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>1.0.3</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jandex</artifactId>
<version>2.1.1.Final</version>
</dependency>
</dependencies>
</plugin>
Panache includes an annotation processor that enhance yourentities. If you disable annotation processors you might need tocreate a marker �le on Panache archives at META-INF/panache-
archive.marker manually.
Testing
Tomockusingactiverecordpattern:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-panache-mock</artifactId>
<scope>test</scope>
</dependency>
@TestpublicvoidtestPanacheMocking(){PanacheMock.mock(Person.class);
Mockito.when(Person.count()).thenReturn(23l);
Assertions.assertEquals(23,Person.count());
PanacheMock.verify(Person.class,Mockito.times(1)).coun
t();
}
DevServices
WhentestingorrunningindevmodeQuarkuscanevenprovideyouwith a zero con�g database out of the box. Depending on yourdatabase type youmay needdocker installed in order to use thisfeature.
Thefollowingopensourcedatabases:
Postgresql (container)
MySQL(container)
MariaDB(container)
H2(in-process)
ApacheDerby(in-process)
TouseDevServicesdon’tcon�gureadatabaseURL,usernameandpassword,Quarkuswillprovidethedatabaseandyoucanjuststartcodingwithoutworryingaboutcon�g.
quarkus.datasource.db-kind=mariadb%prod.quarkus.datasource.jdbc.url=jdbc:mariadb://db:3306/mydb
%prod.quarkus.datasource.username=developer%prod.quarkus.datasource.password=developer
Possiblecon�gurationvaluespre�xedwithquarkus.datasource :
devservices
Ifdevservicesisenabledornot.(default:true )
devservices.image-name
Thecontainerimagenametouseinsteadofthedefaultone.
devservices.properties
Generic properties that are added to the database connectionURL.
DAOpattern
AlsosupportsDAOpatternwithPanacheRepository<TYPE> .
@ApplicationScopedpublicclassDeveloperRepositoryimplementsPanacheRepository<Person>{publicPersonfindByName(Stringname){returnfind("name",name).firstResult();}
}
EntityManagerYoucaninjectEntityManager inyourclasses:
@InjectEntityManagerem;
@Injectorg.hibernate.Sessionsession;
@Injectorg.hibernate.SessionFactorysessionFactory;
em.persist(car);
Multipledatasources
Youcanregistermorethanonedatasource.
#default
quarkus.datasource.db-kind=h2quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:default
....
#usersdatasource
quarkus.datasource.users.devservices=falsequarkus.datasource.users.db-kind=h2quarkus.datasource.users.jdbc.url=jdbc:h2:tcp://localhost/mem:users
Notice that after datasource you set the datasource name, inpreviouscaseusers .
You can inject then AgroalDataSource withio.quarkus.agroal.DataSource .
@DataSource("users")AgroalDataSourcedataSource1;
Flushing
You can force �ush operation by calling .flush() or.persistAndFlush() tomakeitinasinglecall.
This �ush is less e�cient and you still need to committransaction.
Testing
There isaQuarkusTestResourcethatstartsandstopsH2serverbeforeandaftertestsuite.
Registerdependencyio.quarkus:quarkus-test-h2:test .
Andannotatethetest:
@QuarkusTestResource(H2DatabaseTestResource.class)publicclassFlywayTestResources{}
Transactions
Theeasiestwaytode�neyourtransactionboundariesistousethe@Transactional annotation.
Transactions are mandatory in case of none idempotentoperations.
@TransactionalpublicvoidcreateDeveloper(){}
Youcancontrolthetransactionscope:
@Transactional(REQUIRED) (default):startsatransactionifnonewasstarted,stayswiththeexistingoneotherwise.
@Transactional(REQUIRES_NEW) :startsatransactionifnonewasstarted;ifanexistingonewasstarted,suspendsitandstartsanewonefortheboundaryofthatmethod.
@Transactional(MANDATORY) :failsifnotransactionwasstarted;workswithintheexistingtransactionotherwise.
@Transactional(SUPPORTS) :ifatransactionwasstarted,joinsit;otherwiseworkswithnotransaction.
@Transactional(NOT_SUPPORTED) : if a transaction was started,suspendsitandworkswithnotransactionfortheboundaryofthemethod;otherwiseworkswithnotransaction.
@Transactional(NEVER) : if a transactionwas started, raises anexception;otherwiseworkswithnotransaction.
You can con�gure the default transaction timeout usingquarkus.transaction-manager.default-transaction-timeout
con�gurationproperty.Bydefaultitissetto60seconds.
You can set a timeout property, in seconds, that applies totransactions created within the annotated method by using@TransactionConfiguration annotation.
@Transactional@TransactionConfiguration(timeout=40)publicvoidcreateDeveloper(){}
If you want more control over transactions you can injectUserTransaction anduseaprogrammaticway.
@InjectUserTransactiontransaction
transaction.begin();
transaction.commit();
transaction.rollback();
You can implement your custom credentials provider (ie AzureKeyVault) to provide a username/password for the databaseconnection. Name information isnotnecessary if there isonlyonecustomcredentialprovider.
@ApplicationScoped@Unremovable@Named("my-credentials-provider")publicclassCustomCredentialsProviderimplementsCredentialsProvider{@InjectConfigconfig;
@Override publicPropertiesgetCredentials(StringcredentialsProviderName){
properties.put(CredentialsProvider.USER_PROPERTY_NA
ME,"hibernate_orm_test");
properties.put(CredentialsProvider.PASSWORD
_PROPERTY_NAME,"hibernate_orm_test");
}
}
quarkus.datasource.credentials-provider=custom
quarkus.datasource.credentials-provider-name=my-credentials-provider
HibernateMultitenancy
Multitenancy is supported using Schema or Database approach.Firstyouneedtode�nehowtenantisidenti�ed:
@RequestScoped@UnremovablepublicclassCustomTenantResolverimplementsTenantResolver{
@InjectRoutingContextcontext;
@OverridepublicStringgetDefaultTenantId(){return"base";}
@OverridepublicStringresolveTenantId(){}
}
Schemaapproach
quarkus.hibernate-orm.database.generation=none
quarkus.hibernate-orm.multitenant=SCHEMA
Databaseapproach
quarkus.hibernate-orm.database.generation=none
quarkus.hibernate-orm.multitenant=DATABASE
#defaulttenant
quarkus.datasource.base.db-kind=postgresqlquarkus.datasource.base.username=quarkus_test...
#Tenant'mycompany'
quarkus.datasource.mycompany.db-kind=postgresqlquarkus.datasource.mycompany.username=mycompanyquarkus.flyway.mycompany.locations=classpath:database/mycompany
...
Ifyouneedmoredynamicapproachimplement: @ApplicationScopedio.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver
HibernateEnvers
QuarkussupportsHibernateEnvers.
./mvnwquarkus:add-extension
-Dextensions="hibernate-envers"
RESTDataPanache
RESTDatawith Panache extension can generate the basic CRUDendpointsforyourentitiesandrepositories.
./mvnwquarkus:add-extension
-Dextensions="hibernate-orm-rest-data-panache"
You also need to add the JDBC driver extension and a JSONMarshaller(ieresteasy-jackson ).
Thenyoucande�neinterfacesforde�ningendpoints:
IncaseofActiveRecordpattern:
publicinterfaceDeveloperResourceextendsPanacheEntityResource<Developer,Long>{}
IncaseofRepository:
publicinterfaceDeveloperResourceextendsPanacheRepositoryResource<DeveloperRepository,Developer,Long>{}
Quarkus will generate automatically the implementation for youfollowingthenextrules:
Default path is a hyphenated lowercase resource namewithout a su�x of or
get(@PathParam("id")) , list , add(Developer) ,update(@PathParam("id"),Developer) ,delete(@PathParam("id"))
Youcancustomizethesedefaultsbyusing@ResourceProperties and@MethodProperties annotations.
@ResourceProperties(hal=true,path="my-developer",halCollectionName="dev-collections")
publicinterfaceDeveloperResourceextendsPanacheEntityResource<Developer,Long>{@MethodProperties(path="all")List<Developer>list();@MethodProperties(exposed=false)voiddelete(Longid);}
If hal is true , you need to send the Accept:application/hal+jsonHTTPheadertogettheresponse.
HibernateReactive
./mvnwquarkus:add-extension
-Dextensions="quarkus-hibernate-reactive,quarkus-resteas
y-mutiny,"
Also you need to add the reactive driver (ie quarkus-reactive-pg-client ).
You can use: org.hibernate.reactive.mutiny.Mutiny ororg.hibernate.reactive.stage.Stage .
@Entity@Table(name="dev")publicclassDeveloper{}
@InjectCompletionStage<Stage.Session>stageSession;
@InjectUni<Mutiny.Session>mutinySession;
publicUni<Long>reactivePersist(){returnmutinySession.flatMap(s->s.persist(newDeveloper(1,"Alex")).flatMap(v->session.flush())
....
}
publicCompletionStage<Developer>reactiveFind(){returnstageSession.thenCompose(session->{
session.find(Developer.class,1);
});
}
In�nispan
QuarkusintegrateswithIn�nispan:
./mvnwquarkus:add-extension
-Dextensions="infinispan-client"
SerializationusesalibrarycalledProtostream.
Annotationbased
@ProtoFactorypublicAuthor(Stringname,Stringsurname){this.name=name;this.surname=surname;}
@ProtoField(number=1)publicStringgetName(){returnname;}
@ProtoField(number=2)publicStringgetSurname(){returnsurname;}
Initializertosetcon�gurationsettings.
@AutoProtoSchemaBuilder(includeClasses={Book.class,Author.class},
schemaPackageName="book_sample")
interfaceBookContextInitializerextendsSerializationContextInitializer{}
Userwrittenbased
Therearethreewaystocreateyourschema:
Proto�le
Createsa.proto �leintheMETA-INF directory.
packagebook_sample;
messageAuthor{
requiredstringname=1;
requiredstringsurname=2;
}
IncaseofhavingaCollection�eldyouneedtousetherepeated key(ierepeatedAuthorauthors=4 ).
Incode
Settingproto schemadirectlyinaproducedbean.
@ProducesFileDescriptorSourcebookProtoDefinition(){returnFileDescriptorSource.fromString("library.proto",
"packagebook_sample;\n"+
"messageAuthor{\n"+
"requiredstringname=1;\n"+
"requiredstringsurname=2;\n"+
"}");
}
Marshaller
Usingorg.infinispan.protostream.MessageMarshaller interface.
publicclassAuthorMarshallerimplementsMessageMarshaller<Author>{
@OverridepublicStringgetTypeName(){return"book_sample.Author";}
@OverridepublicClass<?extendsAuthor>getJavaClass(){returnAuthor.class;}
@OverridepublicvoidwriteTo(ProtoStreamWriterwriter,Authorauthor)throwsIOException{writer.writeString("name",author.getName());
writer.writeString("surname",author.getSurname());
}
@OverridepublicAuthorreadFrom(ProtoStreamReaderreader)throwsIOException{Stringname=reader.readString("name");
Stringsurname=reader.readString("surname");
returnnewAuthor(name,surname);}
}
Andproducingthemarshaller:
@ProducesMessageMarshallerauthorMarshaller(){returnnewAuthorMarshaller();}
In�nispanEmbedded
./mvnwquarkus:add-extension
-Dextensions="infinispan-embeddedy"
Con�gurationininfinispan.xml :
<local-cachename="quarkus-transaction">
<transaction
transaction-manager-lookup=
"org.infinispan.transaction.lookup.JBossStandaloneJ
TAManagerLookup"/>
</local-cache>
Setcon�guration�lelocationinapplication.properties :
quarkus.infinispan-embedded.xml-config=infinispan.xml
Andyoucaninjectthemainentrypointforthecache:
@Injectorg.infinispan.manager.EmbeddedCacheManagercacheManager;
Redis
QuarkusintegrateswithRedis.
./mvnwquarkus:add-extension
-Dextensions="redis-client"
Con�gureRedislocation:
quarkus.redis.hosts=localhost:6379
Youcanusesynchronousorreactiveclients:
@InjectRedisClientredisClient;
@InjectReactiveRedisClientreactiveRedisClient;
voidincrement(Stringkey,IntegerincrementBy){redisClient.incrby(key,incrementBy.toString());
}
Uni<List<String>>keys(){
returnreactiveRedisClient.keys("*")
.map(response->{
List<String>result=newArrayList<>();for(Responser:response){result.add(r.toString());
}
returnresult;});
}
MultipleRedisClients
quarkus.redis.hosts=localhost:6379quarkus.redis.second.hosts=localhost:6379
@InjectRedisClientdefaultRedisClient;
@Inject@RedisClientName("second")RedisClientredisClient2;
ListofRedisparameters.
quarkus.redis aspre�xisskippedinthenexttable.
health.enabled
Healthcheck ispublished incase thesmallrye-healthextensionispresent.(default:true )
password
TheRedispassword.
hosts
TheRedishosts.(default:localhost:6379 )
database
TheRedisdatabase.
timeout
Themaximumdelaytowaitbeforeablockingcommandtoredisservertimesout.(default:10s )
ssl
EnablesordisablestheSSLonconnect.
clinet-type
The Redis client type. Possible values: standalone , cluster ,sentinel (default:standalone )
Flyway
Quarkus integrateswith Flyway to help you on database schemamigrations.
./mvnwquarkus:add-extension
-Dextensions="quarkus-flyway"
Then place migration �les to the migrations folder(classpath:db/migration ).
You can inject org.flywaydb.core.Flyway to programmaticallyexecutethemigration.
@InjectFlywayflyway;
flyway.migrate();
Or can be automatically executed by setting migrate-at-start
propertytotrue .
quarkus.flyway.migrate-at-start=true
ListofFlywayparameters.
quarkus.flyway aspre�xisskippedinthenexttable.
clean-at-start
ExecuteFlywaycleancommand(default:false )
migrate-at-start
Flywaymigrationautomatically(default:false )
locations
CSV locations to scan recursively for migrations. Supportedpre�xes classpath and filesystem (default:classpath:db/migration ).
connect-retries
The maximum number of retries when attempting to connect(default:0)
schemas
CSVcase-sensitivelistofschemasmanaged(default:none)
table
The name of Flyway’s schema history table (default:flyway_schema_history )
out-of-order
Allowsmigrationstoberun"outoforder".
ignore-missing-migrations
Ignoremissingmigrationswhenreadingthehistorytable.
sql-migration-prefix
Pre�xforversionedSQLmigrations(default:V )
repeatable-sql-migration-prefix:: Pre�x for repeatable SQLmigrations(default:R )
baseline-on-migrate
Onlymigrationsabovebaseline-versionwillthenbeapplied
baseline-version
Versiontotaganexistingschemawithwhenexecutingbaseline(default:1)
baseline-description
Description to tag an existing schema with when executingbaseline(default:FlywayBaseline )
validate-on-migrate
Validate the applied migrations against the available ones(default:true )
placeholder-prefix
Pre�xofeveryplaceholder(default:${ )
placeholder-suffix
Su�xofeveryplaceholder(default:} )
callbacks
Comma-separated listoffullyquali�edclassnamesofCallbackimplementations.
ignore-future-migrations
Ignorefuturemigrationswhenreadingthehistorytable.
MultipleDatasources
To use multiple datasource in Flyway you just need to add thedatasourcenamejustaftertheflyway property:
quarkus.datasource.users.jdbc.url=jdbc:h2:tcp://localhost/mem:users
quarkus.datasource.inventory.jdbc.url=jdbc:h2:tcp://localhost/mem:inventory
#...
quarkus.flyway.users.schemas=USERS_TEST_SCHEMAquarkus.flyway.inventory.schemas=INVENTORY_TEST_SCHEMA#...
Liquibase
QuarkusintegrateswithLiquibasetohelpyouondatabaseschemamigrations.
./mvnwquarkus:add-extension
-Dextensions="quarkus-liquibase"
Thenplacechangelog�lestothe(src/main/resources/db )folder.
You can inject org.quarkus.liquibase.LiquibaseFactory toprogrammaticallyexecutethemigration.
@InjectLiquibaseFactoryliquibaseFactory;
try(Liquibaseliquibase=liquibaseFactory.createLiquibase()){
...
}
Or can be automatically executed by setting migrate-at-start
propertytotrue .
quarkus.liquibase.migrate-at-start=true
ListofLiquibaseparameters.
quarkus.liquibase aspre�xisskippedinthenexttable.
change-logThe change log �le. XML , YAML , JSON , SQL formats supported.(default:db/changeLog.xml )
change-log-parameters."<parameter-name>"Liquibasechangelogparameters.
migrate-at-startThemigrateatstart�ag.(default:false )
validate-on-migrateThevalidateonupdate�ag.(default:false )
clean-at-startThecleanatstart�ag.(default:false )
contextsThelistofcontexts.
labelsThelistoflabels.
database-change-log-table-nameThe database change log lock table name. (default:DATABASECHANGELOG )
database-change-log-lock-table-nameThe database change log lock table name. (default:DATABASECHANGELOGLOCK )
default-catalog-nameThedefaultcatalogname.
default-schema-nameThe default schema name
liquibase-catalog-nameTheliquibasetablescatalogname.
liquibase-schema-nameTheliquibasetablesschemaname.
liquibase-tablespace-nameTheliquibasetablestablespacename.
MultipleDatasources
Tousemultiple datasource in Liquibase you just need to add thedatasourcenamejustaftertheliquibase property:
quarkus.datasource.users.jdbc.url=jdbc:h2:tcp://localhost/mem:users
quarkus.datasource.inventory.jdbc.url=jdbc:h2:tcp://localhost/mem:inventory
#...
quarkus.liquibase.users.schemas=USERS_TEST_SCHEMAquarkus.liquibase.inventory.schemas=INVENTORY_TEST_SCHEMA#...
HibernateSearch
QuarkusintegrateswithElasticsearchtoprovideafull-featuredfull-textsearchusingHibernateSearchAPI.
./mvnwquarkus:add-extension
-Dextensions="quarkus-hibernate-search-elasticsearch"
You need to annotate your model with Hibernate Search API toindexit:
@Entity@IndexedpublicclassAuthorextendsPanacheEntity{
@FullTextField(analyzer="english")publicStringbio;
@FullTextField(analyzer="name")@KeywordField(name="firstName_sort",sortable=Sortable.YES,
normalizer="sort")
publicStringfirstName;
@OneToMany@IndexedEmbeddedpublicList<Book>books;
}
ItisnotmandatorytousePanache.
You need to de�ne the analyzers and normalizers de�ned inannotations. You only need to implementElasticsearchAnalysisConfigurer interfaceandcon�gureit.
publicclassMyQuarkusAnalysisConfigurerimplementsElasticsearchAnalysisConfigurer{
@Overridepublicvoidconfigure(ElasticsearchAnalysisDefinitionContainerContextct
x)
{
ctx.analyzer("english").custom()
.withTokenizer("standard")
.withTokenFilters("asciifolding",
"lowercase","porter_stem");
ctx.normalizer("sort").custom()
.withTokenFilters("asciifolding","lowercase");
}
}
UseHibernateSearchinRESTservice:
publicclassLibraryResource{
@InjectEntityManagerem;
@TransactionalpublicList<Author>searchAuthors(@QueryParam("pattern")Stringpattern){
returnSearch.getSearchSession(em).search(Author.class)
.predicate(f->
pattern==null||pattern.isEmpty()?f.matchAll():
f.simpleQueryString()
.onFields("firstName",
"lastName","books.title")
.matching(pattern)
)
.sort(f->f.byField("lastName_sort")
.then().byField("firstName_sort"))
.fetchHits();
}
When not using Hibernate ORM, index data usingSearch.getSearchSession(em).createIndexer()
.startAndWait() atstartuptime.
Con�guretheextensioninapplication.properties :
quarkus.hibernate-search.elasticsearch.version=7quarkus.hibernate-search.elasticsearch.
analysis-configurer=MyQuarkusAnalysisConfigurerquarkus.hibernate-search.elasticsearch.
automatic-indexing.synchronization-strategy=searchablequarkus.hibernate-search.elasticsearch.
index-defaults.lifecycle.strategy=drop-and-createquarkus.hibernate-search.elasticsearch.
index-defaults.lifecycle.required-status=yellow
List of Hibernate-Elasticsearch properties pre�xed withquarkus.hibernate-search.elasticsearch :
backends
Mapofcon�gurationofadditionalbackends.
version
VersionofElasticsearch
analysis-configurer
Classornameoftheneabusedtocon�gure.
hosts
ListofElasticsearchservershosts.
username
Usernameforauth.
password
Passwordforauth.
connection-timeout
Durationofconnectiontimeout.
max-connections
Maxnumberofconnectionstoservers.
max-connections-per-route
Maxnumberofconnectionstoserver.
indexes
Per-indexspeci�ccon�guration.
discovery.enabled
Enablesautomaticdiscovery.
discovery.refresh-interval
Refreshintervalofnodelist.
discovery.default-scheme
Schemetobeusedforthenewnodes.
automatic-indexing.synchronization-strategy
Status for which you wait before considering the operationcompleted(queued ,committed orsearchable ).
automatic-indexing.enable-dirty-check
When enabled, re-indexing of is skipped if the changes are onpropertiesthatarenotusedwhenindexing.
index-defaults.lifecycle.strategy
Index lifecycle (none , validate , update , create , drop-and-create ,drop-abd-create-drop )
index-defaults.lifecycle.required-status
Minimalclusterstatus(green ,yellow ,red )
index-defaults.lifecycle.required-status-wait-timeout
Waitingtimebeforefailingthebootstrap.
index-defaults.refresh-after-write
Setifindexshouldberefreshedafterwrites.
Possibleannotations:
@Indexed
Registerentityasfulltextindex
@FullTextField
Fulltextsearch.Needtosetananalyzertosplittokens.
@KeywordField
Thestringiskeptasonesingletokenbutcanbenormalized.
IndexedEmbedded
IncludetheBook�eldsintotheAuthorindex.
@ContainerExtraction
Setshowtoextractavaluefromcontainer,e.gfromaMap .
@DocumentId
Mapanunusualentityidenti�ertoadocumentidenti�er.
@GenericField
Fulltextindexforanysupportedtype.
@IdentifierBridgeRef
Referencetotheidenti�erbridgetousefora@DocumentId .
@IndexingDependency
Howadependencyoftheindexingprocesstoapropertyshouldaffectautomaticreindexing.
@ObjectPath
@ScaledNumberField
For java.math.BigDecimal or java.math.BigInteger that you needhigherprecision.
AmazonDynamoDB
Quarkusintegrateswithhttps://aws.amazon.com/dynamodb/:
./mvnwquarkus:add-extension
-Dextensions="quarkus-amazon-dynamodb"
@InjectDynamoDbClientdynamoDB;
TouseasycnhronousclientwithMutiny:
./mvnwquarkus:add-extension
-Dextensions="quarkus-amazon-dynamodb,resteasy-mutiny"
@InjectDynamoDbAsyncClientdynamoDB;
Uni.createFrom().completionStage(() -> dynamoDB.scan(scanRe
quest()))....
TouseitasalocalDynamoDBinstance:
quarkus.dynamodb.region=eu-central-1
quarkus.dynamodb.endpoint-override=http://localhost:8000
quarkus.dynamodb.credentials.type=STATICquarkus.dynamodb.credentials.static-provider
.access-key-id=test-keyquarkus.dynamodb.credentials.static-provider
.secret-access-key=test-secret
IfyouwanttoworkwithanAWSaccount,you’dneedtosetitwith:
quarkus.dynamodb.region=<YOUR_REGION>
quarkus.dynamodb.credentials.type=DEFAULT
DEFAULT credentialsproviderchain:
Systempropertiesaws.accessKeyId ,aws.secretKey
Env.VarablesAWS_ACCESS_KEY_ID ,AWS_SECRET_ACCESS_KEY
Credentialspro�le~/.aws/credentials
Credentials through theAmazonEC2container service if theAWS_CONTAINER_CREDENTIALS_RELATIVE_URI set
CredentialsthroughAmazonEC2metadataservice.
Con�gurationparameterspre�xedwithquarkus.dynamodb :
Parameter Default Description
enable-endpoint-
discoveryfalse
Endpoint discoveryforaserviceAPI thatsupports endpointdiscovery.
endpoint-override Con�gure theendpoint with whichthe SDK shouldcommunicate.
api-call-timeoutTime to complete anexecution.
interceptorsList of classinterceptors.
Con�gurationparameterspre�xedwithquarkus.dynamodb.aws :
Parameter Default Description
regionRegion that hostsDynamoDB.
credentials.type DEFAULT
Credentials thatshould be usedDEFAULT , STATIC ,SYSTEM_PROPERTY ,ENV_VARIABLE ,PROFILE , CONTAINER ,INSTANCE_PROFILE ,PROCESS ,ANONYMOUS
Credentials speci�c parameters pre�xed withquarkus.dynamodb.aws.credentials :
Parameter Default Description
DEFAULT
default-
provider.async-
credential-update-
enabled
falseShould fetchcredentialsasync.
default-
provider.reuse-last-
provider-enabled
true
Should reuse the lastsuccessfulcredentials.
STATIC
static-
provider.access-key-
id
AWSaccesskeyid.
static-
provider.secret-
access-key
AWS secret accesskey.
Parameter Default Description
PROFILE
profile-
provider.profile-namedefault
The name of thepro�letouse.
PROCESS
process-
provider.command
Commandtoexecuteto retrievecredentials.
process-
provider.process-
output-limit
1024 Max bytes to retrievefromprocess.
process-
provider.credential-
refresh-threshold
PT15S
The amount of timebetween credentialsexpire andcredentialsrefreshed.
process-
provider.async-
credential-update-
enabled
falseShould fetchcredentialsasync.
In case of synchronous client, the next parameters can becon�guredpre�xedbyquarkus.dynamodb.sync-client :
Parameter Default Description
connection-
acquisition-timeout10S
Connectionacquisationtimeout.
connection-max-idle-
time60S
Max time toconnection to beopened.
connection-timeout Connectiontimeout.
connection-time-to-
live0
Max time connectiontobeopen.
socket-timeout 30S Timetowaitfordata.
max-connections 50 Maxconnections.
expect-continue-
enabledtrue
Client send an HTTPexpect-continue
handsake.
Parameter Default Description
use-idle-connection-
reapertrue
Connections in poolshould be closedasynchronously.
proxy.endpointEndpointoftheproxyserver.
proxy.enabled false EnablesHTTPproxy.
proxy.username Proxyusername.
proxy.password Proxypassword.
proxy.ntlm-domainFor NTLM, domainname.
proxy.ntlm-
workstation
For NTLM,workstationname.
proxy.preemptive-
basic-authentication-
enabled
Authenticate pre-emptively.
proxy.non-proxy-
hosts
List of non proxyhosts.
tls-managers-
provider.typesystem-property
TLS manager: none ,system-property ,file-store
tls-managers-
provider.file-
store.path
Pathtokeystore.
tls-managers-
provider.file-
store.type
Keystoretype.
tls-managers-
provider.file-
store.password
Keystorepassword.
In case of asynchronous client, the next parameters can becon�guredpre�xedbyquarkus.dynamodb.async-client :
Parameter Default Description
connection-
acquisition-timeout10S
Connectionacquisationtimeout.
Parameter Default Description
connection-max-idle-
time60S
Max time toconnection to beopened.
connection-timeout Connectiontimeout.
connection-time-to-
live0
Max time connectiontobeopen.
max-concurrency 50
Max number ofconcurrentconnections.
use-idle-connection-
reapertrue
Connections in poolshould be closedasynchronously.
read-timeout 30S Readtimeout.
write-timeout 30S Writetimeout.
proxy.endpointEndpointoftheproxyserver.
proxy.enabled false EnablesHTTPproxy.
proxy.non-proxy-
hosts
List of non proxyhosts.
tls-managers-
provider.typesystem-property
TLS manager: none ,system-property ,file-store
tls-managers-
provider.file-
store.path
Pathtokeystore.
tls-managers-
provider.file-
store.type
Keystoretype.
tls-managers-
provider.file-
store.password
Keystorepassword.
ssl-provider
SSL Provider (jdk ,openssl , openssl-
refcnt ).
Parameter Default Description
protocol HTTP_1_1Sets the HTTPprotocol.
max-http2-streamsMax number ofconcurrentstreams.
event-loop.override falseEnable custom eventloopconf.
event-loop.number-of-
threads
Numberofthreadstouseineventloop.
event-loop.thread-
name-prefix
aws-java-sdk-
NettyEventLoop
Pre�x of threadnames.
AmazonS3
./mvnwquarkus:add-extension
-Dextensions="quarkus-amazon-s3"
@InjectS3Clients3Client;
YouneedtosetaHTTPclienteitherURLConnection :
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
orApacheHTTP:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
quarkus.s3.sync-client.type=apache
Andcon�gureit:
quarkus.s3.endpoint-override=http://localhost:8008quarkus.s3.interceptors=io.quarkus.it.amazon.s3.S3ModifyResponse
quarkus.s3.aws.region=us-east-1quarkus.s3.aws.credentials.type=staticquarkus.s3.aws.credentials.static-provider.access-key-id=test-key
quarkus.s3.aws.credentials.static-provider.secret-access-key=test-secret
Youcaninjectasynchronousclienttoo:
@InjectS3AsyncClients3AsyncClient;
AndyouneedtoaddtheasynchronousNettyclient:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
Con�gurationpropertiesare thesameasAmazonDynamoDB butchangingthepre�xfromdynamodb tos3 .
Neo4j
QuarkusintegrateswithNeo4j:
./mvnwquarkus:add-extension
-Dextensions="quarkus-neo4j"
@Injectorg.neo4j.driver.Driverdriver;
Con�gurationproperties:
quarkus.neo4j aspre�xisskippedinthenexttable.
Pre�xisquarkus.neo4j .
uri
URIofNeo4j.(default:localhost:7687 )
authentication.username
Username.(default:neo4j )
authentication.password
Password.(default:neo4j )
authentication.disabled
Disableauthentication.(default:false )
Enablemetrics.(default:false )
pool.log-leaked-sessions
Enableleakedsessionslogging.(default:`false`)
pool.max-connection-pool-size
Maxamountofconnections.(default:100 )
pool.max-connection-lifetime
Pooled connections olderwill be closed and removed from thepool.(default:1H )
pool.connection-acquisition-timeout
Timoutforconnectionadquisation.(default:1M)
pool.idle-time-before-connection-test
Pooledconnectionsidledinthepoolforlongerthanthistimeoutwillbetestedbeforetheyareused.(default:-1 )
As Neo4j uses SSL communication by default, to create a nativeexecutableyouneedtocompilewithnextoptionsGraalVMoptions:
-H:EnableURLProtocols=http,https --enable-all-security-services -
H:+JNI
AndQuarkusMavenPluginwithnextcon�guration:
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<id>native-image</id>
<goals>
<goal>native-image</goal>
</goals>
<configuration>
<enableHttpUrlHandler>true
</enableHttpUrlHandler>
<enableHttpsUrlHandler>true
</enableHttpsUrlHandler>
<enableAllSecurityServices>true
</enableAllSecurityServices>
<enableJni>true</enableJni>
</configuration>
</execution>
</executions>
Alternatively, and as a not recommended way in production, youcan disable SSL and Quarkus will disable Bolt SSL as well.quarkus.ssl.native=false .
IfyouareusingNeo4j4.0,youcanusefullyreactive.Addthenextextension:quarkus-resteasy-mutiny .
@GETpublicPublisher<String>get(){returnMulti.createFrom().resource(driver::rxSession,session->session.readTransaction(tx->{
RxResultresult=tx.run("MATCH(f:Fruit)RETUR
Nf.nameasname");
returnMulti.createFrom().publisher(result.records())
.map(record->record.get("name").asStr
ing());
})
).withFinalizer(session->{
returnUni.createFrom().publisher(session.close());});
}
MongoDBClient
QuarkusintegrateswithMongoDB:
./mvnwquarkus:add-extension
-Dextensions="quarkus-mongodb-client"
@Injectcom.mongodb.client.MongoClientclient;
@Injectio.quarkus.mongodb.reactive.ReactiveMongoClientclient;
INFO:ReactiveclientusesexposesMutinyAPI.
quarkus.mongodb.connection-string=mongodb://localhost:27018quarkus.mongodb.write-concern.journal=false
MultiMongoDBsupport
Youcancon�guremultipleMongoDBclientsusingsameapproachaswith DataSource .Thesyntax is quarkus.mongodb.<optionalname>.<property> :
quarkus.mongodb.users.connection-string = mongodb://mongo2:27017/userdb
quarkus.mongodb.inventory.connection-string = mongodb://mongo3:27017/invdb
Inject the instance [email protected] annotation:
@Inject@MongoClientName("users")MongoClientmongoClient1;
quarkus.mongodb aspre�xisskippedinthefollowingtable.
Parameter Type Description
connection-string StringMongoDBconnectionURI.
hosts List<String>Addressespassedashost:port .
application-name String Applicationname.
max-pool-size IntMaximum number ofconnections.
min-pool-size IntMinimum number ofconnections.
max-connection-idle-
timeDuration
Idle time of a pooledconnection.
max-connection-life-
timeDuration
Life time of pooledconnection.
wait-queue-timeout DurationMaximum wait timefornewconnection.
maintenance-
frequencyDuration
Time period betweenruns of maintenancejob.
maintenance-initial-
delayDuration
Time to wait beforerunning the �rstmaintenancejob.
wait-queue-multiple Int
Multiplied with max-
pool-size gives maxnumer of threadswaiting.
connection-timeout Duration
socket-timeout Duration
tls-insecure boolean[false] InsecureTLS.
tls boolean[false] EnableTLS
Parameter Type Description
replica-set-name StringImplies hosts givenareaseedlist.
server-selection-
timeoutDuration
Time to wait forserverselection.
local-threshold Duration
Minimum ping timeto make a servereligible.
heartbeat-frequency Duration
Frequency todetermine the stateofservers.
read-preference
primary ,primaryPreferred ,secondary ,secondaryPreferred ,nearest
Readpreferences.
max-wait-queue-size Int
Max number ofconcurrentoperationsallowedtowait.
write-concern.safe boolean[true]Ensures are writesareack.
write-
concern.journalboolean[true]
Journal writingaspect.
write-concern.w StringValue to all writecommands.
write-concern.retry-
writesboolean[false]
Retry writes ifnetworkfails.
write-concern.w-
timeoutDuration
Timeout to all writecommands.
credentials.username String Username.
credentials.password String Password.
credentials.auth-
mechanism
MONGO-CR , GSSAPI ,PLAIN ,MONGODB-X509
Parameter Type Description
credentials.auth-
sourceString
Source of theauthenticationcredentials.
credentials.auth-
mechanism-propertiesMap<String,String>
Authenticationmechanismproperties.
MongoDBPanache
YoucanalsousethePanacheframeworktowritepersistencepartwhenusingMongoDB.
./mvnwquarkus:add-extension
-Dextensions="mongodb-panache"
MongoDBcon�gurationcomesfromMongoDBClientsection.
@MongoEntity(collection="ThePerson")publicclassPersonextendsPanacheMongoEntity{publicStringname;
@BsonProperty("birth")publicLocalDatebirthDate;
publicStatusstatus;}
Possible annotations in �elds: @BsonId (for custom ID),@BsonProperty and@BsonIgnore .
@MongoEntity isoptional.
Multi-tenancywithMongoDBPanache
@MongoEntity(collection="TheBook",clientName="client2",database="database2")
Methods provided are similar of the ones shown in Persistencesection.
person.persist();
person.update();
person.delete();
List<Person>allPersons=Person.listAll();
person=Person.findById(personId);
List<Person>livingPersons=Person.list("status",Status.A
live);
List<Person>persons=Person.list(Sort.by("name").and("bir
th"));
longupdated=Person.update("name","Mortal").where("status",Status.Alive);
longcountAll=Person.count();
Person.deleteById(id);
Person.delete("status",Status.Alive);
Alllist methodshaveequivalentstream versions.
Pagination
Youcanalsousepagination:
PanacheQuery<Person>livingPersons=
Person.find("status",Status.Alive);
livingPersons.page(Page.ofSize(25));
//getthefirstpage
List<Person>firstPage=livingPersons.list();
//getthesecondpage
List<Person>secondPage=livingPersons.nextPage().list();
Range
PanacheQuery<Person>livingPersons=Person
.find("status",Status.Alive);
List<Person>secondRange=livingPersons.range(25,49).list
();
Youcannotmixpaginationandrange.
Queries
Native MongoDB queries are supported (if they start with { ororg.bson.Document instance) aswell asPanacheQueries.PanacheQueriesequivalenceinMongoDB:
firstname=?1andstatus=?2 → {'firstname':?1,'status':?2}
amount > ?1 and firstname != ?2 → {'amount': {'$gt': ?1},'firstname':{'$ne':?2}}
lastnamelike?1 →{'lastname':{'$regex':?1}}
lastnameisnotnull →{'lastname':{'$exists':true}}
PanacheQLreferstotheObjectparameternamebutnativequeriesrefertoMongoDB�eldnames.
Projection
ProjectioncanbedoneforbothPanacheQLandnativequeries.
importio.quarkus.mongodb.panache.ProjectionFor;
@ProjectionFor(Person.class)(1)publicclassPersonName{publicStringname;}
PanacheQuery<PersonName>shortQuery=Person.find("status"
,Status.Alive).project(PersonName.class);
1 Entityclass.
Testing
Tomockusingactiverecordpattern:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-panache-mock</artifactId>
<scope>test</scope>
</dependency>
@TestpublicvoidtestPanacheMocking(){PanacheMock.mock(Person.class);
Mockito.when(Person.count()).thenReturn(23l);
Assertions.assertEquals(23,Person.count());
PanacheMock.verify(Person.class,Mockito.times(1)).coun
t();
}
DAOpattern
@ApplicationScopedpublicclassPersonRepositoryimplementsPanacheMongoRepository<Person>{}
Jandex
Ifentitiesarede�ned inexternalJAR,youneedtoenable in theseprojectstheJandex plugininproject.
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>1.0.3</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jandex</artifactId>
<version>2.1.1.Final</version>
</dependency>
</dependencies>
</plugin>
Panache includes an annotation processor that enhance yourentities. If you disable annotation processors you might need tocreate a marker �le on Panache archives at META-INF/panache-
archive.marker manually.
ReactivePanache
MongoDBwithPanacheallowsusing reactive implementation tooby using ReactivePanacheMongoEntity orReactivePanacheMongoEntityBase or ReactivePanacheMongoRepository
orReactivePanacheMongoRepositoryBase dependingonyourstyle.
publicclassReactivePersonextendsReactivePanacheMongoEntity{publicStringname;}
CompletionStage<Void>cs1=person.persist();
CompletionStage<List<ReactivePerson>>allPersons=Reactive
Person.listAll();
Publisher<ReactivePerson>allPersons=ReactivePerson.strea
mAll();
Uni<List<PersonName>> persons = ReactivePersonEntity.find(
"lastname",name).project(PersonName.class).list();
MongoDBRESTDataPanache
MongoDB REST Data with Panache extension can generate thebasicCRUDendpointsforyourentitiesandrepositories.
./mvnwquarkus:add-extension
-Dextensions="mongodb-rest-data-panache"
You also need to add the JDBC driver extension and a JSONMarshaller(ieresteasy-jackson ).
Thenyoucande�neinterfacesforde�ningendpoints:
IncaseofActiveRecordpattern:
publicinterfaceDeveloperResourceextendsPanacheMongoEntityResource<Developer,Long>{}
IncaseofRepository:
publicinterfaceDeveloperResourceextendsPanacheMongoRepositoryResource<DeveloperRepository,Developer,Long>{}
Cassandra
QuarkusintegrateswithCassandraandDataStaxObjectMapper.
<dependency>
<groupId>com.datastax.oss.quarkus</groupId>
<artifactId>cassandra-quarkus-client</artifactId>
</dependency>
Enities and DAOs are generated as you have been doing withDataStaxObjectMapper.
YouneedtocreateaDaoProducer:
@InjectpublicFruitDaoProducer(QuarkusCqlSessionsession){FruitMappermapper=newFruitMapperBuilder(session).build();
fruitDao=mapper.fruitDao();
}
@Produces@ApplicationScopedFruitDaoproduceFruitDao(){returnfruitDao;}
Cassandracon�guration:
quarkus.cassandra.contact-points=127.0.0.1:9042quarkus.cassandra.local-datacenter=datacenter1quarkus.cassandra.keyspace=k1quarkus.cassandra.auth.username=johnquarkus.cassandra.auth.password=s3cr3t
You can con�gure other Cassandra Java driver settings usingapplication.conf or application.json �les.Theyneedtobelocatedintheclasspathofyourapplication.Driversettingsreference.
If MicroPro�le Metrics extension is registered, the Cassandraextension can provide (if enabled) metrics about the session:
quarkus.cassandra.metrics.enabled=truequarkus.cassandra.metrics.session-enabled=connected-nodes,bytes-sent
quarkus.cassandra.metrics.node-enabled=pool.open-connections
Reactive
YoucanalsouseMutinytode�neareactiveDAO:
@DaopublicinterfaceFruitDaoReactive{
@UpdateUni<Void>update(Fruitfruit);
@SelectMutinyMappedReactiveResultSet<Fruit>findById(StringstoreId);
}
@MapperpublicinterfaceFruitMapper{
@DaoFactoryFruitDaoReactivefruitDaoReactive();}
ReactiveProgramming
QuarkusimplementsMicroPro�leReactivespecandusesRXJava2toprovidereactiveprogrammingmodel.
./mvnwquarkus:add-extension
-Dextensions="quarkus-smallrye-reactive-streams-operator
s"
Asynchronous HTTP endpoint is implemented by returning JavaCompletionStage .YoucancreatethisclasseithermanuallyorusingMicroPro�leReactiveStreamsspec:
@GET@Path("/reactive")@Produces(MediaType.TEXT_PLAIN)publicCompletionStage<String>getHello(){returnReactiveStreams.of("h","e","l","l","o").map(String::toUpperCase)
.toList()
.run()
.thenApply(list->list.toString());
}
Creating streams is also easy, you just need to return Publisherobject.
@GET@Path("/stream")@Produces(MediaType.SERVER_SENT_EVENTS)publicPublisher<String>publishers(){returnFlowable.interval(500,TimeUnit.MILLISECONDS)
.map(s->atomicInteger.getAndIncrement())
.map(i->Integer.toString(i));
}
MutinyandJAX-RS
Apart from the CompletionStage support, there is also support forMutiny.
./mvnwquarkus:add-extension
-Dextensions="quarkus-resteasy-mutiny"
@GET@Produces(MediaType.TEXT_PLAIN)publicUni<String>hello(){returnUni.createFrom().item(()->"hello");}
@GET@Produces(MediaType.TEXT_PLAIN)publicMulti<String>multi(){returnMulti.createFrom().items("hello","world");}
Mutiny
QuarkusintegrateswithMutinyasreactiveprogramminglibrary:
./mvnwquarkus:add-extension
-Dextensions="mutiny"
@ApplicationScopedpublicstaticclassReactiveHello{
publicUni<String>greeting(){returnUni.createFrom().item(()->"hello").emitOn(Infrastructure.getDefaultExecutor
());
}
publicMulti<String>stream(){returnMulti.createFrom().items("hello","world").emitOn(Infrastructure.getDefaultExecutor
());
}
}
Convertingfrom/toRxJava2 orReactor APIs:
RxJava2
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>mutiny-rxjava</artifactId>
</dependency>
FromRxJava2 :
Uni<Void>uniFromCompletable=Uni.createFrom()
.converter(UniRxConvert
ers.fromCompletable(),completable);
Uni<String>uniFromSingle=Uni.createFrom()
.converter(UniRxConverters.
fromSingle(),single);
Uni<String>uniFromObservable=Uni.createFrom()
.converter(UniRxConverters.
fromObservable(),observable);
Uni<String>uniFromFlowable=Uni.createFrom()
.converter(UniRxConverters.
fromFlowable(),flowable);
...
Multi<Void>multiFromCompletable=Multi.createFrom()
.converter(MultiRxC
onverters.fromCompletable(),completable);
Multi<String>multiFromObservable=Multi.createFrom()
.converter(MultiRxC
onverters.fromObservable(),observable);
Multi<String>multiFromFlowable=Multi.createFrom()
.converter(MultiRxC
onverters.fromFlowable(),flowable);
...
ToRxJava2 :
Completablecompletable=uni.convert().with(UniRxConverter
s.toCompletable());
Single<Optional<String>>single=uni.convert().with(UniRxC
onverters.toSingle());
Observable<String>observable=uni.convert().with(UniRxCon
verters.toObservable());
Flowable<String>flowable=uni.convert().with(UniRxConvert
ers.toFlowable());
...
Completablecompletable=multi.convert().with(MultiRxConve
rters.toCompletable());
Single<Optional<String>>single=multi.convert().with(Mult
iRxConverters.toSingle());
Observable<String>observable=multi.convert().with(MultiR
xConverters.toObservable());
Flowable<String>flowable=multi.convert().with(MultiRxCon
verters.toFlowable());
...
ReactorAPI
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>mutiny-reactor</artifactId>
</dependency>
FromReactor :
Uni<String>uniFromMono=Uni.createFrom().converter(UniRea
ctorConverters.fromMono(),mono);
Uni<String>uniFromFlux=Uni.createFrom().converter(UniRea
ctorConverters.fromFlux(),flux);
Multi<String> multiFromMono = Multi.createFrom().converter
(MultiReactorConverters.fromMono(),mono);
Multi<String> multiFromFlux = Multi.createFrom().converter
(MultiReactorConverters.fromFlux(),flux);
ToReactor :
Mono<String> mono = uni.convert().with(UniReactorConverter
s.toMono());
Flux<String> flux = uni.convert().with(UniReactorConverter
s.toFlux());
Mono<String>mono2=multi.convert().with(MultiReactorConve
rters.toMono());
Flux<String>flux2=multi.convert().with(MultiReactorConve
rters.toFlux());
CompletionStagesorPublisher
CompletableFuture<String>future=Uni
.createFrom().completionStage(CompletableFuture.sup
plyAsync(()->"hello"));
CompletationStage<String>cs=Uni
.createFrom().subscribeAsCompletionStage();
Multi implementsPublisher .
RESTEasyReactive
RESTEasy Reactive is a new implementation of JAX-RS but fullyreactive.
mvnquarkus:add-extension
-Dextensions="quarkus-resteasy-reactive"
packageorg.acme.rest;importjavax.ws.rs.GET;importjavax.ws.rs.Path;@Path("rest")publicclassEndpoint{
@Path("hello")@GETpublicStringhello(){//executedinevent-loop
return"Hello,World!";}
@GETpublicUni<Book>culinaryGuide(){//executedinevent-loopbutnotblocking
returnBook.findByIsbn("978-2081229297");}
@io.smallrye.common.annotation.Blocking@GETpublicStringblockingHello()throwsInterruptedException{
//executedinworker-thread
return"Yaaaawwwwnnnnnn…";}
}
ReactiveMessaging
Quarkus relies on MicroPro�le Reactive Messaging spec toimplementreactivemessagingstreams.
mvnquarkus:add-extension
-Dextensions="
io.quarkus:quarkus-smallrye-reactive-messaging"
Youcan juststartusing in-memorystreamsbyusing @Incoming toproducedataand@Outgoing toconsumedata.
Produceevery5secondsonepieceofdata.
@ApplicationScopedpublicclassProducerData{
@Outgoing("my-in-memory")publicFlowable<Integer>generate(){returnFlowable.interval(5,TimeUnit.SECONDS).map(tick->random.nextInt(100));
}
}
orinMutiny:
@ApplicationScopedpublicclassProducerData{@Outgoing("my-in-memory")publicMulti<Integer>generate(){returnMulti.createFrom().ticks().every(Duration.ofSeconds(5))
.onItem().apply(n->random.nextInt(100));
}
}
If you want to dispatch to all subscribers you can annotate themethodwith@Broadcast .
Consumesgenerateddatafrommy-in-memory stream.
@ApplicationScopedpublicclassConsumerData{@Incoming("my-in-memory")publicvoidrandomNumber(intrandomNumber){System.out.println("Received"+randomNumber);
}
}
Youcanalsoinjectanstreamasa�eld:
@Inject@Stream("my-in-memory")Publisher<Integer>randomRumbers;
@Inject@Stream("generated-price")Emitter<String>emitter;
Patterns
RESTAPI→Message
@Inject@Stream(“in”)Emitter<String>emitter;
emitter.send(message);
Message→Message
@Incoming(“in”)@Outgoing(“out”)publicStringprocess(Stringin){}
Message→SSE
@Inject@Stream(“out”)Publisher<String>result;
@GET@Produces(SERVER_SENT_EVENTS)publicPublisher<String>stream(){returnresult;}
Message→BusinessLogic
@ApplicationScopedpublicclassReceiverMessages{@Incoming("prices")publicvoidprint(Stringprice){}
}
To indicate that themethodshouldbeexecutedonaworkerpoolyoucanuse@Blocking :
@Outgoing("Y")@Incoming("X")@Blocking
Tocustomize:
@Blocking(value="my-custom-pool",ordered=false)
smallrye.messaging.worker.my-custom-pool.max-concurrency=3
Possibleimplementationsare:
In-Memory
If the stream is not con�gured then it is assumed to be an in-memory stream, if not then stream type is de�ned by connector�eld.
Kafka
TointegratewithKafkayouneedtoaddnextextensions:
mvnquarkus:add-extension
-Dextensions="
io.quarkus:quarkus-smallrye-reactive-messaging-kafka"
Then@Outgoing ,@Incoming or@Stream canbeused.
Kafka con�guration schema: mp.messaging.[outgoing|incoming].
{stream-name}.<property>=<value> .
Theconnector typeissmallrye-kafka .
mp.messaging.outgoing.generated-price.connector=smallrye-kafka
mp.messaging.outgoing.generated-price.topic=prices
mp.messaging.outgoing.generated-price.bootstrap.servers=localhost:9092mp.messaging.outgoing.generated-price.value.serializer=org.apache.kafka.common.serialization.IntegerSerializer
mp.messaging.incoming.prices.connector=smallrye-kafka
mp.messaging.incoming.prices.value.deserializer=org.apache.kafka.common.serialization.IntegerDeserializ
er
A complete list of supported properties are in Kafka site. For theproducerandforconsumer
JSON-BSerializer/Deserializer
YoucanuseJSON-Btoserialize/deserializeobjects.
./mvnwquarkus:add-extension
-Dextensions="quarkus-kafka-client"
To serialize you can useio.quarkus.kafka.client.serialization.JsonbSerializer .
To deserialize you need to extendio.quarkus.kafka.client.serialization.JsonbDeserializer andprovideatype.
publicclassBeerDeserializerextendsJsonbDeserializer<Beer>{
publicBeerDeserializer(){super(Beer.class);}
}
AMQP
TointegratewithAMQPyouneedtoaddnextextensions:
./mvnwquarkus:add-extension
-Dextensions="reactive-messaging-amqp"
Then@Outgoing ,@Incoming or@Stream canbeused.
AMQP con�guration schema: mp.messaging.[outgoing|incoming].
{stream-name}.<property>=<value> . Special properties amqp-usernameandamqp-password areusedtocon�gureAMQPbrokercredentials.
Theconnectortypeissmallrye-amqp .
amqp-username=quarkusamqp-password=quarkus#write
mp.messaging.outgoing.generated-price.connector=smallrye-amqp
mp.messaging.outgoing.generated-price.address=prices
mp.messaging.outgoing.generated-price.durable=true
#read
mp.messaging.incoming.prices.connector=smallrye-amqp
mp.messaging.incoming.prices.durable=true
AcompletelistofsupportedpropertiesforAMQP.
MQTT
TointegratewithMQTTyouneedtoaddnextextensions:
./mvnwquarkus:add-extension
-Dextensions="vertx,smallrye-reactive-streams-operator
s
smallrye-reactive-messaging"
And add io.smallrye.reactive:smallrye-reactive-messaging-mqtt-
1.0:0.0.10 dependencyinyourbuildtool.
Then@Outgoing ,@Incoming or@Stream canbeused.
MQTT con�guration schema: mp.messaging.[outgoing|incoming].
{stream-name}.<property>=<value> .
Theconnectortypeissmallrye-mqtt .
mp.messaging.outgoing.topic-price.type=smallrye-mqtt
mp.messaging.outgoing.topic-price.topic=prices
mp.messaging.outgoing.topic-price.host=localhost
mp.messaging.outgoing.topic-price.port=1883
mp.messaging.outgoing.topic-price.auto-generated-client-id=true
mp.messaging.incoming.prices.type=smallrye-mqtt
mp.messaging.incoming.prices.topic=prices
mp.messaging.incoming.prices.host=localhost
mp.messaging.incoming.prices.port=1883
mp.messaging.incoming.prices.auto-generated-client-id=true
KafkaStreams
CreatestreamingquerieswiththeKafkaStreamsAPI.
./mvnwquarkus:add-extension
-Dextensions="kafka-streams"
All we need to do for that is to declare a CDI producer methodwhich returns the Kafka Streamsorg.apache.kafka.streams.Topology :
@ApplicationScopedpublicclassTopologyProducer{@ProducespublicTopologybuildTopology(){org.apache.kafka.streams.StreamsBuilder.StreamsBuil
der
builder=newStreamsBuilder();//...
builder.stream()
.join()
//...
.toStream()
.to();
returnbuilder.build();}
}
Previousexampleproducescontenttoanotherstream.Ifyouwanttowriteinteractivequeries,youcanuseKafkastreams.
@InjectKafkaStreamsstreams;
returnstreams.store("stream",QueryableStoreTypes.keyValueStore
());
The Kafka Streams extension is con�gured via the Quarkuscon�guration�leapplication.properties .
quarkus.kafka-streams.bootstrap-servers=localhost:9092quarkus.kafka-streams.application-id=temperature-aggregatorquarkus.kafka-streams.application-server=${hostname}:8080quarkus.kafka-streams.topics=weather-stations,temperature-values
kafka-streams.cache.max.bytes.buffering=10240kafka-streams.commit.interval.ms=1000
IMPORTANT: All the properties within the kafka-streams
namespacearepassedthroughas-istotheKafkaStreamsengine.Changingtheirvaluesrequiresarebuildoftheapplication.
ReactiveDataSourceProperties
Common Reeactive DataSource Client con�guration propertiespre�xedwithquarkus.datasource :
reactive.cache-prepared-statements
Prepared statements should be cached on the client side.(default:false )
reactive.url
ThedatasourceURL.
reactive.max-size
Thedatasourcepoolmaximumsize.
reactive.trust-all
Allservercerti�catesshouldbetrusted.(default:false )
reactive.trust-certificate-pem
Trustcon�gurationinthePEMformat.
reactive.trust-certificate-jks
Trustcon�gurationintheJKSformat.
reactive.trust-certificate-pfx
Trustcon�gurationinthePFXformat.
reactive.key-certificate-pem
Key/certcon�gurationinthePEMformat.
reactive.key-certificate-jks
Key/certcon�gurationintheJKSformat.
reactive.key-certificate-pfx
Key/certcon�gurationinthePFXformat.
reactive.thread-local
Useoneconnectionpoolperthread.
reactive.reconnect-attempts
Thenumberofreconnectionattemptswhenapooledconnectioncannotbeestablishedon�rsttry.(default:0 )
reactive.reconnect-interval
The interval between reconnection attempts when a pooledconnectioncannotbeestablishedon�rsttry.(default:PT1S )
reactive.idle-timeout
The maximum time without data written to or read from aconnectionbeforeitisremovedfromthepool.
ReactivePostgreSQLClient
YoucanuseReactivePostgreSQLtoexecutequeriestoPostreSQLdatabaseinareactiveway,insteadofusingJDBCway.
./mvnwquarkus:add-extension
-Dextensions="quarkus-reactive-pg-client"
Database con�guration is the same as shown in Persistencesection,butURLisdifferentasitisnotajdbc.
quarkus.datasource.db-kind=postgresqlquarkus.datasource.reactive.url=postgresql:///your_database
Thenyoucaninjectio.vertx.mutiny.pgclient.PgPool class.
@InjectPgPoolclient;
Uni<List<Fruit>>fruits=
client.preparedQuery("SELECT*FROMfruits")
.onItem().apply(rowSet->{
JsonArrayjsonArray=newJsonArray();for(Rowrow:rowSet){jsonArray.add(from(row));
}
returnjsonArray;})
ReactiveMySQLClient
You can use Reactive MySQL to execute queries to MySQLdatabaseinareactiveway,insteadofusingJDBC.
./mvnwquarkus:add-extension
-Dextensions="quarkus-reactive-mysql-client"
Database con�guration is the same as shown in Persistencesection,butURLisdifferentasitisnotajdbc.
quarkus.datasource.db-kind=mysqlquarkus.datasource.reactive.url=mysql:///your_database
Thenyoucaninjectio.vertx.mutiny.mysqlclient.MySQLPool class.
ReactiveDB2Client
YoucanuseReactiveDB2toexecutequeriestoDB2databaseinareactiveway,insteadofusingJDBC.
./mvnwquarkus:add-extension
-Dextensions="quarkus-reactive-db2-client"
Database con�guration is the same as shown in Persistencesection,butURLisdifferentasitisnotajdbc.
quarkus.datasource.db-kind=db2quarkus.datasource.reactive.url=vertx-reactive:db2://localhost:50005/hreact
Then you can inject i i db2 li 2 l class
ReactiveTransactions
io.vertx.mutiny.sqlclient.SqlClientHelper is an util class thatallowsyoutorunreactivepersistencodewithinatransaction.
Uni<Void>r=SqlClientHelper.inTransactionUni(client,tx-
>{
Uni<RowSet<Row>>insertOne=tx.preparedQuery("INSE
RTINTOfruits(name)VALUES($1)RETURNING(id)")
.execute(Tuple.of(fruit1.name));
});
ActiveMQArtemis
Quarkus uses Reactive Messaging to integrate with messagingsystems,but incaseyouneeddeepercontrolwhenusingApacheActiveMQArtemisthereisalsoanextension:
./mvnwquarkus:add-extension
-Dextensions="quarkus-artemis-core"
And then you can injectorg.apache.activemq.artemis.api.core.client.ServerLocator
instance.
@ApplicationScopedpublicclassArtemisConsumerManager{
@InjectServerLocatorserverLocator;
privateClientSessionFactoryconnection;
@PostConstructpublicvoidinit()throwsException{connection=serverLocator.createSessionFactory();
}
}
Andcon�gureServerLocator inapplication.properties :
quarkus.artemis.url=tcp://localhost:61616
Youcancon�gureActiveMQArtemis in application.properties �lebyusingnextpropertiespre�xedwithquarkus :
artemis.url
ConnectionURL.
artemis.username
Usernameforauthentication.
artemis.password
Passwordforauthentication.
ArtemisJMS
If you want to use JMS with Artemis, you can do it by using itsextension:
./mvnwquarkus:add-extension
-Dextensions="quarkus-artemis-jms"
Andthenyoucaninjectjavax.jms.ConnectionFactory :
@ApplicationScopedpublicclassArtemisConsumerManager{
@InjectConnectionFactoryconnectionFactory;
privateConnectionconnection;
@PostConstructpublicvoidinit()throwsJMSException{connection=connectionFactory.createConnection();
connection.start();
}
}
Con�gurationoptionsarethesameasArtemiscore.
Vert.XReactiveClients
Vert.X Reactive clients in Quarkus, the next clients are supportedandyouneedtoaddthedependencytousethem:
Vert.XMailClientio.smallrye.reactive:smallrye-mutiny-vertx-mail-client
Vert.XMongoDBClientio.smallrye.reactive:smallrye-mutiny-vertx-mongo-client
Vert.XRedisClientio.smallrye.reactive:smallrye-mutiny-vertx-redis-client
Vert.XCassandraClientio.smallrye.reactive:smallrye-mutiny-vertx-cassandra-client
Vert.XConsulClientio.smallrye.reactive:smallrye-mutiny-vertx-consul-client
Vert.XKafkaClientio.smallrye.reactive:smallrye-mutiny-vertx-kafka-client
Vert.XAMQPClientio.smallrye.reactive:smallrye-mutiny-vertx-amqp-client
Vert.XRabbitMQClientio.smallrye.reactive:smallrye-mutiny-vertx-rabbitmq-client
ExampleofVert.XWebClient:
@InjectVertxvertx;
privateWebClientclient;
@PostConstructvoidinitialize(){this.client=WebClient.create(vertx,...);}
AmazonSQSClient
./mvnwquarkus:add-extension
-Dextensions="amazon-sqs"
Injectingtheclient:
@Injectsoftware.amazon.awssdk.services.sqs.SqsClientsqs;
SendMessageResponseresponse=sqs.sendMessage(m->m.queue
Url(queueUrl).messageBody(message));
List<Message>messages=sqs.receiveMessage(m->m.maxNumbe
rOfMessages(10).queueUrl(queueUrl)).messages();
Andcon�gureit:
quarkus.sqs.endpoint-override=http://localhost:8010quarkus.sqs.aws.region=us-east-1quarkus.sqs.aws.credentials.type=staticquarkus.sqs.aws.credentials.static-provider.access-key-id=test-key
quarkus.sqs.aws.credentials.static-provider.secret-access-key=test-secret
YouneedtosetaHTTPclienteitherURLConnection :
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
orApacheHTTP:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
quarkus.sqs.sync-client.type=apache
YoucangoasyncbyusingMutiny:
@Injectsoftware.amazon.awssdk.services.sqs.SqsAsyncClientsqs;
Uni.createFrom()
.completionStage(
sqs.sendMessage(m->m.queueUrl(queueUrl).messageBo
dy(message))
)
.onItem()...
returnUni.createFrom().completionStage(
sqs.receiveMessage(m->m.maxNumberOfMessages(10).q
ueueUrl(queueUrl))
)
.onItem()
AndyouneedtoaddtheasynchronousNettyclient:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
Con�gurationpropertiesare thesameasAmazonDynamoDB butchangingthepre�xfromdynamodb tosqs .
TLS
You can trust all certi�cates globally by using quarkus.tls.trust-all=true
RBAC
YoucansetRBACusingannotationsorinapplication.properties .
Annotations
You can de�ne roles by usingjavax.annotation.security.RolesAllowed annotation.
@RolesAllowed("Subscriber")
You can use io.quarkus.security.Authenticated as a shortcut of@RolesAllowed("*") .
ToalterRBACbehaviourtherearetwocon�gurationproperties:
quarkus.security.deny-unannotated=true
Con�gurationoptions:
quarkus.jaxrs.deny-uncovered
IftruedeniesbydefaulttoallJAX-RSendpoints.(default:false )
quarkus.security.deny-unannotated
IftruedeniesbydefaultallCDImethodsandJAX-RSendpoints.(default:false )
Bydefault inQuarkus, ifan incoming requesthasacredential therequestwillalwaysbeauthenticated(even if thetargetpagedoesnotrequireauthentication).
You can change this behaviour by settingquarkus.http.auth.proactive propertytofalse .
FileCon�guration
De�ning RBAC in application.properties instead of usingannotations.
quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin
quarkus.http.auth.permission.roles1.paths=/roles-secured/*,/other/*,/api/*
quarkus.http.auth.permission.roles1.policy=role-policy1
quarkus.http.auth.permission.permit1.paths=/public/*
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET
quarkus.http.auth.permission.deny1.paths=/forbidden
quarkus.http.auth.permission.deny1.policy=deny
You need to provide permissions set by using the roles-allowedpropertyorusethebuilt-inonesdeny ,permit orauthenticated .
You can use enabled property (iequarkus.http.auth.permission.permit1.enabled ) to enable the entirepermissionset.
Testing
Quarkus provides explicit support for testingwith different users,andwiththesecuritysubsystemdisabled.
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security</artifactId>
<scope>test</scope>
</dependency>
@Test@TestSecurity(authorizationEnabled=false)voidsomeTestMethod(){...
}
@Test@TestSecurity(user="testUser",roles={"admin","user"})voidsomeTestMethod(){...
}
BouncyCastle
Quarkus supports BouncyCastle, you only need to add theBouncyCastledependencyandcon�gurethesecurityprovider:
quarkus.security.security-providers=BCquarkus.security.security-providers=BCJSSEquarkus.security.security-providers=BCFIPSquarkus.security.security-providers=BCFIPSJSSE
JWT
QuarkusimplementsMicroPro�leJWTRBACspec.
mvnquarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-jwt"
Minimum JWT required claims: typ , alg , kid , iss , sub , exp , iat ,jti ,upn ,groups .
YoucaninjecttokenbyusingJsonWebToken oraclaimindividuallybyusing@Claim .
@InjectJsonWebTokenjwt;
@Inject@Claim(standard=Claims.preferred_username)Stringname;
@Inject@Claim("groups")Set<String>groups;
@InjectJWTParserparser;
Set of supported types: String , Set<String> , Long , Boolean,
`javax.json.JsonValue , Optional ,org.eclipse.microprofile.jwt.ClaimValue .
Andcon�gurationinsrc/main/resources/application.properties :
mp.jwt.verify.publickey.location=META-INF/resources/publicKey.pem
mp.jwt.verify.issuer=https://quarkus.io/using-jwt-rbac
Con�gurationoptions:
mp.jwt.verify.publickey
PublicKeytextitselftobesuppliedasastring.
mp.jwt.verify.publickey.location Relative path or URL of a publickey.
mp.jwt.verify.issuer
iss acceptedasvalid.
smallrye.jwt.token.header
Setsheadersuchas Cookie isused topass the token. (default:Authorization ).
smallrye.jwt.token.cookie
Nameofthecookiecontainingatoken.
smallrye.jwt.token.schemes
Comma-separatedlistcontaininganalternativesingleormultipleschemes.(default:Bearer ).
smallrye.jwt.require.named-principal
Atokenmusthaveaupnorpreferred_usernameorsubclaimsetifusing java.security.Principal . True makesthrowanexceptionifnotset.(default:false ).
smallrye.jwt.path.sub
Pathtotheclaimwithsubjectname.
smallrye.jwt.claims.sub
Defaultsubclaimvalue.
smallrye.jwt.path.groups
Pathtotheclaimcontainingthegroups.
smallrye.jwt.groups-separator
Separatorforsplittingastringwhichmaycontainmultiplegroupvalues.(default.``).
smallrye.jwt.claims.groups
Defaultgroupsclaimvalue.
smallrye.jwt.jwks.refresh-interval
JWKcacherefreshintervalinminutes.(default:60 ).
smallrye.jwt.expiration.grace
Expirationgraceinseconds.(default:60 ).
smallrye.jwt.verify.aud
Comma separated list of the audiences that a token aud claimmaycontain.
smallrye.jwt.verify.algorithm
Signaturealgorith.(defsult:RS256 )
smallrye.jwt.token.kid
Ifsetthentheveri�cationJWKkeyaswelleveryJWTtokenmusthaveamatchingkid header.
smallrye.jwt.time-to-live
ThemaximumnumberofsecondsthataJWTmaybeissuedforuse.
smallrye.jwt.sign.key-location
Locationof a private keywhichwill be used to sign the claimswhen either a no-argument sign() or innerSign() method iscalled.
smallrye.jwt.encrypt.key-location
LocationofapublickeywhichwillbeusedtoencrypttheclaimsorinnerJWTwhenano-argumentencrypt() methodiscalled.
Supportedpublickeyformats:
PKCS#8PEM
JWK
JWKS
JWKBase64URL
JWKSBase64URL
To send a token to server-side you should use Authorization
header:curl-H"Authorization:BearereyJraWQiOi…" .
To inject claim values, the bean must be @RequestScoped CDIscoped. Ifyouneedto injectclaimvalues inscopewitha lifetimegreater than @RequestScoped then you need to usejavax.enterprise.inject.Instance interface.
@Inject@Claim(standard=Claims.iat)privateInstance<Long>providerIAT;
RBAC
JWTgroups claimisdirectlymappedtorolestobeusedinsecurityannotations.
@RolesAllowed("Subscriber")
Generatetokens
JWTgenerationAPI:
Jwt.claims()
.issuer("https://server.com")
.claim("customClaim",3)
.sign(createKey());
JwtSignatureBuilderjwtSignatureBuilder=Jwt.claims("/test
JsonToken.json").jws();
jwtSignatureBuilder
.signatureKeyId("some-key-id")
.signatureAlgorithm(SignatureAlgorithm.ES256)
.header("custom-header","custom-value");
.sign(createKey());
Jwt.claims("/testJsonToken.json")
.encrypt(createKey());
JwtEncryptionBuilderjwtEncryptionBuilder=Jwt.claims("/te
stJsonToken.json").jwe();
jwtEncryptionBuilder
.keyEncryptionKeyId("some-key-id")
.keyEncryptionAlgorithm(KeyEncryptionAlgorithm.ECDH_E
S_A256KW)
.header("custom-header","custom-value");
.encrypt(createKey());
Jwt.claims("/testJsonToken.json")
.innerSign(createKey());
.encrypt(createKey());
OpenIdConnect
Quarkus can use OpenId Connect or OAuth 2.0 authorizationserverssuchasKeycloak toprotect resourcesusingbearer tokenissuedbyKeycloakserver.
mvnquarkus:add-extension
-Dextensions="using-openid-connect"
Youcanalsoprotectresourceswithsecurityannotations.
@GET@RolesAllowed("admin")
Con�gureapplicationtoKeycloakservicein application.properties�le.
quarkus.oidc.realm=quarkusquarkus.oidc.auth-server-url=http://localhost:8180/authquarkus.oidc.resource=backend-servicequarkus.oidc.bearer-only=truequarkus.oidc.credentials.secret=secret
Con�gurationoptionswithquarkus.oidc pre�x:
enabled
The OIDC is enabled. (default: true )
tenant-enabled
Ifthetenantcon�gurationisenabled.(default:true )
application-type
Theapplicationtype.Possiblevalues: web_app , service . (default:service )
connection-delay
Themaximumamountoftimetheadapterwilltryconnecting.
auth-server-url
ThebaseURLoftheOpenIDConnect(OIDC)server.
introspection-path
RelativepathoftheRFC7662introspectionservice.
jwks-path
RelativepathoftheOIDCservicereturningaJWKset.
public-key
PublickeyforthelocalJWTtokenveri�cation
client-id
Theclient-idoftheapplication.
roles.role-claim-path
Pathtotheclaimcontaininganarrayofgroups.(realm/groups )
roles.role-claim-separator
Separatorforsplittingastringwhichmaycontainmultiplegroupvalues.
token.issuer
Issuerclaimvalue.
token.audience
Audienceclaimvalue.
token.expiration-grace
Expirationgraceperiodinseconds.
token.principal-claim
Nameoftheclaimwhichcontainsaprincipalname.
token.refresh-expired
Ifpropertyisenabledthenarefreshtokenrequestisperformed.
credentials.secret
Theclientsecret
authentication.redirect-path
Relativepathforcalculatingaredirect_uri queryparameter.
authentication.restore-path-after-redirect
The original request URI used before the authenticationwill berestored after the user has been redirected back to theapplication.(default:true )
authentication.scopes
Listofscopes.
authentication.extra-params
Additional properties which will be added as the queryparameters.
authentication.cookie-path
Cookiepathparameter.
proxy.host
Thehost(nameorIPaddress)oftheProxy.
proxy.port
TheportnumberoftheProxy.(default:80 )
proxy.username
Theusernametoauthenticate.
proxy.password
Thepasswordtoauthenticate.
end-session-path
RelativepathoftheOIDCend_session_endpoint .
logout.path
Therelativepathofthelogoutendpointattheapplication.
logout.post-logout-path
Relativepathof theapplicationendpointwhere theusershouldberedirectedtoafterloggingout.
tls.verification
Sets the TLs veri�cation. Possible values: REQUIRED , NONE .(default:REQUIRED ).
With Keycloak OIDC serverhttps://host:port/auth/realms/{realm} where {realm} hastobereplacedbythenameoftheKeycloakrealm.You can use quarkus.http.cors property to enableconsumingformdifferentdomain.
Multi-tenancy
Multi-tenancy is supported by adding a sub-category to OIDCcon�gurationproperties(iequarkus.oidc.{tenent_id}.property ).
quarkus.oidc.auth-server-url=http://localhost:8180/auth/realms/quarkus
quarkus.oidc.client-id=multi-tenant-clientquarkus.oidc.application-type=web-app
quarkus.oidc.tenant-b.auth-server-url=https://accounts.google.com
quarkus.oidc.tenant-b.application-type=web-appquarkus.oidc.tenant-b.client-id=xxxxquarkus.oidc.tenant-b.credentials.secret=yyyyquarkus.oidc.tenant-b.token.issuer=https://accounts.google.com
quarkus.oidc.tenant-b.authentication.scopes=email,profile,openid
OAuth2
Quarkus integrates with OAuth2 to be used in case of opaquetokens (none JWT) and its validation against an introspectionendpoint.
mvnquarkus:add-extension
-Dextensions="security-oauth2"
Andcon�gurationinsrc/main/resources/application.properties :
quarkus.oauth2.client-id=client_idquarkus.oauth2.client-secret=secretquarkus.oauth2.introspection-url=http://oauth-server/introspect
Andyoucanmaprolestobeusedinsecurityannotations.
@RolesAllowed("Subscriber")
Con�gurationoptions:
quarkus.oauth2.enabled
DetermineiftheOAuth2extensionisenabled.(default:true )
quarkus.oauth2.client-id
TheOAuth2clientidusedtovalidatethetoken.
quarkus.oauth2.client-secret
TheOAuth2clientsecretusedtovalidatethetoken.
quarkus.oauth2.introspection-url
URL used to validate the token and gather the authenticationclaims.
quarkus.oauth2.role-claim
Theclaimthatisusedintheendpointresponsetoloadtheroles((default:scope )
AuthenticatingviaHTTP
HTTP basic auth is enabled by the quarkus.http.auth.basic=trueproperty.
HTTP form auth is enabled by thequarkus.http.auth.form.enabled=true property.
Thenyouneedtoadd elytron-security-properties-file or elytron-security-jdbc .
SecuritywithPropertiesFile
Youcanalsoprotectendpointsandstore identities(user, roles) inthe�lesystem.
mvnquarkus:add-extension
-Dextensions="elytron-security-properties-file"
Youneedtocon�guretheextensionwithusersandroles�les:
Andcon�gurationinsrc/main/resources/application.properties :
quarkus.security.users.file.enabled=truequarkus.security.users.file.users=test-users.propertiesquarkus.security.users.file.roles=test-roles.propertiesquarkus.security.users.file.auth-mechanism=BASICquarkus.security.users.file.realm-name=MyRealmquarkus.security.users.file.plain-text=true
Thenusers.properties androles.properties :
scott=jb0ssjdoe=p4ssw0rd
scott=Admin,admin,Tester,userjdoe=NoRolesUser
IMPORTANT: If plain-text is set to false (or omitted) thenpasswords must be stored in the form MD5(username :`realm`:`password`).
Elytron File Properties con�guration properties. Pre�xquarkus.security.users isskipped.
file.enabled
The�lerealmisenabled.(default:false )
file.auth-mechanism
Theauthenticationmechanism.(default:BASIC )
file.realm-name
Theauthenticationrealmname.(default:Quarkus )
file.plain-text
IfpasswordsareinplainorinMD5.(default:false )
file.users
Classpath resource of user/password. (default:users.properties )
file.roles
Classpathresourceofuser/role.(default:roles.properties )
EmbeddedRealm
You can embed user/password/role in the sameapplication.properties :
quarkus.security.users.embedded.enabled=truequarkus.security.users.embedded.plain-text=truequarkus.security.users.embedded.users.scott=jb0ssquarkus.security.users.embedded.roles.scott=admin,tester,user
quarkus.security.users.embedded.auth-mechanism=BASIC
IMPORTANT: If plain-text is set to false (or omitted) thenpasswords must be stored in the form MD5(username :`realm`:`password`).
Pre�xquarkus.security.users.embedded isskipped.
algorithm
Determine which algorithm to use. Possible values: DIGEST_MD5 ,DIGEST_SHA , DIGEST_SHA_256 , DIGEST_SHA_384 , DIGEST_SHA_512 ,DIGEST_SHA_512_256 .(default:DIGEST_MD5 )
file.enabled
The�lerealmisenabled.(default:false )
file.auth-mechanism
Theauthenticationmechanism.(default:BASIC )
file.realm-name
Theauthenticationrealmname.(default:Quarkus )
file.plain-text
IfpasswordsareinplainorinMD5.(default:false )
file.users.*
* isuserandvalueispassword.
file.roles.*
* isuserandvalueisrole.
SecuritywithaJDBCRealm
Youcanalsoprotectendpointsandstoreidentitiesinadatabase.
mvnquarkus:add-extension
-Dextensions="elytron-security-jdbc"
Youstillneedtoaddthedatabasedriver(iejdbc-h2 ).
Youneedtocon�gureJDBCandElytronJDBCRealm:
quarkus.datasource.url=quarkus.datasource.driver=org.h2.Driverquarkus.datasource.username=saquarkus.datasource.password=sa
quarkus.security.jdbc.enabled=truequarkus.security.jdbc.principal-query.sql=SELECTu.password,u.roleFROMtest_useruWHEREu.user=?
quarkus.security.jdbc.principal-query
.clear-password-mapper.enabled=truequarkus.security.jdbc.principal-query
.clear-password-mapper.password-index=1quarkus.security.jdbc.principal-query
.attribute-mappings.0.index=2quarkus.security.jdbc.principal-query
.attribute-mappings.0.to=groups
Youneedtosettheindex(1-based)ofpasswordandrole.
Elytron JDBC Realm con�guration properties. Pre�xquarkus.security.jdbc isskipped.
auth-mechanism
Theauthenticationmechanism.(default:BASIC )
realm-name
Theauthenticationrealmname.(default:Quarkus )
enabled
Ifthepropertiesstoreisenabled.(default:false )
principal-query.sql
Thesqlqueryto�ndthepassword.
principal-query.datasource
Thedatasourcetouse.
principal-query.clear-password-mapper.enabled
Iftheclear-password-mapperisenabled.(default:false )
principal-query.clear-password-mapper.password-index
Theindexofcolumncontainingclearpassword.(default:1 )
principal-query.bcrypt-password-mapper.enabled
Ifthebcrypt-password-mapperisenabled.(default:false )
principal-query.bcrypt-password-mapper.password-index
Theindexofcolumncontainingpasswordhash.(default:0 )
principal-query.bcrypt-password-mapper.hash-encoding
Astringreferencingthepasswordhashencoding(BASE64 or HEX ).(default:BASE64 )
principal-query.bcrypt-password-mapper.salt-index
TheindexcolumncontainingtheBcryptsalt.(default:0 )
principal-query.bcrypt-password-mapper.salt-encoding
A string referencing the salt encoding (BASE64 or HEX ). (default:BASE64 )
principal-query.bcrypt-password-mapper.iteration-count-index
TheindexcolumncontainingtheBcryptiterationcount.(default:0 )
Formultipledatasourcesyoucanusethedatasourcename in theproperties:
quarkus.datasource.url=quarkus.security.jdbc.principal-query.sql=
quarkus.datasource.permissions.url=quarkus.security.jdbc.principal-query.permissions.sql=
SecuritywithJPA
Youcanalsoprotectendpointsandstore identities inadatabaseusingJPA.
mvnquarkus:add-extension
-Dextensions="security-jpa"
Also you might require jdbc-postgresql , resteasy ,hibernate-orm-panache .
@io.quarkus.security.jpa.UserDefinition@Table(name="test_user")@EntitypublicclassUserextendsPanacheEntity{@io.quarkus.security.UsernamepublicStringname;
@io.quarkus.security.PasswordpublicStringpass;
@ManyToMany@RolespublicList<Role>roles=newArrayList<>();
publicstaticvoidadd(Stringusername,Stringpassword){
Useruser=newUser();user.username=username;
user.password=BcryptUtil.bcryptHash(password);
user.persist();
}
}
@EntitypublicclassRoleextendsPanacheEntity{
@ManyToMany(mappedBy="roles")publicList<ExternalRolesUserEntity>users;
@io.quarkus.security.RolesValuepublicStringrole;}
Youneedtocon�gureJDBC:
quarkus.datasource.url=jdbc:postgresql:security_jpaquarkus.datasource.driver=org.postgresql.Driverquarkus.datasource.username=quarkusquarkus.datasource.password=quarkus
quarkus.hibernate-orm.database.generation=drop-and-create
SecuritywithLDAP
Youcanalsoprotectendpointsandstore identities inadatabaseusingLDAP.
mvnquarkus:add-extension
-Dextensions="elytron-security-ldap"
quarkus.security.ldap.enabled=truequarkus.security.ldap.dir-context.principal=uid=tool,ou=accounts,o=YourCompany,c=DE
quarkus.security.ldap.dir-context.url=ldaps://ldap.server.local
quarkus.security.ldap.dir-context.password=PASSWORDquarkus.security.ldap.identity-mapping.rdn-identifier=uidquarkus.security.ldap.identity-mapping.search-base-dn=ou=users,ou=tool,o=YourCompany,c=DE
quarkus.security.ldap.identity-mapping.attribute-mappings."0".from=cnquarkus.security.ldap.identity-mapping.attribute-mappings."0".to=groupsquarkus.security.ldap.identity-mapping.attribute-mappings."0".filter=(member=uid={0})quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter-base-dn=ou=roles,ou=tool,o=YourCompany,c=DE
Testing
ThereisaQuarkusTestResourcethatstartsandstopsInMemoryLDAPserver before andafter test suite. It is running in localhostwith dc=quarkus,dc=io and binding credentials("uid=admin,ou=system","secret" ). ImportsLDIF froma�le locatedatrootoftheclasspathnamedquarkus-io.ldif .
Registerdependencyio.quarkus:quarkus-test-ldap:test.
Andannotatethetest:
@QuarkusTestResource(io.quarkus.test.ldap.LdapServerTestResource.class)
publicclassElytronLdapExtensionTestResources{}
Elytron LDAP Realm con�guration properties. Pre�xquarkus.security.ldap isskipped.
enabled
EnabletheLDAPelytronmodule(default:false )
realm-name
Theelytronrealmname(default:Quarkus )
direct-verification
Providedcredentialsareveri�edagainstLDAP(default:true )
dir-context.url
TheurloftheLDAPserver.
dir-context.principal
User(bindDn )whichisusedtoconnecttoLDAPserver.
dir-context.password
Thepassword(bindCredential )whichbelongstotheprincipal.
identity-mapping.rdn-identifier
The identi�er (baseFilter )whichcorrelates to theprovideduser(default:uid )
identity-mapping.search-base-dn
Thednwherewelookforusers.
identity-mapping.attribute-mappings.<id>.from
TheroleAttributeId fromwhichismapped
identity-mapping.attribute-mappings.<id>.to
Theidenti�erwhomtheattributeismappedto(default:gropus )
identity-mapping.attribute-mappings.<id>.filter
The�lter(roleFilter )
identity-mapping.attribute-mappings.<id>.filter-base-dn
The�lterbasedn(rolesContextDn )
Vault
Quarkus integrates with Vault to manage secrets or protectingsensitivedata.
mvnquarkus:add-extension
-Dextensions="vault"
Andcon�guringVaultinapplication.properties :
#vaulturl
quarkus.vault.url=http://localhost:8200
quarkus.vault.authentication.userpass.username=bob
quarkus.vault.authentication.userpass.password=sinclair
#pathwithinthekvsecretengine
quarkus.vault.secret-config-kv-path=myapps/vault-quickstart/config
quarkus.vault.secret-config-kv-prefix.singer.paths=multi/singer1,multi/singer2
vault kv put secret/myapps/vault-quickstart/config a-private-
key=123456
vaultkvputsecret/multi/singer1firstname=paul
@ConfigProperty(name="a-private-key")StringprivateKey;
@ConfigProperty(name="singer.firstname")StringfirstName;
YoucanaccesstheKVengineprogrammatically:
@InjectVaultKVSecretEnginekvSecretEngine;
kvSecretEngine.readSecret("myapps/vault-quickstart/" + vaul
tPath).toString();
Map<String,String>secrets;
kvSecretEngine.writeSecret("myapps/vault-quickstart/crud",
secrets);
kvSecretEngine.deleteSecret("myapps/vault-quickstart/crud"
);
FetchingcredentialsDB
With the next kv vault kv put secret/myapps/vault-quickstart/dbpassword=connor
quarkus.vault.credentials-provider.mydatabase.kv-path=myapps/vault-quickstart/db
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=sarah
quarkus.datasource.credentials-provider=mydatabase
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydatabase
NopasswordissetasitisfetchedfromVault.
Dynamiccredentialsarealsosupported:
Runningthefollowingdynamicdatabasecon�ginVault:
vault write database/config/mydb plugin_name=postgresql-database-
plugin…..
Youcancon�gureas:
quarkus.vault.credentials-provider
.mydatabase.database-credentials-role=mydbrole
quarkus.datasource.db-kind=postgresql
quarkus.datasource.credentials-provider=mydatabase
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydatabase
UsernameandpasswordarefetchedfromVault
Transit
@InjectVaultTransitSecretEnginetransit;
transit.encrypt("my_encryption",text);
transit.decrypt("my_encryption",text).asString();
transit.sign("my-sign-key",text);
TransitKey
@InjectVaultTransitSecretEnginetransit;
transit.createKey(KEY_NAME, new KeyCreationRequestDetail().setExportable(true));transit.readKey(KEY_NAME);
transit.listKeys();
transit.exportKey(KEY_NAME, VaultTransitExportKeyType.encry
ption,null);transit.updateKeyConfiguration(KEY_NAME, new KeyConfigRequestDetail().setDeletionAllowed(true));transit.deleteKey(KEY_NAME);
VaultTOTP
TOTP secret engine is supported by usingio.quarkus.vault.VaultTOTPSecretEngine class:
@InjectVaultTOTPSecretEnginevaultTOTPSecretEngine;
CreateKeyParameterscreateKeyParameters=newCreateKeyParameters("Google","[email protected]");
createKeyParameters.setPeriod("30m");
/**GenerateKey(QRcode)*/
finalOptional<KeyDefinition>myKey=vaultTOTPSecretEngine.createKey("my_
key_2",createKeyParameters);
/**Generatekeynumbertologin*/
final String keyCode = vaultTOTPSecretEngine.generateCode("my_key_2");
/**Loginlogic*/
booleanvalid=vaultTOTPSecretEngine.validateCode("my_key_2",keyCode);
VaultProvisioning
Vault extension offers façade classes to Vault provisioningfunctions:
@InjectVaultSystemBackendEnginevaultSystemBackendEngine;
@InjectVaultKubernetesAuthServicevaultKubernetesAuthService;
Stringrules="path\"transit/*\"{\n"+
"capabilities=[\"create\",\"read\",\"updat
e\"]\n"+
"}";
StringpolicyName="sys-test-policy";
vaultSystemBackendEngine.createUpdatePolicy(policyName, rul
es);
vaultKubernetesAuthService
.createRole(roleName,newVaultKubernetesAuthRole().setBoundServiceAccountNames(boundServiceAccountN
ames)
.setBoundServiceAccountNamespaces(boundServiceAcc
ountNamespaces)
.setTokenPolicies(tokenPolicies));
Vaultcon�gurationproperties.Pre�xquarkus.vault isskipped.
url
VaultserverURL
authentication.client-token
Vaulttokentoaccess
authentication.app-role.role-id
RoleIdforAppRoleauth
authentication.app-role.secret-id
SecretIdforAppRoleauth
authentication.app-role.secret-id-wrapping-token
WrappingtokencontainingaSecretId. secret-id and secret-id-wrapping-token areexclusive.
authentication.userpass.username
Usernameforuserpassauth
authentication.userpass.password
Passwordforuserpassauth
authentication.userpass.password-wrapping-token
Wrapping token containing a password. password and password-wrapping-token areexclusive.
authentication.kubernetes.role
Kubernetesauthenticationrole
authentication.kubernetes.jwt-token-path
Locationofthe�lecontainingtheKubernetesJWTtoken
renew-grace-period
Renewgraceperiodduration(default:1H )
secret-config-cache-period
Vaultcon�gsourcecacheperiod(default:10M )
secret-config-kv-path
Vaultpathinkvstore.ListofpathsissupportedinCSV
log-confidentiality-level
Used to hide con�dential infos. low , medium , high (default:medium )
kv-secret-engine-version
Kvsecretengineversion(default:1)
kv-secret-engine-mount-path Kvsecretenginepath(default:secret )
tls.skip-verify
Allows to bypass certi�cate validation on TLS communications(default:false )
tls.ca-cert
Certi�catebundleusedtovalidateTLScommunications
tls.use-kubernetes-ca-cert
TLSwillbeactive(default:true )
connect-timeout
Tiemouttoestablishaconnection(default:5S )
read-timeout
Requesttimeout(default:1S )
credentials-provider."credentials-provider".database-credentials-
role
Databasecredentialsrole
credentials-provider."credentials-provider".kv-path
Apathinvaultkvstore,wherewewill�ndthekv-key
credentials-provider."credentials-provider".kv-key
Keynametosearchinvaultpathkv-path(default:password )
AmazonKMS
mvnquarkus:add-extension
-Dextensions="amazon-kms"
@InjectKmsClientkms;
kms.encrypt(req->req.keyId(keyArn).plaintext(
SdkBytes.fromUtf8String(data))).ciphertextBlob();
quarkus.kms.endpoint-override=http://localhost:8011quarkus.kms.aws.region=us-east-1quarkus.kms.aws.credentials.type=staticquarkus.kms.aws.credentials.static-provider.access-key-id=test-key
quarkus.kms.aws.credentials.static-provider.secret-access-key=test-secret
YouneedtosetaHTTPclienteitherURLConnection :
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
orApacheHTTP:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
quarkus.sqs.sync-client.type=apache
YoucangoasyncbyusingMutiny:
@Injectsoftware.amazon.awssdk.services.kms.KmsAsyncClientkms;
Uni.createFrom().completionStage(
kms.encrypt(req->req.keyId(keyArn).plaintext(SdkByte
s.fromUtf8String(data))
))
AndyouneedtoaddtheasynchronousNettyclient:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
Con�gurationpropertiesare thesameasAmazonDynamoDB butchangingthepre�xfromdynamodb tokms .
AmazonIAM
mvnquarkus:add-extension
-Dextensions="quarkus-amazon-iam"
YouneedtosetaHTTPclienteitherURLConnection :
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
orApacheHTTP:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
AndyouneedtoaddtheasynchronousNettyclient:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
@InjectIamClientclient;
@InjectIamAsyncClientasync;
quarkus.iam.endpoint-override=${iam.url}quarkus.iam.aws.region=us-east-1quarkus.iam.aws.credentials.type=staticquarkus.iam.aws.credentials.static-provider.access-key-id=test-key
quarkus.iam.aws.credentials.static-provider.secret-access-key=test-secret
Con�gurationpropertiesare thesameasAmazonDynamoDB butchangingthepre�xfromdynamodb toiam .
HTTPCon�guration
Youcancon�gureHTTPparameters.Usingquarkus.http pre�x:
cors
EnableCORS.(default:false )
cors.origins
CSVoforiginsallowed.(dedault:Anyrequestvalid.)
cors.methods
CSVofmethodsvalid.(default:Anymethodvalid.)
cors.headers
CSV of valid allowed headers. (default: Any requested headervalid.)
cors.exposed-headers
CSVofvalidexposedheaders.
port
TheHTTPport.(default:8080 )
test-port
TheHTTPtestport.(default:8081 )
host
TheHTTPhost.(default:0.0.0.0 )
host-enabled
Enablelisteningtohost:port.(default:true )
ssl-port
TheHTTPSport.(default8443 )
test-ssl-port
TheHTTPSportusedtoruntests.(default8444 )
proxy-address-forwarding
Theaddress,schemeetcwillbesetfromheadersforwardedbytheproxyserver.
allow-forwarded
Proxyaddressforwardingisenabledthenthestandard Forwardedheader will be used, rather than the more common but notstandardX-Forwarded-For .
insecure-requests
If insecure requests are allowed. Possible values: enabled ,redirect ,disable .(default:enabled )
http2
EnablesHTTP/2.(default:true )
ssl.port
TheHTTPSport.(default:8443 )
ssl certificate file
The�le path to a service certi�cate or certi�cate chain inPEMformat.Relativetosrc/main/resources .
ssl.certificate.key-file
The�lepathtothecorrespondingcerti�cateprivatekey inPEMformat.Relativetosrc/main/resources .
ssl.certificate.key-store-file
The key store contains the certi�cate information. Relative tosrc/main/resources .
ssl.certificate.key-store-file-type
Thekeystoretype.Itisautomaticallydetectedbasedonthe�lenameorcanbesetmanually.Supportedvaluesare: JKS , JCEKS ,P12 ,PKCS12 orPFX .
ssl.certificate.key-store-password
Thepasswordtoopenthekeystore�le.
ssl.certificate.trust-store-file The trust store location whichcontains the certi�cate information of the certi�cates to trust.Relativetosrc/main/resources .
ssl.certificate.trust-store-file-type
Thetruststoretype.Itisautomaticallydetectedbasedonthe�lenameorcanbesetmanually.
ssl.certificate.trust-store-password
Thepasswordtoopenthetruststore�le.
ssl.cipher-suites
A list of strings of cipher suites to use. If not provided, areasonabledefaultisselected.
ssl.protocols
The list of protocols to explicitly enable. (default: TLSv1.3 andTLSv1.2 ).
ssl.client-auth
Con�gures the engine to require/request client authentication.Possiblevaluesare:none ,request andrequired .(default:none ).
io-threads
ThenumberifIOthreadsusedtoperformIO.
limits.max-header-size
Themaximumlengthofallheaders.(default:20k )
limits.max-body-size
Themaximumsizeofarequestbody.(default:10M )
limits.max-chunk-size
ThemaxHTTPchunksize.
limits.max-initial-line-length
Themaximumlengthoftheinitialline.(default:4096 )
idle-timeout
Htt ti idl ti t (d f lt )
enable-compression
Ifresponsesshouldbecompressed.
read-timeout
HttpconnectionreadtimeoutforblockingIO.(default:60s )
body.handle-file-uploads
If the �les sent using multipart/form-data will be stored locally.(default:true )
body.uploads-directory
The directory where the �les sent using multipart/form-data
shouldbestored.(default:file-uploads )
body.merge-from-attributes
Iftheformattributesshouldbeaddedtotherequestparameters.(default:true )
body.delete-uploaded-files-on-end
Iftheuploaded�lesshouldberemovedafterservingtherequest.
body.preallocate-body-buffer
If the body buffer should pre-allocated based on the Content-Length headervalue.(default:1K )
auth.session.encryption-key
Theencryptionkeythatisusedtostorepersistentlogins.
so-reuse-port
Enablesocketreuseport.
tcp-quick-ack
Enabletcpquickack.
tcp-cork
Enabletcpcork.
tcp-fast-open
Enabletcpfastopen.
domain-socket
Path to a unix domain socket. (default:/var/run/io.quarkus.app.socket )
domain-socket-enabled
Enablesdomainsocket.
record-request-start-time
If enabled then start timewill be recorded to enable loggingoftotalrequesttime.(default:false )
access-log.enabled
Ifaccessloggingisenabled.(default:false )
access-log.pattern
Theaccesslogpattern.(default:common )
l l t fil
Ifloggingshouldbedonetoaseparate�le.(default:false )
access-log.base-file-name
Theaccesslog�lebasename.(default:quarkus )
access-log.log-directory
Thelogdirectorytousewhenloggingaccesstoa�le.
access-log.log-directory
Thelogdirectorytousewhenloggingaccesstoa�le.
access-log.log-suffix
Thelog�lesu�x.(default:.log )
access-log.category
Thelogcategorytouseifloggingisbeingdoneviathestandardlogmechanism.(default:io.quarkus.http.access-log )
access-log.rotate
Ifthelogshouldberotateddaily.(default:true )
same-site-cookie.<name>.case-sensitive
Ifthecookiepatterniscasesensitive.
same-site-cookie.<name>.value
Thevaluetosetinthesamesiteattribute.
same-site-cookie.<name>.enable-client-checker
Some User Agents break when sent SameSite=None, this willdetectthemandavoidsendingthevalue.(default:true )
same-site-cookie.<name>.add-secure-for-none
Ifthisistruethenthe'secure'attributewillautomaticallybesentoncookieswithaSameSiteattributeofNone.(default:true )
If metrics extension is registered, you can enable to get HTTPmetricsbysettingquarkus.resteasy.metrics.enabled totrue.
JAX-RS
Quarkus uses JAX-RS to de�ne REST-ful web APIs. Under thecovers,Rest-EASYisworkingwithVert.XdirectlywithoutusinganyServlet.
It is important to know that if you want to use any feature thatimplies a Servlet (ie Servlet Filters) then you need to add thequarkus-undertow extension to switch back to the Servlet
ecosystem but generally speaking, you don’t need to add it aseverythingelseiswell-supported.
@Path("/book")publicclassBookResource{
@GET@Produces(MediaType.APPLICATION_JSON)publicList<Book>getAllBooks(){}
@POST@Produces(MediaType.APPLICATION_JSON)publicResponsecreateBook(Bookbook){}
@DELETE@Path("{isbn}")@Produces(MediaType.APPLICATION_JSON)publicResponsedeleteBook(@PathParam("isbn")Stringisbn){}
@GET@Produces(MediaType.APPLICATION_JSON)@Path("search")publicResponsesearchBook(@QueryParam("description")Stringdescription){}
}
Togetinformationfromrequest:
@PathParam
Gets content from request URI. (example: /book/{id}
@PathParam("id") )
@QueryParam
Gets query parameter. (example: /book?desc=""
@QueryParam("desc) )
@FormParam
Getsformparameter.
@MatrixParam
Get URI matrix parameter. (example:/book;author=mkyong;country=malaysia )
@CookieParam
Getscookieparambyname.
@HeaderParam
Getsheaderparameterbyname.
Valid HTTP method annotations provided by the spec are: @GET ,@POST ,@PUT ,@DELETE ,@PATCH ,@HEAD and@OPTIONS .
You can create new annotations that bind to HTTPmethods notde�nedbythespec.
@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@HttpMethod("LOCK")public@interfaceLOCK{}
@LOCKpublicvoidlockIt(){}}
Injecting
Using@Context annotationtoinjectJAX-RSandServletinformation.
@GETpublicStringgetBase(@ContextUriInfouriInfo){returnuriInfo.getBaseUri();}
Possible injectable objects: SecurityContext , Request , Application ,Configuration , Providers , ResourceContext , ServletConfig ,ServletContext , HttpServletRequest , HttpServletResponse ,HttpHeaders ,Urinfo ,SseEventSink andSse .
HTTPFilters
HTTP requestand responsecanbe intercepted tomanipulate themetadata (ie headers, parameters, media type, …) or abort arequest. You only need to implement the nextContainerRequestFilter and ContainerResponseFilter JAX-RSinterfacesrespectively.
@ProviderpublicclassLoggingFilterimplementsContainerRequestFilter{
@ContextUriInfoinfo;
@ContextHttpServletRequestrequest;
@Overridepublicvoidfilter(ContainerRequestContextcontext){finalStringmethod=context.getMethod();finalStringpath=info.getPath();finalStringaddress=request.getRemoteAddr();System.out.println("Request%s%sfromIP%s",
method,path,address);
}
}
ExceptionMapper
You can map exceptions to produce a custom output byimplementingExceptionMapper interface:
@ProviderpublicclassErrorMapperimplementsExceptionMapper<Exception>{
@OverridepublicResponsetoResponse(Exceptionexception){intcode=500;if(exceptioninstanceofWebApplicationException){code=((WebApplicationException)exception)
.getResponse().getStatus();
}
returnResponse.status(code).entity(
Json.createObjectBuilder()
.add("error",exception.getMessage())
.add("code",code)
.build()
)
.build();
}
}
Caching
AnnotationstosetCache-Controlheaders:
@Produces(MediaType.APPLICATION_JSON)@org.jboss.resteasy.annotations.cache.NoCachepublicUserme(){}
@Produces(MediaType.APPLICATION_JSON)@org.jboss.resteasy.annotations.cache.Cache(maxAge=2000,
noStore=false)
publicUseryou(){}
Vert.XFiltersandRoutes
Programmatically
You can also register Vert.X Filters and Router programmaticallyinsideaCDIbean:
importio.quarkus.vertx.http.runtime.filters.Filters;importio.vertx.ext.web.Router;importjavax.enterprise.context.ApplicationScoped;importjavax.enterprise.event.Observes;
@ApplicationScopedpublicclassMyBean{
publicvoidfilters(@ObservesFiltersfilters){
filters
.register(
rc->{
rc.response()
.putHeader("X-Filter","filter1");
rc.next();
},
10);
}
publicvoidroutes(@ObservesRouterrouter){
router
.get("/")
.handler(rc->rc.response().end("OK"));
}
}
Declarative
You can use @Route annotation to use reactive routes and@RouteFilter tosuereactive�ltersinadeclarativeway:
./mvnwquarkus:add-extension
-Dextensions="quarkus-vertx-web"
@ApplicationScopedpublicclassMyDeclarativeRoutes{
@Route(path="/hello",methods=HttpMethod.GET)publicvoidgreetings(RoutingContextrc){Stringname=rc.request().getParam("name");
if(name==null){name="world";
}
rc.response().end("hello"+name);
}
@RouteFilter(20)voidfilter(RoutingContextrc){rc.response().putHeader("X-Filter","filter2");
rc.next();
}
@RouteStringhello(@ParamOptional<String>name){}
@RouteStringhelloFromHeader(@Header("My-Header")Stringheader){}
@RouteStringcreatePerson(@BodyPersonperson){}
}
GraphQL
Quarkus integrates with GraphQL using MicroPro�le GraphQLintegration.
./mvnwquarkus:add-extension
-Dextensions="graphql"
@GraphQLApipublicclassFilmResource{
@Query("allFilms")publicList<String>films(){}
@QuerypublicStringgetFilm(@Name("filmId")intid)){}
@QuerypublicList<Hero>getHeroesWithSurname(@DefaultValue("Skywalker")Stringsurname){
}
@MutationpublicGreetingsload(Greetingsgreetings){}
}
If name not provided, then query name is resolved frommethodname.
You can see the full schema at /graphql/schema.graphql . AlsoGraphiQLUIisenabledatdevandtestmodeat/graphql-ui/ .
Extensioncanbecon�guredwiththefollwoingparamterspre�xedwithquarkus.smallrye-graphql .
root-path
The rootPath under which queries will be served. (default:/graphql )
root-path-ui
ThepathwhereGraphQLUIisavailable.(default:/graphql-ui )
always-include-ui
ThepathwhereGraphQLUIisavailable.(default:/graphql-ui )
root-path-ui
AlwaysincludetheUI.Bydefaultthiswillonlybeincludedindevandtest.(default:false )
enable-ui
IfGraphQLUIshouldbeenabled.(default:false )
metrics.enabled
Enablemetrics.(default:false )
Vert.XVerticle
Vert.XVerticlesarealsosupported:
@ApplicationScopedpublicclassVerticleDeployer{
@InjectVertxvertx;
publicvoidinit(@ObservesStartupEventev){CountDownLatchlatch=newCountDownLatch(1);vertx.deployVerticle(BareVerticle::new,newDeploymentOptions().setConfig(
newJsonObject().put("id","bare")
)
)
.thenAccept(x->latch.countDown());
latch.countDown();
}
}
Verticlescanbe:
bareextendingio.vertx.core.AbstractVerticle .
mutiny
extendigio.smallrye.mutiny.vertx.core.AbstractVerticle .
GZipSupport
You can con�gure Quarkus to use GZip in theapplication.properties �le using the next properties withquarkus.resteasy su�x:
gzip.enabled
EnableGZip.(default:false )
gzip.max-input
Con�guretheupperlimitonde�atedrequestbody.(default:10M )
GRPC
QuarkusintegrateswithgRPC:
./mvnwquarkus:add-extension
-Dextensions="quarkus-grpc"
Then you need to con�gure buildtool with gRPC plugins. In thecase of Maven, the kr.motd.maven:os-maven-plugin extension andorg.xolstice.maven.plugins:protobuf-maven-plugin
Protos�lesarestoredatsrc/main/proto .
When java �les are created two service implementations areprovided:onewithdefaultgRPCAPIandotherwithMutinysupport.
With quarkus.grpc.server pre�x, the next con�guration propertiescanbeset:
port
ThegRPCServerport.(default:9000 )
host
ThegRPCserverhost.(default:0.0.0.0 )
handshake-timeout
ThegRPChandshaketimeout.
max-inbound-message-size
Themaxinboundmessagesizeinbytes.
plain-text
Useplaintext.(default:true )
alpn
TWhetherALPNshouldbeused.(default:true )
enable-reflection-service
EnablesthegRPCRe�ectionService.(default:false )
ssl.certificate
The �le path to a server certi�cate or certi�cate chain in PEMformat.
ssl.key
The �le path to the corresponding certi�cate private key �le inPEMformat.
ssl.key-store
An optional key store which holds the certi�cate informationinsteadofspecifyingseparate�les.
ssl.key-store-type
Anoptionalparametertospecifythetypeofthekeystore�le.
ssl.key-store-password
A parameter to specify the password of the key store �le.(default:password )
ssl.trust-store
Trust store which holds the certi�cate information of thecerti�catestotrust
ssl.trust-store-type
Parametertospecifytypeofthetruststore�le.
ssl.trust-store-password
Aparametertospecifythepasswordofthetruststore�le.
ssl.cipher-suites
Alistoftheciphersuitestouse.
ssl.protocols
The list of protocols to explicitly enable. (default:TLSv1.3,TLSv1.2 )
transport-security.certificate
Thepathtothecerti�cate�le.
transport-security.key
Thepathtotheprivatekey�le.
Toconsumetheservice:
@GrpcService("hello")GreeterGrpc.GreeterBlockingStubclient;
@GrpcService("hello")io.grpc.Channelchannel;
Some con�guration example to set the host and the SSLparameters:
quarkus.grpc.clients.hello.host=localhostquarkus.grpc.clients.hello.plain-text=falsequarkus.grpc.clients.hello.ssl.certificate=src/main/resources/tls/client.pem
quarkus.grpc.clients.hello.ssl.key=src/main/resources/tls/client.key
quarkus.grpc.clients.hello.ssl.trust-store=src/main/resources/tls/ca.pem
FaultTolerance
QuarkususesMicroPro�leFaultTolerancespec:
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-fault-toleranc
e"
MicroPro�le Fault Tolerance spec usesCDI interceptor and it canbeusedinseveralelementssuchasCDIbean,JAX-RSresourceorMicroPro�leRestClient.
Todoautomaticretriesonamethod:
@Path("/api")@RegisterRestClientpublicinterfaceWorldClockService{@GET@Path("/json/cet/now")@Produces(MediaType.APPLICATION_JSON)@Retry(maxRetries=2)WorldClockgetNow();}
You can set fallback code in case of an error by using @Fallbackannotation:
@Retry(maxRetries=1)@Fallback(fallbackMethod="fallbackMethod")WorldClockgetNow(){}
publicWorldClockfallbackMethod(){returnnewWorldClock();}
fallbackMethod musthavethesameparametersandreturntypeastheannotatedmethod.
Youcanalsosetlogicintoaclassthatimplements FallbackHandlerinterface:
publicclassRecoverFallbackimplementsFallbackHandler<WorldClock>{@OverridepublicWorldClockhandle(ExecutionContextcontext){}
}
And set it in the annotation as value@Fallback(RecoverFallback.class) .
Incaseyouwanttousecircuitbreakerpattern:
@CircuitBreaker(requestVolumeThreshold=4,failureRatio=0.75,
delay=1000)
WorldClockgetNow(){}
If 3 (4 x 0.75) failures occur among the rolling window of 4consecutiveinvocationsthenthecircuitisopenedfor1000msandthen be back to half open. If the invocation succeeds then thecircuitisbacktoclosedagain.
Youcanusebulkahead pattern to limit the number of concurrentaccess to the same resource. If the operation is synchronous ituses a semaphore approach, if it is asynchronous a thread-poolone. When a request cannot be processed BulkheadException isthrown. It can be used together with any other fault toleranceannotation.
@Bulkhead(5)@Retry(maxRetries=4,delay=1000,
retryOn=BulkheadException.class)
WorldClockgetNow(){}
Faulttoleranceannotations:
Annotation Properties
@Timeout unit
@Retry
maxRetries , delay , delayUnit ,maxDuration , durationUnit ,jitter , jitterDelayUnit , retryOn ,abortOn
@Fallback fallbackMethod
@BulkheadwaitingTaskQueue (only valid inasynchronous)
@CircuitBreaker
failOn , delay , delayUnit ,requestVolumeThreshold ,failureRatio ,successThreshold
@Asynchronous
Youcanoverrideannotationparametersviacon�guration�leusingproperty[classname/methodname/]annotation/parameter :
org.acme.quickstart.WorldClock/getNow/Retry/maxDuration=30#Classscope
org.acme.quickstart.WorldClock/Retry/maxDuration=3000#Global
Retry/maxDuration=3000
You can also enable/disable policies using special parameterenabled .
org.acme.quickstart.WorldClock/getNow/Retry/enabled=false#Disableeverythingexceptfallback
MP_Fault_Tolerance_NonFallback_Enabled=false
MicroPro�le Fault Tolerance integrates with MicroPro�leMetrics spec. You can disable it by settingMP_Fault_Tolerance_Metrics_Enabled tofalse.
Observability
HealthChecks
Quarkus relies on MicroPro�le Health spec to provide healthchecks.
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-health"
Byjustaddingthisextension,anendpointisregisteredto/q/healthprovidingadefaulthealthcheck.
{
"status":"UP",
"checks":[
]
}
To create a custom health check you need to implement theHealthCheck interfaceandannotateeitherwith @Readiness (readytoprocessrequests)or@Liveness (isrunning)annotations.
@ReadinesspublicclassDatabaseHealthCheckimplementsHealthCheck{@OverridepublicHealthCheckResponsecall(){HealthCheckResponseBuilderresponseBuilder=
HealthCheckResponse.named("Databaseconn");
try{checkDatabaseConnection();
responseBuilder.withData("connection",true);responseBuilder.up();
}catch(IOExceptione){//cannotaccessthedatabase
responseBuilder.down()
.withData("error",e.getMessage());
}
returnresponseBuilder.build();}
}
Buildsthenextoutput:
{
"status":"UP",
"checks":[
{
"name":"Databaseconn",
"status":"UP",
"data":{
"connection":true
}
}
]
}
SincehealthchecksareCDIbeans,youcando:
@ApplicationScopedpublicclassDatabaseHealthCheck{
@LivenessHealthCheckcheck1(){returnio.smallrye.health.HealthStatus.up("successful-live");
}
@ReadinessHealthCheckcheck2(){returnHealthStatus.state("successful-read",this::isReady)}
privatebooleanisReady(){}}
You can ping liveness or readiness health checks individually byquerying/q/health/live or/q/health/ready .
Quarkus comes with some HealthCheck implementations forcheckingservicestatus.
SocketHealthCheck: checks if host is reachable using asocket.
UrlHealthCheck:checksifhost isreachableusingaHttpURLconnection.
InetAddressHealthCheck: checks if host is reachable usingInetAddress.isReachable method.
@LivenessHealthCheckcheck1(){returnnewUrlHealthCheck("https://www.google.com").name("Google-Check");
}
Ifyouwant tooverrideorsetmanually readiness/livenessprobes,youcandoitbysettinghealthproperties:
quarkus.smallrye-health.root-path=/helloquarkus.smallrye-health.liveness-path=/customlivequarkus.smallrye-health.readiness-path=/customready
Automaticreadinessprobes
Somedefaultreadinessprobesareprovidedbydefaultifanyofthenextfeaturesareadded:
datasourceAprobetocheckdatabaseconnectionstatus.
kafkaAprobetocheckkafkaconnectionstatus.Inthiscaseyouneedto enable manually by setting quarkus.kafka.health.enabled totrue .
mongoDBAprobetocheckMongoDBconnectionstatus.
neo4jAprobetocheckNeo4Jconnectionstatus.
artemisAprobetocheckArtemisJMSconnectionstatus.
kafka-streamsLiveness (for stream state) and Readiness (topics created)probes.
vaultAprobetocheckVaultconectionstatus.
gRPCAreadinessprobeforthegRPCservices.
CassandraAreadinessprobetocheckCassandraconnectionstatus.
RedisAreadinessprobetocheckRedisconnectionstatus.
You can disable the automatic generation by setting<component>.health.enabled tofalse.
quarkus.kafka-streams.health.enabled=falsequarkus.mongodb.health.enabled=falsequarkus.neo4j.health.enabled=false
InthecaseofVaultyoucanpassparameterstomodifythecallofthestatus endpointinVault.
quarkus.vault.health.enabled=truequarkus.vault.health.stand-by-ok=truequarkus.vault.health.performance-stand-by-ok=true
Health groups are supported to provide custom health checksgroups:
@io.smallrye.health.HealthGroup("mygroup1")public class SimpleHealthGroupCheck implements HealthCheck{
}
Youcanpinggroupedhealthchecksbyquerying/group/mygroup1 .
Grouprootpathcanbecon�gured:
quarkus.smallrye-health.group-path=/customgroup
Metrics
QuarkuscanutilizetheMicroPro�leMetricsspectoprovidemetricssupport.
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-metrics"
ThemetricscanbereadwithJSONortheOpenMetricsformat.Anendpointisregisteredautomaticallyat /q/metrics providingdefaultmetrics.
MicroPro�leMetricsannotations:
@Timed
Trackstheduration.
@SimplyTimed
Tracksthedurationwithoutmeananddistributioncalculations.
@Metered
Tracksthefrequencyofinvocations.
@Counted
Countsnumberofinvocations.
@Gauge
Samplesthevalueoftheannotatedobject.
@ConcurrentGauge
Gaugetocountparallelinvocations.
@Metric
Used to inject a metric. Valid types Meter , Timer , Counter ,Histogram .Gauge onlyonproducermethods/�elds.
@GET//...
@Timed(name="checksTimer",description="Ameasureofhowlongittakes
toperformahello.",
unit=MetricUnits.MILLISECONDS)
publicStringhello(){}
@Counted(name="countWelcome",description="Howmanywelcomehavebeenperformed.")
publicStringhello(){}
@Gauge annotationreturningameasureasagauge.
@Gauge(name="hottestSauce",unit=MetricUnits.NONE,description="HottestSaucesofar.")
publicLonghottestSauce(){}
Injectingahistogramusing@Metric .
@Inject@Metric(name="histogram")Histogramhistorgram;
Youcancon�gureMetrics:
quarkus.smallrye-metrics.path=/mymetrics
Pre�xisquarkus.smallrye-metrics .
path
Thepathtothemetricshandler.(default:/q/metrics )
extensions.enabled
Metricsareenabledornot.(default:true )
micrometer.compatibility
ApplyMicrometercompatibilitymode.(default:false )
quarkus.hibernate-orm.metrics.enabled set to true exposesHibernatemetricsundervendor scope.
quarkus.mongodb.metrics.enabled set to true exposes MongoDBmetricsundervendor scope.
YoucanapplymetricsannotationsviaCDIstereotypes:
@Stereotype@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.TYPE, ElementType.METHOD, ElementTyp
e.FIELD})
@Timed(name="checksTimer",description="Ameasureofhowlongittakes
toperformahello.",
unit=MetricUnits.MILLISECONDS)
public@interfaceTimedMilliseconds{}
There is a tight integration with Micrometer in the form of anextension:
./mvnwquarkus:add-extension
-Dextensions="micrometer"
Addamicrometerdependencyfortheregistryofyourchoosing:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Youcancon�gureMicrometer.Pre�xisquarkus.micrometer :
enabled
Micrometermetricssupport.(default:true )
registry-enabled-default
MicrometerMeterRegistrydiscovery.(default:true )
binder-enabled-default
MicrometerMeterBinderdiscovery.(default:true )
binder.vertx.enabled
Vert.xmetricssupport.
binder.mp-metrics.enabled
Micropro�leMetricssupport.
binder.jvm
MicrometerJVMmetricssupport.(default:true )
binder.system
MicrometerSystemmetricssupport.(default:true )
export.datadog.enabled
SupportforexporttoDatadogSupportforDatadog.
export.jmx.enabled
SupportforexporttoJMXSupportforJMX.
export.prometheus.enabled
SupportforexporttoPrometheus.
export.prometheus.path
The path for the prometheus metrics endpoint (producestext/plain).(default:/q/metrics )
export.azuremonitor.enabled
SupportforexporttoAzureMonitor.
export.azuremonitor.instrumentation-key
ThepathfortheazuremonitorinstrumentationKey.
export.statsd.enabled
SupportforexporttoStatsD.
export.stackdriver.enabled
Micrometermetricssupport.(default:true )
export.signalfx.enabled
Micrometermetricssupport.(default:true )
export.signalfx.uri
SignalfxURI.
export.signalfx.access-token
AccessToken.
binder.vertx.match-patterns
Comma-separated case-sensitive list of regular expressionsde�ningPathsthatshouldbematchedandusedastags
binder.vertx.ignore-patterns
Comma-separated case-sensitive list of regular expressionsde�ningPathsthatshouldbeignored/notmeasured.
export.datadog
Datadog MeterRegistry con�guration in Map<String, String>
format.
export.jmx
JMX registry con�guration properties in Map<String, String>
format.
export.prometheus
Prometheus registry con�guration properties in Map<String,
String> format.
export.stackdriver
Stackdriver registry con�guration properties in Map<String,
String> format.
Tracing
QuarkuscanutilizetheMicroPro�leOpenTracingspec.
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-opentracing"
Requestssenttoanyendpointaretracedautomatically.
ThisextensionincludesOpenTracingsupportandJaeger tracer.
Jaegertracercon�guration:
quarkus.jaeger.service-name=myservicequarkus.jaeger.sampler-type=constquarkus.jaeger.sampler-param=1quarkus.jaeger.endpoint=http://localhost:14268/api/tracesquarkus.jaeger.metrics.enabled=true
@Traced annotationcanbesettodisabletracingatclassormethodlevel.
Tracer classcanbeinjectedintotheclass.
@InjectTracertracer;
tracer.activeSpan().setBaggageItem("key","value");
Youcandisable Jaeger extensionbyusing quarkus.jaeger.enabledproperty.
YoucanlogthetraceId ,spanId andsampled innormallog:
quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId},
spanId=%X{spanId},sampled=%X{sampled}[%c{2.}](%t)%s%e%n
Additionaltracers
JDBCTracer
AddsaspanforeachJDBCqueries.
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-jdbc</artifactId>
</dependency>
Con�gureJDBCdriverapartfromtracingpropertiesseenbefore:
#add':tracing'toyourdatabaseURL
quarkus.datasource.url=jdbc:tracing:postgresql://localhost:5432/mydatabase
quarkus.datasource.driver=io.opentracing.contrib.jdbc.TracingDriver
quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQLDialect
OpenTelemetry
Quarkus integrateswith theOpenTelemetry project. For exportingtraces to a Jaeger collector, use the quarkus-opentelemetry-
exporter-jaeger extension
KafkaTracer
Adds a span for eachmessage sent to or received from a Kafkatopic.
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-kafka-client<</artifactId>
</dependency>
Andcon�gureit:
...
mp.messaging.outgoing.generated-price.topic=prices
#ForProduces
mp.messaging.outgoing.generated-price.interceptor.classes=io.opentracing.contrib.kafka.TracingProducerInterceptor
...
#Forconsumers
mp.messaging.incoming.prices.interceptor.classes=io.opentracing.contrib.kafka.TracingConsumerInterceptor
AWSXRay
If you are building native images, and want to use AWS X-RayTracingwithyour lambdayouwill need to include quarkus-amazon-lambda-xray asadependencyinyourpom.
NativeExecutable
Youcanbuildanative imagebyusingGraalVM.Thecommonusecase is creating a Docker image so you can execute the nextcommands:
./mvnwpackage-Pnative-Dquarkus.native.container-build=tr
ue
dockerbuild-fsrc/main/docker/Dockerfile.native
-tquarkus/getting-started.
dockerrun-i--rm-p8080:8080quarkus/getting-started
You can use quarkus.native.container-runtime to select thecontainerruntimetouse.Now docker (default)and podman are thevalidoptions.
./mvnwpackage-Pnative-Dquarkus.native.container-runtime=
podman
Tocon�gurenativeapplication,youcancreateaconfig directoryatthe same place as the native �le and place anapplication.properties �leinside.config/application.properties .
SSL
Tocreateanative imagewithSSLyouneedtocopySunEClibraryandcerti�cates:
Java8:
FROM quay.io/quarkus/ubi-quarkus-native-image:{graalvm-vers
ion}-java8asnativebuilder
RUNmkdir-p/tmp/ssl-libs/lib\
&&cp/opt/graalvm/jre/lib/security/cacerts/tmp/ssl-libs
\
&&cp/opt/graalvm/jre/lib/amd64/libsunec.so/tmp/ssl-lib
s/lib/
FROMregistry.access.redhat.com/ubi8/ubi-minimal
WORKDIR/work/
COPY--from=nativebuilder/tmp/ssl-libs//work/
COPYtarget/*-runner/work/application
RUNchmod775/work/work/application
EXPOSE8080
CMD["./application","-Dquarkus.http.host=0.0.0.0","-Djav
a.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/wor
k/cacerts"]
Java11:
FROM quay.io/quarkus/ubi-quarkus-native-image:{graalvm-vers
ion}-java11asnativebuilder
RUNmkdir-p/tmp/ssl-libs/lib\
&&cp/opt/graalvm/lib/security/cacerts/tmp/ssl-libs\
&&cp/opt/graalvm/lib/libsunec.so/tmp/ssl-libs/lib/
FROMregistry.access.redhat.com/ubi8/ubi-minimal
WORKDIR/work/
COPY--from=nativebuilder/tmp/ssl-libs//work/
COPYtarget/*-runner/work/application
RUNchmod775/work/work/application
EXPOSE8080
CMD["./application","-Dquarkus.http.host=0.0.0.0","-Djav
a.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/wor
k/cacerts"]
Inclusionofresources
By default, no resources are included in native executable.quarkus.native.resources.includes allowstosetglobexpressionstoincluderesourcesbasedonsrc/main/resources path.
Givensrc/main/resources/foo/selected.png :
quarkus.native.resources.includes=foo/**
Exclusionofresources
Bydefault,noresourcesareexcluded.
quarkus.native.resources.excludes=foo/**
Nativecon�gurationpropertiespre�xedwithquarkus.native :
additional-build-args
Additionalargumentstopasstothebuildprocess.
enable-http-url-handler
IftheHTTPurlhandlershouldbeenabled.(default:true )
enable-https-url-handler
IftheHTTPSurlhandlershouldbeenabled.
enable-all-security-services
Ifallsecurityservicesshouldbeaddedtothenativeimage.
user-language
De�nes the user language used for building the nativeexecutable.
user-country
De�nestheusercountryusedforbuildingthenativeexecutable.
file-encoding
De�nesthe�leencoding.
Ifallcharactersetsshouldbeaddedtothenativeimage.
graalvm-home
ThelocationoftheGraaldistribution.
java-home
ThelocationoftheJDK.
native-image-xmx
The maximum Java heap to be used during the native imagegeneration.
debug-build-process
If the native image build should wait for a debugger to beattachedbeforerunning.
publish-debug-build-process-port
Ifthedebugportshouldbepublishedwhenbuildingwithdockeranddebug-build-process.(default:true )
cleanup-server
Ifthenativeimageservershouldberestarted.
enable-isolates
Ifisolatesshouldbeenabled.(default:true )
enable-fallback-images
IfaJVMbased'fallbackimage'shouldbecreatedifnativeimagefails.
enable-server
Ifthenativeimageservershouldbeused.
auto-service-loader-registration
If all META-INF/services entries should be automaticallyregistered.
dump-proxies
Ifthebytecodeofallproxiesshouldbedumpedforinspection.
container-build
Ifthisbuildshouldbedoneusingacontainerruntime.
remote-container-build
Ifthisbuildisdoneusingaremotedockerdaemon.
builder-image
Thedockerimagetousetodotheimagebuild.
container-runtime
Thecontainer runtime that isused todoan imagebasedbuild.(docker ,podman )
container-runtime-options
Optionstopasstothecontainerruntime.
enable-vm-inspection
If the resulting image should allow VM introspection
full-stack-traces
Iffullstacktracesareenabledintheresultingimage.
enable-reports
If the reports on call paths and includedpackages/classes/methodsshouldbegenerated.
report-exception-stack-traces
Ifexceptionsshouldbereportedwithafullstacktrace.
report-errors-at-runtime
Iferrorsshouldbereportedatruntime.
enable-dashboard-dump
Generatethereport�lesforGraalVMDashboard.
resources.includes
A comma separated list of globs tomatch resource paths thatshouldbeaddedtothenativeimage.
resources.excludes
A comma separated list of globs tomatch resource paths thatshouldexcludetothenativeimage.
debug.enabled
Ifdebugisenabledanddebugsymbolsaregenerated.
ContainerImagesCreation
Youcan levarage toQuarkus togenerationand releaseofDockercontainers.Itprovidesseveralextensionstomakeitso.
mvncleanpackage
-Dquarkus.container-image.build=true
-Dquarkus.container-image.push=true
-Dquarkus.container-image.registry=quay.io
Pre�xisquarkus.container-image :
group
Thegroup/repositoryoftheimage.(default:the${user.name} )
name
Thenameoftheimage.(default:theapplicationname)
tag
Thetagoftheimage.(default:theapplicationversion)
additional-tags
Additionaltagsofthecontainerimage.
registry
Theregistrytouseforpushing.(default:docker.io )
username
Theregistryusername.
password
Theregistrypassword.
insecure
Flagtoallowinsecureregistries.(default:false )
build
Booleantosetifimageshouldbebuilt.(default:false )
push
Booleantosetifimageshouldbepushed.(default:false )
Jib
./mvnwquarkus:add-extensions
-Dextensions="quarkus-container-image-jib"
Quarkuscopiesany�leunder src/main/jib intothebuiltcontainerimage.
Pre�xisquarkus.container-image-jib :
base-jvm-image
The base image to use for the jib build. (default: fabric8/java-alpine-openjdk8-jre )
base-native-image
The base image to use for the native build. (default:registry.access.redhat.com/ubi8/ubi-minimal )
jvm-arguments
The arguments to pass to java. (default: -
Dquarkus.http.host=0.0.0.0,-
Djava.util.logging.manager=org.jboss.logmanager.LogManager )
native-arguments
The arguments to pass to the native application. (default: -Dquarkus.http.host=0.0.0.0 )
environment-variables
Mapofenvironmentvariables.
jvm-entrypoint
AcustomentrypointofthecontainerimageinJVMmode.
native-entrypoint
Acustomentrypointofthecontainerimageinnativemode.
labels
Customlabelstoaddtothegeneratedimage.
base-registry-username
The username to use to authenticate with the registry used topullthebaseJVMimage.
base-registry-password
Thepasswordtousetoauthenticatewiththeregistryusedtopull
ports
Theportstoexpose.
user
Theusertouseingeneratedimage.
always-cache-base-image
Controls theoptimizationwhich skipsdownloadingbase imagelayersthatexistinatargetregistry(default:false ).
appcds-builder-image
WhenAppCDSgenerationisenabled, ifthisproperty isset,thenthe JVM used to generate the AppCDS �le will be the JVMpresentinthecontainerimage.
platforms
Listoftargetplatforms.(ielinux/amd64 ).
Docker
./mvnwquarkus:add-extensions
-Dextensions="quarkus-container-image-docker"
Pre�xisquarkus.container-image-s2i :
dockerfile-jvm-path
Path to the JVM Docker�le. (default:${project.root}/src/main/docker/Dockerfile.jvm )
dockerfile-native-path
Path to the native Docker�le. (default:${project.root}/src/main/docker/Dockerfile.native )
S2I
./mvnwquarkus:add-extensions
-Dextensions="quarkus-container-image-s2i"
Pre�xisquarkus.container-image-docker :
base-jvm-image
Thebase image to use for the s2i build. (default: fabric8/java-alpine-openjdk8-jre )
base-native-image
The base image to use for the native build. (default:registry.access.redhat.com/ubi8/ubi-minimal )
Kubernetes
QuarkuscanuseDekoratetogenerateKubernetesresources.
./mvnwquarkus:add-extensions
-Dextensions="quarkus-kubernetes"
Running ./mvnwpackage the Kubernetes resources are created attarget/kubernetes/ directory.
Container Images Creation integrates with Kubernetesextension,sononeedofextraKubernetesproperties.
Generated resource is integrated with MicroPro�le Healthannotations.
Also,youcancustomizethegeneratedresourcebysettingthenewvaluesinapplication.properties :
quarkus.kubernetes.namespace=mynamespace
quarkus.kubernetes.replicas=3
quarkus.kubernetes.labels.foo=bar
quarkus.kubernetes.readiness-probe.period-seconds=45
quarkus.kubernetes.mounts.github-token.path=/deployment/github
quarkus.kubernetes.mounts.github-token.read-only=true
quarkus.kubernetes.secret-volumes.github-token.volume-name=github-token
quarkus.kubernetes.secret-volumes.github-token.secret-name=greeting-security
quarkus.kubernetes.secret-volumes.github-token.default-mode=420
quarkus.kubernetes.config-map-volumes.github-token.config-map-name=my-secret
quarkus.kubernetes.expose=truequarkus.kubernetes.ingress.expose=truequarkus.kubernetes.ingress.host=example.com
quarkus.kubernetes.env.vars.my-env-var=foobarquarkus.kubernetes.env.configmaps=my-config-map,another-config-map
quarkus.kubernetes.env.secrets=my-secret,my-other-secret
quarkus.kubernetes.resources.requests.memory=64Miquarkus.kubernetes.resources.requests.cpu=250mquarkus.kubernetes.resources.limits.memory=512Miquarkus.kubernetes.resources.limits.cpu=1000m
All possible values are explained athttps://quarkus.io/guides/kubernetes#con�guration-options.
LabelsandAnnotations
The generatedmanifest use the Kubernetes recommended labelsandannotations.
"labels":{
"app.kubernetes.io/part-of":"todo-app",
"app.kubernetes.io/name":"todo-rest",
"app.kubernetes.io/version":"1.0-rc.1"
}
"annotations":{
"app.quarkus.io/vcs-url":"<someurl>",
"app.quarkus.io/commit-id":"<somegitSHA>",
}
Youcanoverridethelabelsbyusingthenextproperties:
quarkus.kubernetes.part-of=todo-appquarkus.kubernetes.name=todo-restquarkus.kubernetes.version=1.0-rc.1
Oraddnewlabelsand/orannotations:
quarkus.kubernetes.labels.foo=barquarkus.kubernetes.annotations.foo=bar
metrics
When using metrics extension, Prometheus annotations aregenerated:
prometheus.io/scrape:"true"
prometheus.io/path:/metrics
prometheus.io/port:"8080"
KubernetesDeploymentTargets
You can generate different resources setting the propertyquarkus.kubernetes.deployment-target .
Possiblevaluesare kubernetes , openshift and knative .Thedefaultvalueiskubernetes .
KnativeProperties
Most of the Kubernetes properties are valid in Knative output byjust changing the kubernetes pre�x to knative pre�x (iequarkus.kubernetes.readiness-probe.period-seconds toquarkus.knative.readiness-probe.period-seconds ).
Therearealsospeci�cpropertiesforKnative:
quarkus.kubernetes.deployment-target=knativequarkus.knative.revision-name=my-revisionquarkus.knative.traffic.my-revision.percentage=80
Listofcon�gurationoptions:
kuberneteshttps://quarkus io/guides/kubernetes#con�guration options
openshifthttps://quarkus.io/guides/kubernetes#openshift
Knativehttps://quarkus.io/guides/kubernetes#knative
UsingExistingResources
YouanprovideyourKubernetesresourcesinformofyaml/jsonandtheywill provide additional resources or be used as base for thegenerationprocess:
Resources are added in src/main/kubernetes directory with thetarget name (kubernetes.json , openshift.json , knative.json , or theyml equivalents) with one orm ore Kubernetes resources. Anyresourcefoundwillbeaddedinthegeneratedmanifests.Ifoneoftheprovidedresourceshasthesamenameasoneofthegeneratedones, then the generated resource will be created on top of theprovidedresource,respectingexistingcontent.
To override the name of the generated resource you can use:quarkus.kubernetes.name , quarkus.openshift.name andquarkus.knative.name .
Deployment
Todeployautomatically thegenerated resources, youneed to setquarkus.container.deploy �agtotrue .
mvncleanpackage-Dquarkus.kubernetes.deploy=true
If you set this �ag to true , the build and push �ags fromcontainer-imagearesettotrue too.
To deploy the application, the extension uses thehttps://github.com/fabric8io/kubernetes-client. All optionsdescribedatKubernetesClientarevalidhere.
KubernetesServiceBinding
Quarkus supports binding services to applications via theServiceBindingSpeci�cationforKubernetes.
ThefollowingQuarkusextensionssupportthisfeature:
quarkus-jdbc-mariadb
quarkus-jdbc-mssql
quarkus-jdbc-mysql
quarkus-jdbc-postgresql
quarkus-kafka-client
quarkus-smallrye-reactive-messaging-kafka
./mvnwquarkus:add-extensions
-Dextensions="quarkus-kubernetes-service-binding"
Datasource con�gurationpart is absent as it is aut-discoveredbyQuarkus.
Minikube
Quarkus has a Minikube extension which creates KubernetesmanifeststhataretailoredforMinikube.
./mvnwquarkus:add-extension
-Dextensions="minikube"
Remember to execute eval$(minikube-pminikubedocker-env) tobuildimagesdirectlyinsideMinkubecluster.
OpenShift
Instead of adding Kubernetes extension, set container image s2iand the target to openshift for working with OpenShift, anextensiongroupingalloftheiscreated:
./mvnwquarkus:add-extension
-Dextensions="openshift"
KubernetesCon�gurationExtension
Integration between MicroPro�le Con�g spec and Con�gMaps &Secrets:
./mvnwquarkus:add-extensions
-Dextensions="quarkus-kubernetes-config"
quarkus.kubernetes-config.enabled=truequarkus.kubernetes-config.config-maps=cmap1,cmap2
@ConfigProperty(name="some.prop1")StringsomeProp1;
@ConfigProperty(name="some.prop2")StringsomeProp2;
If the con�g key is a Quarkus con�guration �leapplication.properties/application.yaml ,thecontentisparsedandeachkeyofthecon�guration�leisusedascon�gproperty.
ListofKubernetesCon�gparameters.
quarkus.kubernetes-config aspre�xisskippedinthenexttable.
enabled
Theapplicationwillattempttolookupthecon�gurationfromtheAPIserver.(default:false )
fail-on-missing-config
The application will not start if any of the con�gured con�gsourcescannotbelocated.(default:true )
config-maps
Con�gMaps to look for in the namespace that the KubernetesClienthasbeencon�guredfor.SupportsCSV.
namespace
AccesstoCon�gMapsfromaspeci�cnamespace.
secrets.enabled
Whetherornotcon�gurationcanbereadfromsecrets.(default:false )
KubernetesClient
QuarkusintegrateswithFabric8KubernetesClient.
./mvnwquarkus:add-extension
-Dextensions="quarkus-kubernetes-client"
ListofKubernetesclientparameters.
quarkus.kubernetes-client aspre�xisskippedinthenexttable.
trust-certs
Trustself-signedcerti�cates.(default:false )
master-url
URLofKubernetesAPIserver.
namesapce
Defaultnamespace.
ca-cert-file
CAcerti�catedata.
client-cert-file
Clientcerti�cate�le.
client-cert-data
Clientcerti�catedata.
client-key-data
Clientkeydata.
client-key-algorithm
Clientkeyalgorithm.
client-key-passphrase
Clientkeypassphrase.
username
Username.
password
Password
watch-reconnect-interval
Watchreconnectinterval.(default:PT1S )
watch-reconnect-limit
Maximumreconnectattempts.(default:-1 )
connection-timeout
Maximum amount of time to wait for a connection. (default:PT10S )
request-timeout
Maximumamountoftimetowaitforarequest.(default:PT10S )
rolling-timeout
Maximumamountoftimetowaitforarollout.(default:PT15M )
http-proxy
HTTPproxyusedtoaccesstheKubernetes.
https-proxy
HTTPSproxyusedtoaccesstheKubernetes.
proxy-username
Proxyusername.
proxy-password
Proxypassword.
no-proxy
IPaddressesorhoststoexcludefromproxying
Orprogrammatically:
@DependentpublicclassKubernetesClientProducer{
@ProducespublicKubernetesClientkubernetesClient(){Configconfig=newConfigBuilder().withMasterUrl("https://mymaster.com")
.build();
returnnewDefaultKubernetesClient(config);}
}
Andinjectitoncode:
@InjectKubernetesClientclient;
ServiceListmyServices=client.services().list();
Servicemyservice=client.services()
.inNamespace("default")
.withName("myservice")
.get();
CustomResourceDefinitionListcrds=client
.customResourceDefinitions()
.list();
dummyCRD=newCustomResourceDefinitionBuilder()...
.build()
client.customResourceDefinitions()
.create(dummyCRD);
Testing
Quarkus provides a Kubernetes Mock test resource that starts amock of Kubernetes API server and sets the proper environmentvariablesneededbyKubernetesClient.
Register next dependency: io.quarkus:quarkus-test-kubernetes-
client:test .
@QuarkusTestResource(KubernetesMockServerTestResource.class)
@QuarkusTestpublicclassKubernetesClientTest{
@MockServerprivateKubernetesMockServermockServer;
@Testpublicvoidtest(){finalPodpod1=...mockServer
.expect()
.get()
.withPath("/api/v1/namespaces/test/pods")
.andReturn(200,
newPodListBuilder().withNewMetadata()
.withResourceVersion("1")
.endMetadata()
.withItems(pod1,pod2)
.build())
.always();
}
}
AWSLambda
QuarkusintegrateswithAmazonLambda.
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-amazon-lambda"
And then implementcom.amazonaws.services.lambda.runtime.RequestHandler interface.
publicclassTestLambdaimplementsRequestHandler<MyInput,MyOutput>{@OverridepublicMyInputhandleRequest(MyOutputinput,Contextcontext){
}
}
The interfacecom.amazonaws.services.lambda.runtime.RequestStreamHandler is alsosupported.
Theinterfacecom.amazon.ask.SkillStreamHandler isalsosupported.
You can set the handler name by using quarkus.lambda.handlerproperty or by annotating the Lambda with the CDI @Named
annotation.
Test
YoucanwritetestsforAmazonlambdas:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-amazon-lambda</artifactId>
<scope>test</scope>
</dependency>
@TestpublicvoidtestLambda(){MyInputin=newMyInput();in.setGreeting("Hello");
in.setName("Stu");
MyOutputout=LambdaClient.invoke(MyOutput.class,in);
}
ToscaffoldaAWSLambdarun:
mvnarchetype:generate\
-DarchetypeGroupId=io.quarkus\
-DarchetypeArtifactId=quarkus-amazon-lambda-archetype\
-DarchetypeVersion={version}
AzureFunctions
Quarkus can make a microservice be deployable to the AzureFunctions.
ToscaffoldadeployablemicroservicetotheAzureFunctionsrun:
mvnarchetype:generate\
-DarchetypeGroupId=io.quarkus\
-DarchetypeArtifactId=quarkus-azure-functions-http-archet
ype\
-DarchetypeVersion={version}
Funqy
QuarkusFunqyispartofQuarkus’sserverlessstrategyandaimstoprovideaportableJavaAPItowritefunctionsdeployabletovariousFaaSenvironmentslikeAWSLambda,AzureFunctions,Knative,andKnativeevents.
publicclassGreetingFunction{
@InjectGreetingServiceservice;
@io.quarkus.funqy.FunqpublicStringgreet(Stringname){}
@io.quarkus.funqy.Funq("HelloCustomer")publicStringgreet(Customername){}
@FunqpublicGreetinggreet(Friendfriend,@io.quarkus.funqy.ContextAwsContextctx){}
}
In case of Amazon Lambda, only one Funqy function can beexported per Amazon Lambda deployment. If there is only onemethodannotatedwith @Funq thennoprob, ifnot,youneedtosetthefunctionnamewithquarkus.funqy.export property.
FunqyHTTP
You can invoke on Funqy functions in a pure HTTP environmentwithsimpleaddingtheFunqyHTTPextension.
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-http</artifactId>
</dependency>
FunqyCloudEvents
Addtheextension:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-knative-events</artifactId>
</dependency>
@FunqpublicStringdefaultChain(Stringinput){}
TheCloudEvent type that triggers the function is defaultChain . ItgeneratesaresponsethattriggersanewCloudEventwhosetypeisdefaultChain.output andtheeventsourceisdefaultChain .
Itcanbechangedbyusingthenextproperties:
quarkus.funqy.knative-events.mapping.defaultChain.trigger=configChain.output
quarkus.funqy.knative-events.mapping.defaultChain.response-type=annotatedquarkus.funqy.knative-events.mapping.defaultChain.response-source=configChain
The properties are of form: quarkus.funqy.knative-events.mapping.{functionname}. .
Also can be overriden [email protected] annotation.
@Funq@CloudEventMapping(trigger = "annotated", responseSource ="annotated",responseType="lastChainLink")
publicStringannotatedChain(Stringinput){}
responseType chains annotatedChain response to lastChainLink
function.
@FunqpublicvoidlastChainLink(Stringinput,@Contextio.quarkus.funqy.knative.events.CloudE
ventevent){}
AK-NativeTriggerlookslike:
apiVersion:eventing.knative.dev/v1alpha1
kind:Trigger
metadata:
name:defaultchain
spec:
filter:
attributes:
type:defaultChain
subscriber:
ref:
apiVersion:serving.knative.dev/v1
kind:Service
name:funqy-knative-events-quickstart
Andtocurl frominsidetheKubernetescluster:
curl -v "http://default-broker.knativetutorial.svc.cluster.
local"\
-XPOST\
-H"Ce-Id:1234"\
-H"Ce-Specversion:1.0"\
-H"Ce-Type:defaultChain"\
-H"Ce-Source:curl"\
-H"Content-Type:application/json"\
-d'"Start"'
ApacheCamel
Apache Camel Quarkus has its own site:https://github.com/apache/camel-quarkus
WebSockets
Quarkuscanbeusedtohandlingwebsockets.
./mvnwquarkus:add-extension
-Dextensions="quarkus-websockets"
Andwebsocketsclassescanbeused:
@ServerEndpoint("/chat/{username}")@ApplicationScopedpublicclassChatSocket{
@OnOpenpublicvoidonOpen(Sessionsession,@PathParam("username")Stringusername){}
@OnClosepublicvoidonClose(..){}
@OnErrorpublicvoidonError(...,Throwablethrowable){}
@OnMessagepublicvoidonMessage(...){}
}
OpenAPI
QuarkuscanexposeitsAPIdescriptionasOpenAPIspecandtestitusingSwaggerUI.
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-smallrye-openapi"
Thenyouonlyneedtoaccessto /openapi togetOpenAPIv3specofservices.
You can update the OpenApi path by setting quarkus.smallrye-openapi.path property.
Also, incaseofstartingQuarkusapplication in dev or test mode,Swagger UI is accessible at /swagger-ui . If you want to use it inproduction mode you need to set quarkus.swagger-ui.always-
include propertytotrue .
You can update the Swagger UI path by setting quarkus.swagger-ui.path property.
quarkus.swagger-ui.path=/my-custom-path
PossibleSwaggerUIoptionswithquarkus.swagger-ui pre�x:
urls
The urls that will be included as options. (ie quarkus.swagger-ui.urls.petstore=https://petstore.swagger.io/v2/swagger.json )
urls-primary-name
If urls option is used, this will be the name of the defaultselection.
title
Thehtmltitleforthepage.
theme
SwaggerUIthemetobeused.
footer
Afooterforthehtmlpage.Nothingbydefault.
deep-linking
Enablesdeeplinkingfortagsandoperations.
display-operation-id
ControlsthedisplayofoperationIdinoperationslist.
default-models-expand-depth
Thedefaultexpansiondepthformodels.
default-model-expand-depth
Thedefaultexpansiondepthforthemodelonthemodel-examplesection.
default-model-rendering
ControlshowthemodelisshownwhentheAPIis�rstrendered.
display-request-duration
Controlsthedisplayoftherequestduration(inmilliseconds)for"Tryitout"requests.
doc-expansion
Controls the default expansion setting for the operations andtags.
filter
Enables�ltering.
max-displayed-tags
Limitsthenumberoftaggedoperationsdisplayedtoatmostthismany.
operations-sorter
Apply a sort to the operation list of each API. (alpha , method ,function )
show-extensions
Controlsthedisplayofvendorextension.
show-common-extensions
Controlsthedisplayofextensions.
tag-sorter
ApplyasorttothetaglistofeachAPI.
on-complete
Provides a mechanism to be noti�ed when Swagger UI has�nishedrenderinganewlyprovidedde�nition.
syntax-highlight
Set to false to deactivate syntax highlighting of payloads andcURLcommand.
oauth2-redirect-url
OAuthredirectURL.
request-interceptor
Functiontointerceptremotede�nition,"Tryitout",andOAuth2.0requests.
request-curl-options
Arrayofcommandlineoptionsavailabletothecurlcommand.
response-interceptor
Functiontointerceptremotede�nition,"Tryitout",andOAuth2.0responses.
show-mutated-request
Usesthemutatedrequest returnedfromarequestInterceptor toproducethecurlcommandintheUI.
supported-submit-methods
ListofHTTPmethodsthathavethe"Tryitout"featureenabled.
validator-url
Swagger UI attempts to validate specs against swagger.io’sonlinevalidator.
with-credentials
Enablespassingcredentials,asde�nedintheFetchstandard,inCORSrequeststhataresentbythebrowser.
model-property-macro
Functiontosetdefaultvaluestoeachpropertyinmodel.
parameter-macro
Functiontosetdefaultvaluetoparameters.
persist-authorization
Itpersistsauthorizationdataanditwouldnotbelostonbrowserclose/refresh.
layout
Thenameofacomponentavailableviathepluginsystemtouseasthetop-levellayoutforSwaggerUI.
plugins
AlistofpluginfunctionstouseinSwaggerUI.
presets
AlistofpresetstouseinSwaggerUI.
YoucancustomizetheoutputbyusingOpenAPIv3annotations.
@Schema(name="Developers",description="POJOthatrepresentsadeveloper.")
publicclassDeveloper{@Schema(required=true,example="Alex")privateStringname;}
@POST@Path("/developer")@Operation(summary="Createdeeloper",description="Onlybedonebyadmin.")
publicResponsecreateDeveloper(@RequestBody(description="Developerobject",
required=true,content=@Content(schema=
@Schema(implementation=Developer.class)))
Developerdeveloper)
All possible annotations can be seen atorg.eclipse.micropro�le.openapi.annotationspackage.
You can also serve OpenAPI Schema from static �les instead ofdynamicallygeneratedfromannotationscanning.
You need to put OpenAPIdocumentation under META-INF directory(ie:META-INF/openapi.yaml ).
Arequestto /openapi willserve thecombinedOpenAPIdocumentfrom the static �le and the generated from annotations. You candisable the scanningdocumentsby adding the next con�gurationproperty:mp.openapi.scan.disable=true .
Other valid document paths are: META-INF/openapi.yml , META-
INF/openapi.json , WEB-INF/classes/META-INF/openapi.yml , WEB-
INF/classes/META-INF/openapi.yaml , WEB-INF/classes/META-
INF/openapi.json .
You can store generated OpenAPI schema if quarkus.swagger-
ui.store-schema-directory isset.
PossibleOpenAPIoptionswithquarkus.smallrye-openapi pre�x:
pathThe path at which to register the OpenAPI Servlet. (default:openapi )
store-schema-directoryThegeneratedOpenAPI schemadocumentswill be storedhereonbuild.
security-schemeAdd a certain SecurityScheme with con�g. (basic , jwt , oidc ,oauth2Implicit )
security-scheme-name
Add a Security Scheme name to the generated OpenAPIdocument.(default:SecurityScheme )
security-scheme-descriptionAdd a description to the Security Scheme. (default:Authentication )
basic-security-scheme-valueAdd a scheme value to the Basic HTTP Security Scheme.(default:basic )
jwt-security-scheme-valueAdd a scheme value to the JWT Security Scheme. (default:bearer )
jwt-bearer-formatAddabearerformattotheJWTSecurityScheme.(default:JWT )
oidc-open-id-connect-urlAddaopenIdConnectUrlvaluetotheOIDCSecurityScheme
oauth2-implicit-refresh-urlAdd a implicit �ow refreshUrl value to the OAuth2 SecurityScheme
oauth2-implicit-authorization-urlAddanimplicit�owauthorizationUrlvaluetotheOAuth2SecurityScheme
oauth2-implicit-token-urlAdd an implicit �ow tokenUrl value to the OAuth2 SecurityScheme
MailSender
YoucansendemailsbyusingQuarkusMailerextension:
./mvnwquarkus:add-extension
-Dextensions="io.quarkus:quarkus-mailer"
You can inject two possible classes io.quarkus.mailer.Mailer forsynchronous API or io.quarkus.mailer.reactive.ReactiveMailer forasynchronous/reactiveAPI.
@InjectMailermailer;
Andthenyoucanusethemtosendanemail:
mailer.send(
Mail.withText("[email protected]","Subject","Body")
);
ReactiveMailclient
@InjectReactiveMailerreactiveMailer;
CompletionStage<Response>stage=
reactiveMailer.send(
Mail.withText("[email protected]","Subject","Body")
)
.subscribeAsCompletionStage()
.thenApply(x->Response.accepted().build());
If you are using quarkus-resteasy-mutiny , you can returnio.smallrye.mutiny.Uni type.
Mail class contains methods to add cc , bcc , headers , bounce
address ,replyto ,attachments ,inlineattachments andhtmlbody .
mailer.send(Mail.withHtml("[email protected]","Subject",body)
.addInlineAttachment("quarkus.png",
newFile("quarkus.png"),"image/png","<[email protected]>"));
If you need deep control you can inject Vert.xmail client@InjectMailClientclient;
Youneedtocon�gureSMTPpropertiestobeabletosendanemail:
[email protected]=smtp.sendgrid.netquarkus.mailer.port=465quarkus.mailer.ssl=truequarkus.mailer.username=....quarkus.mailer.password=....
ListofMailerparameters.quarkus. asapre�xisskippedinthenexttable.
Parameter Default Description
mailer.from Defaultaddress.
mailer.mockfalse in prod , true indev andtest .
Emails not sent, justprinted and stored inaMockMailbox .
mailer.bounce-
addressDefaultaddress.
mailer.host mandatory SMTPhost.
mailer.port 25 SMTPport.
mailer.username Theusername.
Parameter Default Description
mailer.password Thepassword.
mailer.ssl false EnablesSSL.
mailer.trust-all false Trustallcerti�cates.
mailer.max-pool-size 10 Max openconnections.
mailer.own-host-name
Hostname forHELO/EHLO andMessage-ID
mailer.keep-alive trueConnection poolenabled.
mailer.disable-esmtp false DisableESMTP.
mailer.start-tls OPTIONAL
TLS security mode.DISABLED , OPTIONAL ,REQUIRED .
mailer.login NONELogin mode. NONE ,OPTIONAL ,REQUIRED .
mailer.auth-methods Allmethods. Space-separatedlist.
mailer.key-store Pathofthekeystore.
mailer.key-store-
passwordKeystorepassword.
if you enable SSL for themailer and you want to build anativeexecutable,youwillneedtoenabletheSSLsupportquarkus.ssl.native=true .
Testing
If quarkus.mailer.mock is set to true , which is the default value indev and test mode, you can inject MockMailbox to get the sentmessages.
@InjectMockMailboxmailbox;
@BeforeEachvoidinit(){mailbox.clear();
}
List<Mail>sent=mailbox
.getMessagesSentTo("[email protected]");
ScheduledTasks
YoucanscheduleperiodictaskswithQuarkus.
@ApplicationScopedpublicclassCounterBean{
@Scheduled(every="10s",delayed="1s")voidincrement(){}
@Scheduled(cron="01510**?")voidmorningTask(){}}
every and cron parameters can be surrounded with {} and thevalueisusedascon�gpropertytogetthevalue.
@Scheduled(cron="{morning.check.cron.expr}")
voidmorningTask(){}
Andcon�gurethepropertyintoapplication.properties :
morning.check.cron.expr=01510**?
BydefaultQuarkusexpresion isused,butyoucanchange thatbysettingquarkus.scheduler.cron-type property.
quarkus.scheduler.cron-type=unix
org.quartz.Scheduler can be injected as any other bean andscehdulejobsprogrammatically.
@Injectorg.quartz.Schedulerquartz;
quartz.scheduleJob(job,trigger);
Kogito
Quarkus integrates with Kogito, a next-generation businessautomation toolkit from Drools and jBPM projects for addingbusinessautomationcapabilities.
Tostartusingityouonlyneedtoaddthenextextension:
./mvnwquarkus:add-extension
-Dextensions="kogito"
ApacheTika
Quarkus integrates with Apache Tika to detect and extractmetadata/textfromdifferent�letypes:
./mvnwquarkus:add-extension
-Dextensions="quarkus-tika"
@Injectio.quarkus.tika.TikaParserparser;
@POST@Path("/text")@Consumes({"text/plain","application/pdf","application/vnd.oasis.opendocument.text"})
@Produces(MediaType.TEXT_PLAIN)publicStringextractText(InputStreamstream){returnparser.parse(stream).getText();}
You can con�gure Apache Tika in application.properties �le byusingnextpropertiespre�xedwithquarkus :
Parameter Default Description
tika.tika-config-
pathtika-config.xml
Path to the Tikacon�gurationresource.
quarkus.tika.parsers
CSV of theabbreviated or fullparser class to beloaded by theextension.
tika.append-embedded-
contenttrue
The document mayhaveotherembeddeddocuments. Set ifautmaticallyappend.
JGit
QuarkusintegrateswithJGittointegratewithGitrepositories:
./mvnwquarkus:add-extension
-Dextensions="quarkus-jgit"
AndthenyoucanstartusingJGit:
try(Gitgit=Git.cloneRepository().setDirectory(tmpDir)
.setURI(url)
.call()){
returntmpDir.toString();}
Whenrunning innativemode,makesure tocon�gureSSLaccesscorrectlyquarkus.ssl.native=true (NativeandSSL).
WebResources
YoucanservewebresourceswithQuarkus.Youneedtoplacewebresources at src/main/resources/META-INF/resources and then theyareaccessible(iehttp://localhost:8080/index.html)
Bydefault static resources as servedunder the root context. Youcanchangethisbyusingquarkus.http.root-path property.
TransactionalMemory
QuarkusintegrateswiththeSoftwareTransactionalMemory(STM)implementationprovidedbytheNarayanaproject.
./mvnwquarkus:add-extension
-Dextensions="narayana-stm"
Transactional objects must be interfaces and annotated withorg.jboss.stm.annotations.Transactional .
@Transactional@NestedTopLevelpublicinterfaceFlightService{intgetNumberOfBookings();voidmakeBooking(Stringdetails);}
The pessimistic strategy is the default one, you can change tooptimisticbyusing@Optimistic .
Thenyouneedtocreatetheobjectinsideorg.jboss.stm.Container .
Container<FlightService>container=newContainer<>();FlightServiceImplinstance=newFlightServiceImpl();FlightServiceflightServiceProxy=container.create(instanc
e);
Theimplementationoftheservicesetsthelockingandwhatneedstobesaved/restored:
importorg.jboss.stm.annotations.ReadLock;importorg.jboss.stm.annotations.State;importorg.jboss.stm.annotations.WriteLock;
publicclassFlightServiceImplimplementsFlightService{@StateprivateintnumberOfBookings;
@ReadLockpublicintgetNumberOfBookings(){returnnumberOfBookings;}
@WriteLockpublicvoidmakeBooking(Stringdetails){numberOfBookings+=1;
}
}
Any member is saved/restored automatically (@State is notmandatory).Youcanuse@NotState toavoidbehaviour.
Transactionboundaries
Declarative
@NestedTopLevel : De�nes that the containerwill create a newtop-leveltransactionforeachmethodinvocation.
@Nested :De�nesthatthecontainerwillcreateanewtop-levelornestedtransactionforeachmethodinvocation.
Programmatically
AtomicActionaa=newAtomicAction();
aa.begin();
{
try{flightService.makeBooking("BA123...");
taxiService.makeBooking("EastCoastTaxis...");
aa.commit();
}catch(Exceptione){aa.abort();
}
}
Quartz
Quarkus integrates with Quartz to schedule periodic clusteredtasks.
./mvnwquarkus:add-extension
-Dextensions="quartz"
@ApplicationScopedpublicclassTaskBean{
@Transactional@Scheduled(every="10s")voidschedule(){Tasktask=newTask();task.persist();
}
}
Tocon�gureinclusteredmodevidaDataSource:
quarkus.datasource.url=jdbc:postgresql://localhost/quarkus_
test
quarkus.datasource.driver=org.postgresql.Driver
#...
quarkus.quartz.clustered=true
quarkus.quartz.store-type=db
Youneedtode�nethedatasourceusedbyclusteredmodeand also import the database tables following the Quartzschema.
Quartz can be con�gured usinf the following properties withquarkus.quartz pre�x:
clustered
Enableclustermodeornot.
store-type
Thetypeofstoretouse.Possiblevalues:ram ,db (default:ram )
datasource
Thenameofthedatasourcetouse.
table-prefix
Thepre�xforquartzjobstoretables.(default:QRTZ_ )
trigger-listeners.<name>.class
Classnameforthetrigger.
trigger-listeners.<name>.property-name
Thepropertiespassedtotheclass.
job-listeners.<name>.class
Classnameforthejob.
job-listeners.<name>.property-name
Thepropertiespassedtotheclass.
plugins.<name>.class
Classnamefortheplugin.
plugins.<name>.property-name
The properties passed to the class
instance-name
The name of the Quartz instance. (default:QuarkusQuartzScheduler )
thread-count
Thesizeofschedulerthreadpool.(default:25 )
thread-priority
Threadpriorityofworkerthreadsinthepool.(default:5 )
force-start
The scheduler will be started even if no scheduled businessmethodsarefound.
start-mode
Scheduler can be started in different modes: normal , forced orhalted .(default:normal )
Qute
Qute is a templating engine designed speci�cally to meet theQuarkus needs. Templates should be placed by default atsrc/main/resources/templates aandsubdirectories.
./mvnwquarkus:add-extension
-Dextensions="quarkus-resteasy-qute"
Templatescanbede�nedinanyformat,incaseofHTML:
item.html
{@org.acme.Itemitem}
<!DOCTYPEhtml><html>
<head>
<metacharset="UTF-8">
<title>{item.name}</title>
</head>
<body>
<h1>{item.name?:'Unknown'}</h1>
<h2>{str:reverse('Hello')}</h2>
<div>Price:{item.price}</div>
{#ifitem.price>100}
<div>DiscountedPrice:{item.discountedPrice}</div>
{/if}
</body>
</html>
First line is notmandatory but helpsondoingproperty checksatcompilationtime.
Includingtemplatespassingparameters:
<html>
<head>
<metacharset="UTF-8">
<title>SimpleInclude</title>
</head>
<body>
{#includefoolimit=10/}
</body>
</html>
Torenderthetemplate:
publicclassItem{publicStringname;publicBigDecimalprice;}
@Injectio.quarkus.qute.Templateitem;
@GET@Path("{id}")@Produces(MediaType.TEXT_HTML)publicTemplateInstanceget(@PathParam("id")Integerid){returnitem.data("item",service.findItem(id));}
@TemplateExtensionstaticBigDecimaldiscountedPrice(Itemitem){returnitem.price.multiply(newBigDecimal("0.9"));}
@TemplateExtension(namespace="str")publicstaticclassStringExtensions{staticStringreverse(Stringval){returnnewStringBuilder(val).reverse().toString();}
}
If@ResourcePath isnotusedinTemplate thenthenameofthe�eldisused as �le name. In this case the �le should besrc/main/resources/templates/item.{} . Extension of the �le is notrequiredtobeset.
discountedPrice is not a �eld of the POJO but a method call.Methodde�nitionmust be annotatedwith @TemplateExtension andbestaticmethod.Firstparameterisusedtomatchthebaseobject(Item ).@TemplateExtension canbeusedatclasslevel:
@TemplateExtensionpublicclassMyExtensions{staticBigDecimaldiscountedPrice(Itemitem){returnitem.price.multiply(newBigDecimal("0.9"));}
}
Methodswithmultipleparametersaresupportedtoo:
{item.discountedPrice(2)}
staticBigDecimaldiscountedPrice(Itemitem,intscale){returnitem.price.multiply(scale);}
Qute for syntax supports any instance of Iterable , Map.EntrySet ,Stream orInteger .
{#foriintotal}
{i}:
{/for}
Thenextmapmethodsaresupported:
{#forkeyinmap.keySet}
{#forvalueinmap.values}
{map.size}
{#ifmap.isEmpty}
{map['foo']
Thenextlistmethodsaresupported:
{list[0]}
Thenextnumbermethodsaresupported:
{#ifcounter.mod(5)==0}
Switch/When
{#switchperson.name}
{#case'John'}
HeyJohn!
{#case'Mary'}
HeyMary!
{/switch}
{#whenitems.size}
{#is1}(1)Thereisexactlyoneitem!
{#is>10}(2)Therearemorethan10items!
{#else}(3)Thereare2-10items!
{/when}
Followingoperatorscanbeusedeitherinwhen and switch : not,ne,!= ,gt,> ,ge,>= ,lt,< ,le,<= ,in ,ni,!in .
MessageBundling
@io.quarkus.qute.i18n.MessageBundlepublicinterfaceAppMessages{@io.quarkus.qute.i18n.Message("Hello{name}!")Stringhello_name(Stringname);}
Thereare3methodstoinjectthemessage:
MessageBundles.get(AppMessages.class).hello_name("Lucie");
or
@InjectAppMessagesapp;
app.hello_name("Lucie");
or
<p>{msg:hello_name('Lucie')}</p>
Localization
Therearetwowaystosetlocalizedmessage:
@io.quarkus.qute.i18n.Localized("de")publicinterfaceGermanAppMessages{
@[email protected]("Hallo{name}!")Stringhello_name(Stringname);}
or
msg_de.properties
hello_name=Hallo{name}!
Youcanrenderprogrammaticalythetemplatestoo:
//filelocatedatsrc/main/resources/templates/reports/v1/
report_01.{}
@ResourcePath("reports/v1/report_01")Templatereport;
Stringoutput=report
.data("samples",service.get())
.render();
ValueResolvers
Valueresolversareinvokedwhenevaluatingexpressions.
voidconfigureEngine(@ObservesEngineBuilderbuilder){builder.addValueResolver(ValueResolver.builder()
.appliesTo(ctx->ctx.getBase()instanceofLong&&ctx.getName().equals("tenTimes"))
.resolveSync(ctx->(Long)ctx.getBase()*10)
.build());
}
ContentFilters
Content�lterscanbeusedtomodifythetemplatecontentsbeforeparsing.
voidconfigureEngine(@ObservesEngineBuilderbuilder){builder.addParserHook(newParserHook(){@OverridepublicvoidbeforeParsing(ParserHelperparserHelper){
parserHelper.addContentFilter(contents->content
s.replace("${","$\\{"));
}
});
}
ReactiveandAsync
CompletionStage<String>async=report.renderAsync();
Multi<String>publisher=report.createMulti();
Uni<String>content=io.smallrye.mutiny.Uni.createFrom()
.completionStage(()->report.r
enderAsync());
QuteMailIntegration
@InjectMailTemplatehello;
CompletionStage<Void>c=hello.to("[email protected]")
.subject("HellofromQutetemplate")
.data("name","John")
.send();
INFO: Template located at src/main/resources/templates/hello.
[html|txt] .
Sentry
Quarkus integrates with Sentry for logging errors into an errormonitoringsystem.
./mvnwquarkus:add-extension
-Dextensions="quarkus-logging-sentry"
And the con�guration to send all errors occuring in the packageorg.example toSentrtywithDSNhttps://[email protected]/1234 :
quarkus.log.sentry=truequarkus.log.sentry.dsn=https://[email protected]/1234quarkus.log.sentry.level=ERRORquarkus.log.sentry.in-app-packages=org.example
Fulllistofcon�gurationpropertieshavingquarkus.log aspre�x:
sentry.enable
EnabletheSentryloggingextension(default:false)
sentry.dsn
Wheretosendevents.
sentry.level
Loglevel(default:WARN )
sentry.server-name
Setstheservernamethatwillbesentwitheachevent.
sentry.in-app-packages
Con�gurewhichpackagepre�xesyourapplicationuses.
JSch
QuarkusintegrateswithJschforSSHcommunication.
./mvnwquarkus:add-extension
-Dextensions="quarkus-jsch"
JSchjsch=newJSch();Sessionsession=jsch.getSession(null,host,port);session.setConfig("StrictHostKeyChecking","no");
session.connect();
Cache
Quarkuscancachemethodcallsbyusingaskeythetuple(method+arguments).
./mvnwquarkus:add-extension
-Dextensions="cache"
@io.quarkus.cache.CacheResult(cacheName="weather-cache")publicStringgetDailyForecast(LocalDatedate,Stringcity){}
@CacheInvalidate removes the element represented by thecalculatedcachekey fromcache. @CacheInvalidateAll removesallentriesfromthecache. @CacheKey tospeci�callysetthearguments
b d k d f ll
@ApplicationScopedpublicclassCachedBean{
@CacheResult(cacheName="foo")publicObjectload(Objectkey){}
@CacheInvalidate(cacheName="foo")publicvoidinvalidate(Objectkey){}
@CacheInvalidateAll(cacheName="foo")publicvoidinvalidateAll(){}}
You can disable the caching system by settingquarkus.cache.enabled propertytofalse .
ThisextensionusesCaffeineasitsunderlyingcachingprovider.
Eachcachecanbecon�guredindividually:
quarkus.cache.caffeine."foo".initial-capacity=10quarkus.cache.caffeine."foo".maximum-size=20quarkus.cache.caffeine."foo".expire-after-write
quarkus.cache.caffeine."bar".maximum-size=1000
Full list of con�guration properties having quarkus.cache.caffeine.[cache-name] aspre�x:
initial-capacity
Minimumtotalsizefortheinternaldatastructures.
maximum-size
Maximumnumberofentriesthecachemaycontain.
expire-after-write
Speci�esthateachentryshouldbeautomaticallyremovedfromthe cache once a �xed duration has elapsed after the entry’screation,orlastwrite.
expire-after-access
Speci�esthateachentryshouldbeautomaticallyremovedfromthe cache once a �xed duration has elapsed after the entry’screation,orlastwrite.
Youcanmultiplecacheannotationsonasinglemethod.
If you see a javax.enterprise.context.ContextNotActiveException ,you need to add the quarkus-smallrye-context-propagation
extension.
Banner
Bannerisprintedbydefault.Itisnotanextensionbutplacedinthecore.
quarkus.banner.path
Path is relative to root of the classpath. (default:)
quarkus.banner.enabled
Enablesbanner.(default:true )
OptaPlanner
QuarkusintegrateswithOptaPlanner.
./mvnwquarkus:add-extension
-Dextensions="quarkus-optaplanner,quarkus-optaplanner-ja
ckson"
@PlanningSolutionpublicclassTimeTable{}
@InjectprivateSolverManager<TimeTable,UUID>solverManager;
UUIDproblemId=UUID.randomUUID();
SolverJob<TimeTable, UUID> solverJob = solverManager.solve
(problemId,problem);
TimeTablesolution=solverJob.getFinalBestSolution();
Possiblecon�gurationoptionspre�xedwithquarkus.optaplanner :
solver-config-xml
Aclasspath resource to read thesolver con�gurationXML.Notmandatory.
solver.environment-mode
Enable runtime assertions to detect common bugs in yourimplementation during development. Possible values:FAST_ASSERT , FULL_ASSERT , NON_INTRUSIVE_FULL_ASSERT ,NON_REPRODUCIBLE ,REPRODUCIBLE .(default:REPRODUCIBLE )
solver.move-thread-count
Enable multithreaded solving for a single problem. Possiblevalues: MOVE_THREAD_COUNT_NONE , MOVE_THREAD_COUNT_AUTO ,anumberor formula based on the available processors. (default:MOVE_THREAD_COUNT_NONE )
solver.termination.spent-limit
Howlongthesolvercanrun.(ie5s )
solver.termination.unimproved-spent-limit
Howlongthesolvercanrunwithout�ndinganewbestsolutionafter�ndinganewbestsolution.(ie2h )
solver.termination.best-score-limit
Terminates thesolverwhenaspeci�corhigherscorehasbeenreached.(ie0hard/-1000soft )
solver-manager.parallel-solver-count
The number of solvers that run in parallel. (default:PARALLEL_SOLVER_COUNT_AUTO )
Context Propagation
./mvnwquarkus:add-extension
-Dextensions="quarkus-smallrye-context-propagation"
If using mutiny extension together you already get contextpropagation for ArC, RESTEasy and transactions. WithCompletionStage youneedto:
@InjectThreadContextthreadContext;@InjectManagedExecutormanagedExecutor;
threadContext.withContextCapture(..)
.thenApplyAsync(r->{},managedExecutor);
If youaregoing tousesecurity ina reactiveenvironmentyouwilllikelyneedSmallryeContentPropagationtopropagatetheidentitythroughoutthereactivecallback.
Con�gurationfromHasiCorpConsul
Youcanreadruntimecon�gurationfromHashiCorpConsul.
./mvnwquarkus:add-extension
-Dextensions="consul-config"
Youneedtocon�gureConsul:
quarkus.consul-config.enabled=truequarkus.consul-config.agent.host-port=localhost:8500quarkus.consul-config.properties-value-keys=config/consul-test
@ConfigProperty(name="greeting.message")Stringmessage;
InConsul:
"Key":"config/consul-test",
"Value":"greeting.message=HellofromConsul"
Possible con�guration parameters, pre�xed with quarkus.consul-config :
enabled
The application will attempt to look up the con�guration fromConsul.(default:false )
prefix
Commonpre�xthatallkeyssharewhenlookingupthekeysfromConsul. The pre�x is not included in the keys of the usercon�guration
raw-value-keys
Keyswhosevalueisarawstring.Thekeysthatendupintheusercon�gurationarethekeysspeci�edherwith'/'replacedby'.'
properties-value-keys
Keyswhosevaluerepresentsaproperties-like�leconttent.
fail-on-missing-key
If the application will not start if any of the con�gured con�gsourcescannotbelocated.(default:true )
trust-store
TrustStore to be used containing the SSL certi�cate used byConsulagent.
trust-store-password
PasswordofTrustStoretobeusedcontainingtheSSLcerti�cateusedbyConsulagent.
key-password
Password to recover key from KeyStore for SSL clientauthenticationwithConsulagent.
agent.host-port
Consulagenthost.(default:localhost:8500 )
agent.use-https
UseHTTPSwhencommunicatingwiththeagent.(default:false )
agent.token
Consultokentobeprovidedwhenauthenticationisenabled.
agent.key-store
KeyStore(classpathor�lesystem)tobeusedcontainingtheSSLcerti�cateusedbyConsulagent.
agent.key-store-password
PasswordofKeyStore.
agent.trust-certs
Totrustallcerti�catesornot.
agent.connection-timeout
Connectiontimeout.(default:10S )
agent.read-timeout
Readingtimeout.(default:60S )
AmazonAlexa
YoucanuseAmazonAlexabyaddingtheextension:
./mvnwquarkus:add-extension
-Dextensions="quarkus-amazon-alexa"
WebJarLocator
Tochangehowyoucanrefer towebjarsskipping theversionpartyoucanuseWebJarslocatorextension.
./mvnwquarkus:add-extension
-Dextensions="webjars-locator"
Then the JavaScript location is changed from/webjars/jquery/3.1.1/jquery.min.js to/webjars/jquery/jquery.min.js inyourHTML�les.
AmazonSES
mvnquarkus:add-extension
-Dextensions="amazon-ses"
@Injectsoftware.amazon.awssdk.services.ses.SesClientsesClient;
@Injectsoftware.amazon.awssdk.services.ses.SesAsyncClient sesClien
t;
quarkus.ses.endpoint-override=http://localhost:8012quarkus.ses.aws.region=us-east-1quarkus.ses.aws.credentials.type=staticquarkus.ses.aws.credentials.static-provider.access-key-id=test-key
quarkus.ses.aws.credentials.static-provider.secret-access-key=test-secret
YouneedtosetaHTTPclienteitherURLConnection :
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
orApacheHTTP:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>
quarkus.ses.sync-client.type=apache
Orasync:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
Con�gurationpropertiesare thesameasAmazonDynamoDB butchangingthepre�xfromdynamodb toses .
Jbang
Creatinganinitialscript:
jbangscripting/quarkusapp.java
AddingQuarkusdependenciesinscript:
//DEPSio.quarkus:quarkus-resteasy:{quarkus-version}
PutsomeQuarkusCLIcode:
@Path("/hello")@ApplicationScopedpublicclassquarkusapp{@GETpublicStringsayHello(){return"hello";}
publicstaticvoidmain(String[]args){Quarkus.run(args);
}
}
Torunthescript:
jbangquarkusapp.java
AMavengoalisprovidedtoscaffoldaproject:
mvnio.quarkus:quarkus-maven-plugin:<version>:create-jbang
SpringDI
Quarkus provides a compatibility layer for Spring dependencyinjection.
./mvnwquarkus:add-extension
-Dextensions="quarkus-spring-di"
Some examples ofwhat you can do. Notice that annotations aretheSpringoriginalones.
@Configuration
publicclassAppConfiguration{
@Bean(name="capitalizeFunction")
publicStringFunctioncapitalizer(){
returnString::toUpperCase;
}
}
Orasacomponent:
@Component("noopFunction")publicclassNoOpSingleStringFunctionimplementsStringFunction{}
Also as a service and injection properties fromapplication.properties .
@ServicepublicclassMessageProducer{
@Value("${greeting.message}")Stringmessage;
}
Andyoucaninjectusing Autowired orconstructor inacomponentandinaJAX-RSresourcetoo.
@ComponentpublicclassGreeterBean{
privatefinalMessageProducermessageProducer;
@Autowired@Qualifier("noopFunction")StringFunctionnoopStringFunction;
publicGreeterBean(MessageProducermessageProducer){this.messageProducer=messageProducer;}
}
SpringBootCon�guration
Quarkus provides a compatibility layer for Spring BootConfigurationProperties .
./mvnwquarkus:add-extension
-Dextensions="quarkus-spring-boot-properties"
@ConfigurationProperties("example")publicfinalclassClassProperties{
privateStringvalue;privateAnotherClassanotherClass;
//getters/setters
}
example.value=class-valueexample.anotherClass.value=true
SpringCloudCon�gClient
Quarkus integrates Spring Cloud Con�g Client and MicroPro�leCon�gspec.
./mvnwquarkus:add-extension
-Dextensions="quarkus-spring-cloud-config-client"
Youneedtocon�guretheextension:
quarkus.spring-cloud-config.uri=http://localhost:8089quarkus.spring-cloud-config.username=userquarkus.spring-cloud-config.password=passquarkus.spring-cloud-config.enabled=true
@ConfigProperty(name="greeting.message")Stringgreeting;
Pre�xisquarkus.spring-cloud-config .
uri
Base URI where the Spring Cloud Con�g Server is available.(default:localhost:8888 )
username
Username to be used if the Con�g Server has BASIC Authenabled.
password
Password to be used if the Con�g Server has BASIC Authenabled.
enabled
Enables read con�guration from Spring Cloud Con�g Server.(default:false )
fail-fast
True to not start application if cannot access to the server.(default:false )
connection-timeout
The amount of time to wait when initially establishing aconnectionbeforegivingupandtimingout.(default:10S )
read-timeout
The amount of time to wait for a read on a socket before anexceptionisthrown.(default:60S )
label
Thelabeltobeusedtopullremotecon�gurationproperties.
SpringWeb
QuarkusprovidesacompatibilitylayerforSpringWeb.
./mvnwquarkus:add-extension
-Dextensions="quarkus-spring-web"
Speci�cally supports the REST related features. Notice thatinfrastructurethingslikeBeanPostProcessor willnotbeexecuted.
@RestController@RequestMapping("/greeting")publicclassGreetingController{
privatefinalGreetingBeangreetingBean;
publicGreetingController(GreetingBeangreetingBean){this.greetingBean=greetingBean;}
@GetMapping("/{name}")publicGreetinghello(@PathVariable(name="name")Stringname){
returnnewGreeting(greetingBean.greet(name));}
}
Supported annotations are: RestController , RequestMapping ,GetMapping , PostMapping , PutMapping , DeleteMapping , PatchMapping ,RequestParam , RequestHeader , MatrixVariable , PathVariable ,CookieValue , RequestBody , ResponseStatus , ExceptionHandler andRestControllerAdvice .
If you scaffold theprojectwith spring-web extension, thenSpringWeb annotations are sed in the generated project.mvnio.quarkus:quarkus-maven-plugin:1.13.0.Final:create…-
Dextensions="spring-web" .
The next return types are supported:org.springframework.http.ResponseEntity andjava.util.Map .
The next parameter types are supported: An Exception argumentand ServletRequest/HttpServletRequest (adding quarkus-undertow
dependency).
SpringDataJPA
While users are encouraged to useHibernate ORMwith Panachefor Relational Database access, Quarkus provides a compatibilitylayerforSpringDataJPArepositories.
./mvnwquarkus:add-extension
-Dextensions="quarkus-spring-data-jpa"
INFO:OfcourseyoustillneedtoaddtheJDBCdriver,andcon�gureitinapplication.properties .
publicinterfaceFruitRepositoryextendsCrudRepository<Fruit,Long>{List<Fruit>findByColor(Stringcolor);}
AndthenyoucaninjectiteitherasshowninSpringDIorinSpringWeb.
Interfacessupported:
org.springframework.data.repository.Repository
org.springframework.data.repository.CrudRepository
org.springframework.data.repository.PagingAndSortingReposito
ry
org.springframework.data.jpa.repository.JpaRepository .
INFO: Generated repositories are automatically annotated with@Transactional .
Repositoryfragmentsisalsosupported:
publicinterfacePersonRepositoryextendsJpaRepository<Person,Long>,PersonFragment{
voidmakeNameUpperCase(Personperson);}
Userde�nedqueries:
@Query("selectmfromMoviemwherem.rating=?1")Iterator<Movie>findByRating(Stringrating);
@Modifying@Query("deletefromMoviewhererating=:rating")voiddeleteByRating(@Param("rating")Stringrating);
@Query(value="SELECTCOUNT(*),publicationYearFROMBookGROUPBYpublicationYear")
List<BookCountByYear>findAllByPublicationYear2();
interfaceBookCountByYear{intgetPublicationYear();
LonggetCount();}
Whatiscurrentlyunsupported:
Methods oforg.springframework.data.repository.query.QueryByExampleExec
utor
QueryDSLsupport
Customizingthebaserepository
java.util.concurrent.Future asreturntype
Nativeandnamedquerieswhenusing@Query
SpringDataRest
WhileusersareencouragedtouseRESTDatawithPanachefortheREST data access endpoints generation, Quarkus provides acompatibility layerforSpringDataRESTintheformofthe spring-data-rest extension.
./mvnwquarkus:add-extension
-Dextensions="spring-data-rest"
importjava.util.Optional;importorg.springframework.data.repository.CrudRepository;import org.springframework.data.rest.core.annotation.Reposi
toryRestResource;
import org.springframework.data.rest.core.annotation.RestRe
source;
@RepositoryRestResource(exported=false,path="/my-fruits")
publicinterfaceFruitsRepositoryextendsCrudRepository<Fruit,Long>{@RestResource(exported=true)Optional<Fruit>findById(Longid);@RestResource(exported=true)Iterable<Fruit>findAll();}
The spring-data-jpa extensionwillgenerateanimplementationforthisrepository.Thenthe spring-data-rest extensionwillgenerateaRESTCRUDresourceforit.
Thefollowinginterfacesaresupported:
org.springframework.data.repository.CrudRepository
org.springframework.data.repository.PagingAndSortingReposito
ry
org.springframework.data.jpa.repository.JpaRepository
SpringSecurity
QuarkusprovidesacompatibilitylayerforSpringSecurity.
./mvnwquarkus:add-extension
-Dextensions="spring-security"
You need to choose a security extension to de�ne user, roles, …such as openid-connect , oauth2 , properties-file or security-jdbcasseenatRBAC.
Then you can use Spring Security annotations to protect themethods:
@Secured("admin")@GetMappingpublicStringhello(){return"hello";}
Quarkus provides support for someof themost used features ofSpringSecurity’s@PreAuthorize annotation.
Someexamples:
hasRole
@PreAuthorize("hasRole('admin')")
@PreAuthorize("hasRole(@roles.USER)") where roles is a beande�nedwith @Component annotation and USER is a public �eldoftheclass.
hasAnyRole
@PreAuthorize("hasAnyRole(@roles.USER,'view')")
PermitandDenyAll
@PreAuthorize("permitAll()")
@PreAuthorize("denyAll()")
AnonymousandAuthenticated
@PreAuthorize("isAnonymous()")
@PreAuthorize("isAuthenticated()")
Checks if the current logged in user is the same as theusernamemethodparameter:
@PreAuthorize("#person.name == authentication.principal.username")
publicvoiddoSomethingElse(Personperson){}
Checksifcallingamethodifusercanaccess:
@PreAuthorize("@personChecker.check(#person, authenticatio
n.principal.username)")
publicvoiddoSomething(Personperson){}
@ComponentpublicclassPersonChecker{publicbooleancheck(Personperson,Stringusername){returnperson.getName().equals(username);}
}
Combiningexpressions:
@PreAuthorize("hasAnyRole('user','admin')AND#user==principal.username")
publicvoidallowedForUser(Stringuser){}
SpringCache
Quarkus provides a compatibility layer for Spring dependencyinjection.
./mvnwquarkus:add-extension
-Dextensions="spring-cache"
@org.springframework.cache.annotation.Cacheable("someCache")
publicGreetinggreet(Stringname){}
Quarkus provides compatibility with the following Spring Cacheannotations:
@Cacheable
@CachePut
@CacheEvict
SpringSchedule
Quarkus provides a compatibility layer for Spring Scheduledannotation.
./mvnwquarkus:add-extension
-Dextensions="spring-scheduled"
@org.springframework.scheduling.annotation.Scheduled(cron="*/5****?")
voidcronJob(){System.out.println("Cronexpressionhardcoded");
}
@Scheduled(fixedRate=1000)@Scheduled(cron="{cron.expr}")
Resources
https://quarkus.io/guides/
https://www.youtube.com/user/lordofthejars
Authors:
@alexsotobJavaChampionandDirectorofDevExpatRedHat
1.13.0.Final