This Banner is For Sale !!
Get your ad here for a week in 20$ only and get upto 15k traffic Daily!!!

Quarkus : Greener, Better, Faster, Stronger


So that you heard of Quarkus and the way it’s blazingly quick, and also you wish to take your share of the cake.

You come from a world the place sharing code is all about doing maven modules, and should you come from the Spring world, scanning it when your utility begins. Nicely you possibly can overlook about jar scanning. If Quarkus is quicker and greener, it is -amongst different things- as a result of it really works at compile time as a lot as doable. And that is accomplished by means of the extension mecanism.

So if you wish to present companies to others and hold that quick frictionless feeling, you’ll have to achieve this.

On this article we are going to stroll you thru the scaffolding of an extension to a completed one, making use of it is best capabilities. I will not cowl all of them. Firstly as a result of I do not know all of them, secondly as a result of it will take way more than an article…

I’ll attempt to hold a deal with speedy startups, and least reminiscence consumption: the smaller, the higher.

To do this Quarkus presents us a framework to do a lot of the job throughout the compilation/packaging part, in order that the applying startup is left with the least doable duties.

💡 You’ll be able to observe alongside the article or deep dive instantly in the extension code

If Quarkus claims to be greener is because of the truth that it makes all it could to scale back reminiscence footprint. Small artefact results in smaller classoader and fewer reminiscence consumption.



⚠️ Warning

Writting an exension just isn’t all the time the way in which. There are lots of issues that may be accomplished with out the burden. There are even good articles on easy methods to not write an extension (here’s one from Loïc Mathieu)



Context

Let’s fake that we’re working for an enormous firm (Say Acme Firm ©) that has many java utility and needs emigrate to Quarkus.

Our firm has it is personal centralized tech’ conferences referential supplier, and we wish to facilitate its use to the developpers. The prefered solution to go along with Quarkus is to create a customized ConfigSourceProvider.

So that is what we will probably be implementing right here by placing the code in an extension so that’s might be shareable with all the corporate purposes, and also can present another companies.



🚧 Scaffolding the extension

Creating an extension is fairly properly documented within the Quarkus guides.

So following the information we are going to simply do :

mvn io.quarkus.platform:quarkus-maven-plugin:3.6.1:create-extension -N 
    -DgroupId=org.acme 
    -DextensionId=configuration-provider
Enter fullscreen mode

Exit fullscreen mode

💡 Remember to replace this plugin model to the newest one…

It’ll generate the next folder tree :

Challenge file folder

├── configuration-provider 1️⃣
│   ├── pom.xml 2️⃣
│   ├── deployment 3️⃣
│   ├── runtime 4️⃣
│   │   └── src
│   │       └── essential
│   │           ├── java
│   │           └── sources
│   │               └── META-INF
│   │                   └── quarkus-extension.yaml 5️⃣
│   ├── integration-tests 6️⃣
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – Root folder
2️⃣ – Father or mother maven undertaking descriptor
3️⃣ – Compile time module, the place all of the magic will lie
4️⃣ – Runtime module, the place our config supply will probably be
5️⃣ – Extension descriptor
6️⃣ – Will include our integration exams, consisting of an utility utilizing the extension and a few take a look at assertions

Within the above schema all folders are basic modules with a typical construction



The runtime module

The runtime module comprises plain Quarkus flavoured java code, so we cannot cowl each particulars however simply spotlight some attention-grabbing bits.

Please remind that the extension is offering values by calling the Acme Referential by means of it is REST API. So it relies on a java relaxation consumer that must be configured, for instance -for the least-, that it wants a URL.



The config supply manufacturing facility

I’ve chosen to observe the ConfigSourceFactory path to instantiate my ConfigSource bean. It offers me extra potentialities as to how I can provide context and instantiate the ConfigSource. I simply do not want the registration half, as it is going to be accomplished within the deployment module.



Configuring the REST API consumer

Exterior configuration mapping is completed by the EnvironmentRuntimeConfiguration interface.

@ConfigRoot(part = ConfigPhase.RUN_TIME) 1️⃣
@ConfigMapping(prefix = "acme")2️⃣
public interface EnvironmentRuntimeConfiguration {

    /**
     * The atmosphere supplier server URL.
     *
     * [NOTE]
     * ====
     * Worth should be a sound `URI`
     * ====
     *
     * @asciidoclet 4️⃣
     */
    @WithName("atmosphere.url") 3️⃣
    URI url();
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – This tells that this bean is used at runtime
2️⃣ – Specifies the foundation property key
3️⃣ – Specifies this particular property key that will probably be acme.atmosphere.url
4️⃣ – Word the annotation that will probably be usefull when producing the extension configuration.

(jump back to the end



The AcmeConfigSource

The AcmeConfigSource is fairly easy :

AcmeConfigSource open

public class AcmeConfigSource implements ConfigSource {

    // Ignorable Code

    public AcmeConfigSource(EnvironmentRuntimeConfiguration runtimeConfiguration) {
        environmentProviderClient = new EnvironmentProviderClient(runtimeConfiguration.url());
        String sample = "(?<env>.*).(?<key>.*)";

        // Create a Sample object
        patternMatcher = Sample.compile(sample);
    }

    @Override
    public String getValue(String propertyName) {
        if (Predicate.not(isAcme)
                .or(isProviderConfiguration)
                .take a look at(propertyName))
            return null;

        // Now create matcher object.
        Matcher m = patternMatcher.matcher(propertyName);

        if (m.discover()) {
            Map<String, String> env = environmentProviderClient.getEnvironment(m.group("env"));
            if (env != null) {
                return env.get(m.group("key"));
            }
        }
        return null;
    }
    // extra necessary code
}
Enter fullscreen mode

Exit fullscreen mode

That is about all there may be to say concerning the runtime module.



The deployment module

Now let’s dive into the deployment module. The code executed at compile time is usualy positioned in courses known as processor.

Now I would like to inform quarkus that it must execute code throughout the compile time. That’s accomplished by annotating strategies with @BuildStep. These strategies produce AND eat BuildItem. There are many of them, and one that can definitely fit your want.

There isn’t a easy solution to order a number of step strategies, however quarkus will be certain that the construct gadgets requested by a construct step exist earlier than invoking it, and that’s how we will order buildsteps.



Getting utility scan end result

In a category known as org.acme.configurationProvider.deploymen.EnvironmentInjectorProcessor, in created the next technique :

@BuildStep
void askForApplicationScan(
   ApplicationIndexBuildItem index, 1️⃣
   BuildProducer<AcmeEnvironmentBuildItem> buildProducer 2️⃣) {
   index.getIndex().getAnnotations(ConfigProperty.class)
         .stream()
         .map(AnnotationInstance::values)
         .flatMap(Checklist::stream)
         .filter(worth -> worth.asString().startsWith("acme"))
         .findFirst()
         .ifPresent(annotationInstance -> buildProducer.produce(new AcmeEnvironmentBuildItem()));
    }
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – The tactic is asking to get an index of the courses current within the utility that is utilizing the extension
2️⃣ – Right here requesting the construct producer that’s used to assemble all produced AcmeEnvironmentBuildItem.

The index lets us interract with him by means of many entry factors, and amongst them (technique names are self talking): getClassesInPackage, getAnnotations, getAllKnownImplementors, and plenty of extra.

On this case, I wish to be certain that there’s a actual want for this extension, and which means not less than on want of a ConfigProperty with a key beginning with acme..

The AcmeEnvironmentBuildItem is an empty construct merchandise that I’m utilizing solely for instance BuildStep ordering, additionally this isn’t very ordinary that an extension makes positive it is wanted, however I wish to spotlight that it is doable.

I additionally created a second technique :

@BuildStep
void envConfigSourceFactory(
   AcmeEnvironmentBuildItem acmeEnvironmentBuildItem, 1️⃣       
   BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder 2️⃣) {
  if (acmeEnvironmentBuildItem != null) {
    runTimeConfigBuilder.produce(
      new RunTimeConfigBuilderBuildItem(
        AcmeConfigSourceFactoryBuilder.class.getName()
      )
    );
    return;
  }
  logger.warn("You shoud not use this extension should you do not want it.");
    }
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – It consumes the AcmeEnvironmentBuildItem, that creates the construct step AcmeEnvironmentBuildItem
2️⃣ – And it produces a RunTimeConfigBuilderBuildItem

We will see that the tactic solely produces a RunTimeConfigBuilderBuildItem if wanted. This construct merchandise supplies a solution to register our AcmeConfigSourceFactoryBuilder for runtime part.

If the given AcmeEnvironmentBuildItem is null, the buidstep will warn the consumer, asking him if he’s positive the extension is required, letting him know that he ought to probaby take away the dependency.

When constructing its appication, the folowing log will probably be produced.

 WARN  [o.a.c.d.EnvironmentInjectorProcessor] 
    You shoud not use this extension if you don't want it.
Enter fullscreen mode

Exit fullscreen mode



Testing the extension

To check the extension, I’ll create a easy utility utilizing two extensions (not utilizing the Quarkus cli, since my extension is not a part of any platform):

. io.quarkus:picocli
. org.acme:configuration-provider

And create the next class :

package deal org.acme.picocli;

import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import picocli.CommandLine;

@CommandLine.Command
public class Starter implements Runnable{

    @Inject
    Logger log;

    @ConfigProperty(identify = "env.snowcamp.title")
    String snowcampConfTitle;
    @ConfigProperty(identify = "env.snowcamp.creator")
    String snowcampConfAuthor;

    @Override
    public void run() {
        log.information("********   WELCOME !     ********");
        log.infof("Welcome %s, that can current: "%s"%n",snowcampConfAuthor, snowcampConfTitle);
        log.information("*********************************");
    }
}
Enter fullscreen mode

Exit fullscreen mode

Now launching my utility I get :

2023-12-13 08:30:48,502 ERROR [i.q.r.Application] 
  Failed to begin utility (with profile [dev]):
    java.lang.RuntimeException: Failed to begin quarkus
    // Lengthy stacktrace
   Attributable to: io.smallrye.config.ConfigValidationException:
      Configuration validation failed:
    java.util.NoSuchElementException: 
      SRCFG00014: 
        The config property acme.atmosphere.url is required however it couldn't be discovered in any config supply
        // extra stacktrace
Enter fullscreen mode

Exit fullscreen mode

Oh sure after all, I must move the acme supplier URL, no points… Besides I haven’t got a dev atmosphere supplier at disposal…



The Devservice

Right here comes the devservices 🚀.

Till now we’ve seen how Quarkus will help us to scale back the variety of beans and jar scanning at rutime by doing all these process at compile time. That may assist us be greener and quicker, however not likely stronger from a developer expertise perspective.

Devservices helps the automated provisioning of unconfigured third celebration companies in improvement and take a look at mode. They are often supplied by extension leveraging (normally) TestContainer library.

So our extension will do exactly that.



The configuration

As was the case for the runtime I’ll use configuration courses, this time with the next :

@ConfigRoot(
   prefix = "acme", 1️⃣
   identify = "", 2️⃣
   part = ConfigPhase.BUILD_TIME 3️⃣)
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – The properties key prefix
2️⃣ – By default extension properties are on the quarkus namespace (that will make quarkus.acme.*), and never beeing a core or quarkiverse extension, I made a decision to not use the default namespace
3️⃣ – These properties will solely be editable at compile time.

The configuration will include two properties :

acme.deveservice.enabled
Enable to allow/disable the devservices for this extension. The default worth is true
acme.devservices.image-name
Enable to override the picture used for this devservice. The default worth is quay.io/jtama/acme-provider



The devservice processor

I now must make use of this configuration. So I create a org.acme.configurationProvider.deployment.devservice.DevServicesProcessor class. I’ll solely present probably the most related a part of the processor’s code.

The category has two responsabilty:

  1. Create or retrieve a container and get the required values to entry it.
  2. Inform Quarkus that there’s a operating devservice, to configure the applying accordingly.

All of the code proven on this chapter will probably be a simplified model of the true extension for a greater match to this format.



Operating the container

To run the container, we are going to leverage the testcontainer lib:

Generic container = new GenericContainer("quay.io/jtama/acme-provider")
  .withNetwork(Community.SHARED) 1️⃣
  .withExposedPorts(8080); 2️⃣ 
container.begin(); 3️⃣
return new DevServicesResultBuildItem.RunningDevService(DEV_SERVICE_LABEL,
                    container.getContainerId(), 4️⃣
                    container::shut, 5️⃣
                    Map.of("acme.atmosphere.url", "http://%s:%d".formatted(container.getHost(), container.getPort()))) 6️⃣;
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – Use the docker shared community
2️⃣ – Inform take a look at container that this container listens on port 8080, and that it must be mapped.
3️⃣ – Begin the container, and wait till it is prepared
4️⃣ – Retrieve the container id
5️⃣ – Provides a closeable, that can permit to cease the container when the applying stops
6️⃣ – Offers a map of properties that will probably be use to wire up the applying.

On this pattern you possibly can see that testcontainer permits us to retrieve worth that have been dynamically generated after we began the container, such because the container host or uncovered port.

Quarkus will then do the plumbering auto-magically, in order that your utility is configured to make use of these devservices.

This pattern code has been simplified to hell, the true classe has 170+ traces of code, however that is sufficient to display how straightforward it’s to offer an new devservice for an extension.



Restarting the applying

If I attempt to begin my utility once more I get the next log :

2023-12-22 09:13:46,579 INFO  [org.acm.con.dep.dev.DevServicesProcessor] (build-25) Dev Providers for Acme Env began on http://localhost:49221
2023-12-22 09:13:46,582 INFO  [org.acm.con.dep.dev.DevServicesProcessor] (build-25) Different Quarkus purposes in dev mode will discover the occasion mechanically. For Quarkus purposes in manufacturing mode, you possibly can hook up with this by beginning your utility with -Dacme.atmosphere.url=http://localhost:49221
   ___                                    ___      _   _              
  / _ _ __ ___  ___ _ __   ___ _ __     / __ ___| |_| |_ ___ _ __   
 / /_/ '__/ _ / _  '_  / _  '__|   /__/// _  __| __/ _  '__|  
/ /_| | |  __/  __/ | | |  __/ |     / /    __/ |_| ||  __/ |     
____/|_|  ___|___|_| |_|___|_|     _____/___|__|_____|_|     

   ___         _                  _                                   
  / ___ _ ___| |_ ___ _ __   ___| |_ _ __ ___  _ __   __ _  ___ _ __ 
 / _/ _` / __| __/ _  '__| / __| __| '__/ _ | '_  / _` |/ _  '__|
/ / | (_| __  ||  __/ |    __  |_| | | (_) | | | | (_| |  __/ |   
/   __,_|___/_____|_|    |___/__|_|  ___/|_| |_|__, |___|_|   
                                                      |___/           
                                              Powered by Quarkus 3.6.4
2023-12-22 09:13:47,319 INFO  [io.quarkus] (Quarkus Primary Thread) configuration-provider-picocli-tests 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.6.4) began in 10.341s. 
2023-12-22 09:13:47,320 INFO  [io.quarkus] (Quarkus Primary Thread) Profile dev activated. Reside Coding activated.
2023-12-22 09:13:47,320 INFO  [io.quarkus] (Quarkus Primary Thread) Put in options: [cdi, configuration-provider, picocli]
2023-12-22 09:13:47,398 INFO  [org.acm.con.it.Starter] (Quarkus Primary Thread) ********   WELCOME !     ********
2023-12-22 09:13:47,398 INFO  [org.acm.con.it.Starter] (Quarkus Primary Thread) Welcome j.tama, that can current: "Quarkus: Greener, Higher, Quicker, Stronger"

2023-12-22 09:13:47,398 INFO  [org.acm.con.it.Starter] (Quarkus Primary Thread) *********************************
2023-12-22 09:13:47,404 INFO  [io.quarkus] (Quarkus Primary Thread) configuration-provider-picocli-tests stopped in 0.005s
Enter fullscreen mode

Exit fullscreen mode

Which means each acme.snowcamp.title, acme.snowcam.creator properties have been injected within the Starter command and used.



Sliding down the flawed slope

Seeing how straightforward it was to present purposes new capabilities I made a decision to go additional. In our staff, we’ve somebody whose best battle is that talking about REST API’s is heretic. He taught us how REST cannot be by it’s totally nature an API. So I made a decision to assist him in his struggle, implementing a fault rectifier. I thus added a ThisIsNotRestTransformerProcessor within the deployment module.

As I mentioned, we wish to deal with the Greener and quicker mojo. So in any respect price we wish to hold :

. Small artefacts, that can result in smaller class loader, much less reminiscence consumption and faster begins.
. Purposes that solely do what they really want, so, no ineffective extension dependencies.

To do this I’ll add the quarkus-resteasy-reactive extension to the runtime module with a particular trace :

<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-resteasy-reactive</artifactId>
   <non-obligatory>true</non-obligatory>
</dependency>
Enter fullscreen mode

Exit fullscreen mode

What which means, is that this extension will not be current within the last purposes artefact until explicitly requested by the purposes.



Including/eradicating/modifying annotations

I’ll now add a brand new @BuildStep to the processor, however I need it to be set off, provided that the @ResponseHeader is current at runtime, which means provided that the applying has added the quarkus-resteasy-reactive extension to its dependencies.

To do that I’ll first create a java.util.perform.BooleanSupplier :

public static class ReactiveResteasyEnabled 
   implements BooleanSupplier {

   @Override
   public boolean getAsBoolean() {
       return QuarkusClassLoader.
           isClassPresentAtRuntime( 1️⃣
              "org.jboss.resteasy.reactive.ResponseHeader");
        }
    }
Enter fullscreen mode

Exit fullscreen mode

1️⃣ Discover how Quarkus helps me discover out if a category will probably be current at runtime

All I’ve to do is use it :

@BuildStep(onlyIf = ReactiveResteasyEnabled.class) 1️⃣
public void correctApproximations(
   ApplicationIndexBuildItem applicationIndexBuildItem,
   BuildProducer<AnnotationsTransformerBuildItem> transformers) {
   logger.infof("Correcting your approximations if any. We'll see at runtime !");
   transformers.produce(
       new AnnotationsTransformerBuildItem(
           new RestMethodCorrector()));
   return;
}
Enter fullscreen mode

Exit fullscreen mode

1️⃣ This construct step will solely execute if wanted

The AnnotationsTransformer code is fairly straight ahead :

personal static class RestMethodCorrector 
      implements AnnotationsTransformer {

   public static last DotName RESPONSE_HEADER = 
      DotName.createSimple(
         org.jboss.resteasy.reactive.ResponseHeader.class);

   public static last AnnotationValue HEADER_NAME = 
      AnnotationValue.createStringValue(
         "identify",
         "X-ApproximationCorrector");

   public static last AnnotationValue HEADER_VALUE = 
      AnnotationValue.createStringValue(
         "ignored",
         "It is extra JSON over http actually.");

    public static last AnnotationValue HEADER_VALUES = 
       AnnotationValue.createArrayValue(
          "worth", 
          Checklist.of(HEADER_VALUE));

   @Override
   public boolean appliesTo(AnnotationTarget.Variety type) {
      return AnnotationTarget.Variety.METHOD == type; 1️⃣
   }

   @Override
   public void remodel(
      AnnotationsTransformer.TransformationContext context) {
      MethodInfo technique = context.getTarget().asMethod();
      if (isRestEndpoint.take a look at(technique)) { 2️⃣
         Transformation remodel = context.remodel(); 3️⃣
         remodel.add(RESPONSE_HEADER,HEADER_VALUES); 4️⃣
         remodel.accomplished(); 5️⃣
       }
    }
}
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – Solely applies transformations to technique, as a result of it is what @ResponseHeader targets
2️⃣ – If the given is an enpoint, ie is annotated with one of many following : @GET,@PUT,@POST,@DELETE,@PATCH
3️⃣ – Begins a brand new transformation
4️⃣ – Provides the @ResponseHeader to the tactic with right values
5️⃣ – Ends the transformation

And we’re accomplished !



Testing the newly added header

I’ll now create an different easy utility utilizing:

. io.quarkus:quarkus-resteasy-reactive-jackson
. org.acme:configuration-provider

And create the next enpoint :

package deal org.acme.enpoints;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.eclipse.microprofile.config.inject.ConfigProperty;

@Path("/acme")
public class AcmeResource {

    @ConfigProperty(identify = "env.devoxxFR.title")
    String devoxxFRConfTitle;
    @ConfigProperty(identify = "env.devoxxFR.creator")
    String devoxxFRConfAuth;

    @GET
    public String hellodevoxxFR() {
        return "Welcome %s, that can current: "%s""
                .formatted(
                        devoxxFRConfAuth, 
                        devoxxFRConfTitle);
    }
}
Enter fullscreen mode

Exit fullscreen mode

If I now begins the applying and set off the endpoint with httpie :

> http localhost:8080/acme/foo

HTTP/1.1 200 OK
Content material-Kind: textual content/plain;charset=UTF-8
X-ApproximationCorrector: It's extra JSON over http actually.
content-length: 91

Welcome Malvin le Martien, that can current: "Why does Elmyra Duff love animals a lot ?"
Enter fullscreen mode

Exit fullscreen mode

o/ That is successful ! My endpoint is magically augmented !

That could be a bit to a lot although. I believe I’ll let the developper inform me if he need’s to be strict about this or not.

If it would not (and that would be the default behaviour), I’ll solely log one thing at utility startup. If he needs strictness, we are going to falback to annotation transformation.

I might want to introduce one final function for this.



Recording bytecode for later invocation.

To start with, let’s introduce a brand new property for the compile part: acme.strict.relaxation. Certainly, the extension deployment code is run throughout the compilation part, so if we wish the developpers to have the ability to pilot their behaviour we’d like early configuration. The property will default to false.

I then should slighty modify my construct step:

@BuildStep(onlyIf = ReactiveResteasyEnabled.class)
@File(ExecutionTime.RUNTIME_INIT) 1️⃣
public void correctApproximations(
   AcmeConfigurationBuildTimeConfiguration compileConfiguration, 2️⃣
   ApplicationIndexBuildItem applicationIndexBuildItem,
   BuildProducer<AnnotationsTransformerBuildItem> transformers,
   ThisIsNotRestLogger thisIsNotRestLogger 2️⃣) {

   if (compileConfiguration.strict.isRestStrict) { 3️⃣
      logger.infof("Correcting your approximations if any. We'll see at runtime !");
      transformers.produce(new
        AnnotationsTransformerBuildItem(new
           RestMethodCorrector()));
      return;
    }
    Stream<MethodInfo> restEndpoints = applicationIndexBuildItem
       .getIndex()
       .getKnownClasses()
       .stream()
       .flatMap(
         classInfo -> classInfo.strategies().stream())
       .filter(isRestEndpoint);
    thisIsNotRestLogger.youAreNotDoingREST(restEndpoints
                .map(this::getMessage)
                .toList()); 4️⃣
}

personal String getMessage(MethodInfo methodInfo) {
   return 
      "You suppose you technique "%s#%s" is doing relaxation however it's extra JSON over HTTP truly."
      .formatted(
         methodInfo.declaringClass().toString(),
         methodInfo.toString());
}
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – Tells Quarkus this @BuildStep is doing byte code recording
2️⃣ – Injects configuration and recorder
3️⃣ – Add annotations provided that in strict mode
4️⃣ – Else invoke recorder with checklist of messages

And the recorder is a classical class :

package deal org.acme.configurationProvider.runtime;

import io.quarkus.runtime.annotations.Recorder;
import org.jboss.logging.Logger;

import java.util.Checklist;

@Recorder 1️⃣
public class ThisIsNotRestLogger {

    personal static last Logger logger = Logger.getLogger(ThisIsNotRestLogger.class);

    public void youAreNotDoingREST(Checklist<String> warnings) {
        logger.errorf("%s******** It's best to Pay attention *********%spercentspercentspercents",
                System.lineSeparator(),
                System.lineSeparator(),
                String.be a part of(System.lineSeparator(), warnings),
                System.lineSeparator(),
                "If I had been stricter I'd have modified your code...");
    }

}
Enter fullscreen mode

Exit fullscreen mode

1️⃣ – Hey Quarkus, I am a recorder !

Discover regardless that this technique is invoked throughout construct time, it is going to be invoked every time the applying begins :

   ___                                    ___      _   _              
  / _ _ __ ___  ___ _ __   ___ _ __     / __ ___| |_| |_ ___ _ __   
 / /_/ '__/ _ / _  '_  / _  '__|   /__/// _  __| __/ _  '__|  
/ /_| | |  __/  __/ | | |  __/ |     / /    __/ |_| ||  __/ |     
____/|_|  ___|___|_| |_|___|_|     _____/___|__|_____|_|     

   ___         _                  _                                   
  / ___ _ ___| |_ ___ _ __   ___| |_ _ __ ___  _ __   __ _  ___ _ __ 
 / _/ _` / __| __/ _  '__| / __| __| '__/ _ | '_  / _` |/ _  '__|
/ / | (_| __  ||  __/ |    __  |_| | | (_) | | | | (_| |  __/ |   
/   __,_|___/_____|_|    |___/__|_|  ___/|_| |_|__, |___|_|   
                                                      |___/           
                                              Powered by Quarkus 3.6.4
2023-12-22 11:16:06,281 ERROR [org.acm.con.run.ThisIsNotRestLogger] (Quarkus Primary Thread) 
******** It's best to Pay attention *********
You suppose you technique "org.acme.configurationProvider.it.AcmeResource#java.lang.String hellodevoxxFR(java.lang.String occasion)" is doing relaxation however it's extra JSON over HTTP truly.
You suppose you technique "org.acme.configurationProvider.it.CustomResourceUtils#java.lang.String good day()" is doing relaxation however it's extra JSON over HTTP truly.
If I had been stricter I'd have modified your code... [Error Occurred After Shutdown]
Enter fullscreen mode

Exit fullscreen mode

If I now retrigger my endpoint, ,I get the next end result :

http localhost:8080/acme/foo
HTTP/1.1 200 OK
Content material-Kind: textual content/plain;charset=UTF-8
content-length: 91

Welcome Malvin le Martien, that can current: "Why does Elmyra Duff love animals a lot ?"
Enter fullscreen mode

Exit fullscreen mode

The added header is now not right here.



Documenting

Remembder once I confirmed you the @asciidoclet tag in the javadoc ?

Nicely scaffolding an extension additionally generates a docs module wich leverages Antora, and with a minimal effort, we will produce a nice and clean documentation.

All of the configuration documentation has been mechanically generated from the javadoc



Conclusion

I’ve solely scratch the floor right here, however I hope to have ease your path in writing an extension.

Please keep in mind that extension maintainers are to be tremendously accountable for retaining issues small and quick.

Joyful coding !



The supply code

All of the sources (and a bit extra) I’ve proven on this article might be discovered within the following repository. Please be happy to clone/fork it and play with it !

Version

Welcome to Quarkiverse!

Congratulations and thanks for creating a brand new Quarkus extension undertaking in Quarkiverse!

Be at liberty to switch this content material with the right description of your new undertaking and needed directions easy methods to use and contribute to it.

You will discover the fundamental information, Quarkiverse insurance policies and conventions in the Quarkiverse wiki.

In case you’re making a Quarkus extension undertaking for the primary time, please observe Building My First Extension information.

Different helpful articles associated to Quarkus extension improvement might be discovered below the Writing Extensions information class on the Quarkus.io web site.

Thanks once more, good luck and have enjoyable!

Documentation

The documentation for this extension needs to be maintained as a part of this repository and it’s saved within the docs/ listing.

The structure ought to observe the Antora’s Standard File and Directory Set.

As soon as the docs are able to be revealed, please open…

. You will discover there the completed extension, it is integration exams, and the acme centralized tech’ convention referential.



The Article was Inspired from tech community site.
Contact us if this is inspired from your article and we will give you credit for it for serving the community.

This Banner is For Sale !!
Get your ad here for a week in 20$ only and get upto 10k Tech related traffic daily !!!

Leave a Reply

Your email address will not be published. Required fields are marked *

Want to Contribute to us or want to have 15k+ Audience read your Article ? Or Just want to make a strong Backlink?