Why Custom Extensions? Because We Can!

Let's face it: off-the-shelf solutions don't always cut it. Sometimes, you need to roll up your sleeves and build something tailor-made. That's where custom Quarkus extensions come in. They're like the secret sauce that makes your application uniquely powerful.

"With great power comes great responsibility" – Uncle Ben (and every Quarkus developer ever)

The Ingredients for Our Extension Potion

Before we dive in, let's gather our tools:

  • A dash of creativity (don't worry, we've got plenty)
  • Quarkus (obviously)
  • Jakarta EE (our trusty sidekick)
  • A sprinkle of patience (trust me, you'll need it)

Step 1: Conceptualize Your Extension

First things first – what do you want your extension to do? For this tutorial, let's create something fun and useful: a "RandomQuoteGenerator" extension. Because who doesn't need a dose of wisdom (or silliness) in their code?

Step 2: Setting Up the Project

Time to get our hands dirty. Fire up your terminal and let's create a new Quarkus extension project:

mvn io.quarkus:quarkus-maven-plugin:create-extension -DextensionId=io.mycompany:quarkus-random-quote-generator
Bash

This command creates a basic structure for our extension. It's like the foundation of a house – not very exciting yet, but essential.

Step 3: Implementing the Core Functionality

Now, let's add some meat to the bones. We'll create a RandomQuoteGenerator class that does the heavy lifting:

package io.mycompany.quarkus.random.quote.generator;

import jakarta.enterprise.context.ApplicationScoped;
import java.util.List;
import java.util.Random;

@ApplicationScoped
public class RandomQuoteGenerator {
    private static final List<String> QUOTES = List.of(
        "I'm not a great programmer; I'm just a good programmer with great habits." - Kent Beck,
        "Talk is cheap. Show me the code." - Linus Torvalds,
        "Programming isn't about what you know; it's about what you can figure out." - Chris Pine
    );

    private final Random random = new Random();

    public String getRandomQuote() {
        return QUOTES.get(random.nextInt(QUOTES.size()));
    }
}
Java

Look at that beautiful Jakarta CDI annotation (@ApplicationScoped). It's like we're giving our class superpowers!

Step 4: Creating the Runtime Module

Next, we need to set up the runtime module. This is where the magic happens when someone actually uses our extension:

package io.mycompany.quarkus.random.quote.generator.runtime;

import io.mycompany.quarkus.random.quote.generator.RandomQuoteGenerator;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.runtime.annotations.Recorder;

@Recorder
public class RandomQuoteGeneratorRecorder {
    public void initialize(BeanContainer container) {
        container.instance(RandomQuoteGenerator.class).getRandomQuote();
    }
}
Java

This recorder class is like the backstage crew of a theater – it sets everything up behind the scenes.

Step 5: Deployment Module - Where the Pieces Come Together

Now, let's create the deployment module. This is where we tell Quarkus how to integrate our extension:

package io.mycompany.quarkus.random.quote.generator.deployment;

import io.mycompany.quarkus.random.quote.generator.RandomQuoteGenerator;
import io.mycompany.quarkus.random.quote.generator.runtime.RandomQuoteGeneratorRecorder;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.FeatureBuildItem;

class RandomQuoteGeneratorProcessor {

    private static final String FEATURE = "random-quote-generator";

    @BuildStep
    FeatureBuildItem feature() {
        return new FeatureBuildItem(FEATURE);
    }

    @BuildStep
    AdditionalBeanBuildItem registerBean() {
        return AdditionalBeanBuildItem.unremovableOf(RandomQuoteGenerator.class);
    }

    @BuildStep
    @Record(ExecutionTime.RUNTIME_INIT)
    void initialize(RandomQuoteGeneratorRecorder recorder) {
        recorder.initialize();
    }
}
Java

This processor is like the conductor of an orchestra, making sure all parts of our extension play together harmoniously.

Step 6: Configuration

Every good extension needs some configuration options. Let's add a way to customize our quotes:

package io.mycompany.quarkus.random.quote.generator.runtime;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;

@ConfigRoot(name = "random-quote", phase = ConfigPhase.RUN_TIME)
public class RandomQuoteConfig {

    /**
     * Custom quotes to add to the generator
     */
    @ConfigItem(name = "custom-quotes")
    public Optional<List<String>> customQuotes;
}
Java

Now users can add their own quotes. It's like giving them a paintbrush to add their own colors to our masterpiece!

Step 7: Testing - Because We're Professionals

No extension is complete without tests. Let's write a simple test to make sure our generator works:

package io.mycompany.quarkus.random.quote.generator;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import jakarta.inject.Inject;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@QuarkusTest
public class RandomQuoteGeneratorTest {

    @Inject
    RandomQuoteGenerator generator;

    @Test
    public void testRandomQuoteGeneration() {
        String quote = generator.getRandomQuote();
        assertNotNull(quote);
        System.out.println("Generated quote: " + quote);
    }
}
Java

Running tests is like giving your code a health check-up. Better safe than sorry!

Step 8: Documentation - Because We're Nice

Last but not least, let's write some documentation. Create a README.md file in your project root:

# Quarkus Random Quote Generator Extension

This extension adds a random quote generator to your Quarkus application.

## Usage

1. Add the extension to your project:

```xml
<dependency>
    <groupId>io.mycompany</groupId>
    <artifactId>quarkus-random-quote-generator</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>
```

2. Inject and use the generator in your code:

```java
@Inject
RandomQuoteGenerator generator;

public void printRandomQuote() {
    System.out.println(generator.getRandomQuote());
}
```

3. Customize quotes in your application.properties:

```properties
quarkus.random-quote.custom-quotes=May the source be with you,I code, therefore I am
```
Markdown

Good documentation is like a well-commented code – it makes everyone's life easier.

The Grand Finale: Publishing Your Extension

You've done it! Your extension is ready to face the world. To publish it:

  1. Push your code to GitHub
  2. Set up CI/CD (GitHub Actions are your friend)
  3. Publish to Maven Central (because sharing is caring)

Wrapping Up

And there you have it – your very own Quarkus extension, from idea to production-ready solution. It's like you've just added a new spell to the Quarkus spellbook. Remember, with great power comes... well, you know the rest.

Now go forth and extend Quarkus to your heart's content. Who knows? Your extension might just be the next big thing in the Quarkus ecosystem. Happy coding, and may your builds always be successful!

"The best code is no code at all." - Jeff Atwood (but we'll make an exception for awesome Quarkus extensions)