• Latest
Native-image With Quarkus – DZone Java

Native-image With Quarkus – DZone Java

December 13, 2021
Remembering DC Comics’ Canceled Lobo Game

Remembering DC Comics’ Canceled Lobo Game

May 24, 2022
Java Outsourcing, a Strong Business, and Management Approaches

Java Outsourcing, a Strong Business, and Management Approaches

May 24, 2022
Sonic The Hedgehog 2 Hits Paramount Plus Tomorrow

Sonic The Hedgehog 2 Hits Paramount Plus Tomorrow

May 24, 2022
Apple ‘ungodly well-managed’ says Billionaire investor- 9to5Mac

Apple to open retail in New Jersey, first store in almost a year in the US

May 24, 2022
We’re Really Hoping Team Ladybug’s New Shmup ‘DRANIUS’ Comes To Switch

We’re Really Hoping Team Ladybug’s New Shmup ‘DRANIUS’ Comes To Switch

May 24, 2022
AT&T Customers Can Now Stream Remedy’s Control For Free

AT&T Customers Can Now Stream Remedy’s Control For Free

May 24, 2022
vivo announces Y55s 5G with its biggest battery ever

vivo delays T2 launch but leaks all of its specs, Y72t debuts

May 24, 2022
These Street Fighter Versus Teenage Mutant Ninja Turtles Action Figure Sets Look Amazing

These Street Fighter Versus Teenage Mutant Ninja Turtles Action Figure Sets Look Amazing

May 24, 2022
Sniper Elite 5 achievements once again take aim at Hitler’s balls

Sniper Elite 5 achievements once again take aim at Hitler’s balls

May 23, 2022
Looney Tunes Expansion Racing To Hot Wheels Unleashed This July

Looney Tunes Expansion Racing To Hot Wheels Unleashed This July

May 23, 2022
Another Palworld Trailer Is Out And We’re Still Confused About How The Pokemon Company Isn’t Mad

Another Palworld Trailer Is Out And We’re Still Confused About How The Pokemon Company Isn’t Mad

May 23, 2022
Salesforce CRM Integration Methods to Know

Salesforce CRM Integration Methods to Know

May 23, 2022
Advertise with us
Tuesday, May 24, 2022
Bookmarks
  • Login
  • Register
GetUpdated
  • Home
  • Game Updates
    • Mobile Gaming
    • Playstation News
    • Xbox News
    • Switch News
    • MMORPG
    • Game News
    • IGN
    • Retro Gaming
  • Tech News
    • Apple Updates
    • Jailbreak News
    • Mobile News
  • Software Development
  • Photography
  • Contact
    • Advertise With Us
    • About
No Result
View All Result
GetUpdated
No Result
View All Result
GetUpdated
No Result
View All Result
ADVERTISEMENT

Native-image With Quarkus – DZone Java

December 13, 2021
in Software Development
Reading Time:11 mins read
0 0
0
Share on FacebookShare on WhatsAppShare on Twitter


So far, we have looked at how well Spring Boot and Micronaut integrate GraalVM native image extension. In this post, I’ll focus on Quarkus:

A Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM, crafted from the best of breed Java libraries and standards.

Creating a New Project

Just as Spring Boot and Micronaut, Quarkus provides options to create new projects:

  1. A dedicated quarkusCLI
  2. A Web UI

Quarkus new project

Quarkus offers a definite improvement over its competitors. Every dependency has a detailed contextual menu that allows:

  • Copying the command to add the dependency via quarkus
  • Copying the command to add the dependency via Maven
  • Copying the Maven POM dependency snippet
  • Copying the Maven BOM dependency snippet
  • Copying the Maven BOM dependency snippet
  • Opening the related dependency’s guide

Note that the menu displays Gradle-related commands instead if you choose Gradle as the build tool.

3. A Maven plugin: I like that no external dependencies are necessary beyond one’s build tool of choice.

Bean Configuration

Quarkus relies on JSR 330. However, it deviates from the specification: it lists both limitations and non-standard features.

For example, with Quarkus, you can skip the @Produces annotation on a producer method if it’s already annotated with one of the scope annotations, e.g., @Singleton. Here’s the code to create the message digest:

class MarvelFactory {

    @Singleton
    fun digest(): MessageDigest = MessageDigest.getInstance("MD5")
}

Controller Configuration

A lot of Quarkus relies on Jakarta EE specifications. As such, the most straightforward path to creating controllers is JAX-RS. We can create a “controller” with the following code:

@Path("https://dzone.com/")
class MarvelController {

    @GET
    fun characters() = Response.accepted()
}

Because the developers of Quarkus also worked on Vert.x, the former also offers a plugin that integrates the latter. Vert.x is fully reactive and provides the concept of routes. With Quarkus, you can annotate methods to mark them as routes. One can migrate the above code to routes:

@Singleton
class MarvelController {

     @Routes
     fun characters() = Response.accepted()
}

Alternatively, one can prefer programmatic route registration:

@Singleton
class MarvelRoutes {

    fun get(@Observes router: Router) {       // 1
        router.get("https://dzone.com/").handler {
            it.response()
                .setStatusCode(200)
                .send()                       // 2
        }
    }
}

  1. Observe the Router “event”: it’s fired once at startup time
  2. Send the empty response; return a Future

Note that the programmatic way requires as many annotations as the annotation way in this particular case. However, the former requires two annotations, while the latter requires one per route plus one.

Non-blocking HTTP Client

Micronaut integrates with many HTTP client flavors via plugins. In this project, I chose to use Mutiny.

There are other reactive programming libraries out there. In the Java world, we can mention Project Reactor and Rx Java.

So, what makes Mutiny different from these two well-known libraries? The API!

As said above, asynchronous is hard to grasp for most developers, and for good reasons. Thus, the API must not require advanced knowledge or add cognitive overload. It should help you design your logic and still be intelligible in 6 months.

— https://smallrye.io/smallrye-mutiny/pages/philosophy#what-makes-mutiny-different

Here’s a glimpse into a subset of the Mutiny API:

Subset of the Mutiny API

At first, I was not fond of Mutiny. I mean, we already have enough reactive clients: Project Reactor, RxJava2, etc.

Then, I realized the uniqueness of its approach. Reactive programming is pretty tricky because of all available options. But Mutiny is designed around a fluent API that leverages the type system to narrow down compatible options at compile-time. It gently helps you write the result you want, even with a passing API knowledge.

I’m now convinced to leave it a chance. Let’s use Mutiny to make a request:

val client = WebClient.create(vertx)                                  // 1
client.getAbs("https://gateway.marvel.com:443/v1/public/characters")  // 2
      .send()                                                         // 3
      .onItem()                                                       // 4
      .transform { it.bodyAsString() }                                // 5
      .await()                                                        // 6
      .indefinitely()                                                 // 7

  1. Create the client by wrapping a Vertx instance. Quarkus provides one and can inject it for you
  2. Create a new instance of a GET HTTP request
  3. Send the request asynchronously. Nothing has happened at this point yet
  4. When it receives the response, transform its body to a String
  5. Wait… forever, until it gets the response

To get parameters from the coming request and forward them is straightforward with the routing context:

router.get("https://dzone.com/").handler { rc ->
    client.getAbs("https://gateway.marvel.com:443/v1/public/characters")
        .queryParamsWith(rc.request())
        .send()
        .onItem()
        .transform { it.bodyAsString()) }
        .await()
        .indefinitely()

fun HttpRequest<Buffer>.queryParamsWith(request: HttpServerRequest) =
    apply {
        arrayOf("limit", "offset", "orderBy").forEach { param ->
            request.getParam(param)?.let {
                addQueryParam(param, it)
            }
        }
    }

Parameterization

Like Spring Boot and Micronaut, Quarkus allows parameterizing one’s application in multiple ways:

  • System properties
  • Environment variables
  • .env file in the current working directory
  • Configuration file in $PWD/config/application.properties
  • Configuration file application.properties in classpath
  • Configuration file META-INF/microprofile-config.properties in classpath

Note that it’s not possible to use command-line parameters for parameterization.

Unlike its siblings, the web client requires you to split the URL into three components, host, port, and whether to use SSL.

app.marvel.server.ssl=true
app.marvel.server.host=gateway.marvel.com
app.marvel.server.port=443

Because of this, we need to be a bit creative regarding the configuration classes:

@Singleton                                                                    // 1
data class ServerProperties(
    @ConfigProperty(name = "app.marvel.server.ssl") val ssl: Boolean,         // 2
    @ConfigProperty(name = "app.marvel.server.host") val host: String,        // 2
    @ConfigProperty(name = "app.marvel.server.port") val port: Int            // 2
)

@Singleton                                                                    // 1
data class MarvelProperties(
    val server: ServerProperties,                                             // 3
    @ConfigProperty(name = "app.marvel.apiKey") val apiKey: String,           // 2
    @ConfigProperty(name = "app.marvel.privateKey") val privateKey: String    // 2
)

  1. Configuration classes are regular CDI beans.
  2. Quarkus uses the Microprofile Configuration specification. @ConfigProperty sets the property key to read from. It’s unwieldy to repeat the same prefix on all keys. Thus, Microprofile offers the @ConfigProperties to set the prefix on the class. However, such a class needs a zero-arg constructor, which doesn’t work with Kotlin’s data classes.
  3. Inject the other config class and benefit from a nested structure

Testing

Like its siblings, Quarkus offers its dedicated annotation for tests, @QuarkusTest. It also provides @NativeImageTest, which allows running the test in a native-image context. The idea is to define your JVM test in a class annotated with the former and create a subclass annotated with the latter. This way, the test will run both in a JVM context and a native one. Note that I’m not sure it worked in my setup.

But IMHO, the added value of Quarkus in a testing context lies in how it defines a reusable resource abstraction.

Quarkus test resource

With only one interface and one annotation, one can define a resource, e.g., a mock server, start it before tests and stop it after. Let’s do that:

class MockServerResource : QuarkusTestResourceLifecycleManager {

    private val mockServer = MockServerContainer(
        DockerImageName.parse("mockserver/mockserver")
    )

    override fun start(): Map<String, String> {
        mockServer.start()
        val mockServerClient = MockServerClient(
            mockServer.containerIpAddress,
            mockServer.serverPort
        )
        val sample = this::class.java.classLoader.getResource("sample.json")
                                                ?.readText()
        mockServerClient.`when`(
            HttpRequest.request()
                .withMethod("GET")
                .withPath("/v1/public/characters")
        ).respond(
            HttpResponse()
                .withStatusCode(200)
                .withHeader("Content-Type", "application/json")
                .withBody(sample)
        )
        return mapOf(
            "app.marvel.server.ssl" to "false",
            "app.marvel.server.host" to mockServer.containerIpAddress,
            "app.marvel.server.port" to mockServer.serverPort.toString()
        )
    }

    override fun stop() = mockServer.stop()
}

Now, we can use this server inside our test:

@QuarkusTest
@QuarkusTestResource(MockServerResource::class)
class QuarkusApplicationTest {

    @Test
    fun `should deserialize JSON payload from server and serialize it back again`() {
        val model = given()                                             // 1
            .`when`()
            .get("https://dzone.com/")
            .then()
            .statusCode(200)
            .contentType(ContentType.JSON)
            .and()
            .extract()
            .`as`(Model::class.java)
        assertNotNull(model)
        assertNotNull(model.data)
        assertEquals(1, model.data.count)
        assertEquals("Anita Blake", model.data.results.first().name)
    }
}

  1. Quarkus integrates the RestAssured API. It uses some of Kotlin’s keywords, so we need to escape them with back-ticks.

I like how it decouples the test from its dependencies.

Docker and GraalVM Integration

When one scaffolds a new project, Quarkus creates different ready-to-use Dockerfile:

  • A legacy JAR
  • A layered JAR approach: dependencies are added to the image first so that if any of them changes, the build reuses their layer
  • A native image
  • A native image with a distroless parent

The good thing is that one can configure any of these templates to suit one’s needs. The downside is that it requires a local Docker install. Moreover, templates are just templates – you can change them entirely.

If you don’t like this approach, Quarkus provides an integration point with Jib. In the rest of this section, we will keep using Docker files.

To create a GraalVM native binary, one uses the following command:

./mvnw package -Pnative -Dquarkus.native.container-build=true

You can find the resulting native executable in the target folder.

To wrap it in a Docker container, use:

docker build -f src/main/docker/Dockerfile.native -t native-quarkus .

Note that the Docker container would fail to start if you ran the first command on a non-Linux platform. To fix this issue, one needs to add an option:

./mvnw package -Pnative -Dquarkus.native.container-build=true 
                        -Dquarkus.container-image.build=true

quarkus.container-image.build=true instructs Quarkus to create a container-image using the final application artifact (which is the native executable in this case).

— https://quarkus.io/guides/building-native-image#using-the-container-image-extensions

For a smaller image, we can use the distroless distribution.

The result is the following:

REPOSITORY                 TAG       IMAGE ID         CREATED         SIZE
native-quarkus-distroless  latest    7a13aef3bcd2     2 hours ago     67.9MB
native-quarkus             latest    6aba7346d987     2 hours ago     148MB

Let’s dive:

┃ ● Layers ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cmp   Size  Command
    2.4 MB  FROM 58f4b2390f4a511                                       // 1
     18 MB  bazel build ...                                            // 2
    2.3 MB  bazel build ...                                            // 2
    113 kB  #(nop) COPY file:b8552793e0627404932d516d478842f7f9d5d5926 // 3
     45 MB  COPY target/*-runner /application # buildkit               // 4

  1. Parent distroless image
  2. Add system libraries, obviously via the Bazel build system
  3. One more system library
  4. Our native executable

We can now run the container:

docker run -it -p8080:8080 native-quarkus-distroless

And the following URLs work as expected:

curl localhost:8080
curl 'localhost:8080?limit=1'
curl 'localhost:8080?limit=1&offset=50'

Conclusion

Quarkus brings an exciting take to the table. Unlike Micronaut, it doesn’t generate additional bytecode during each compilation. The extra code is only generated when one generates the native image via the Maven command. Moreover, relying on Dockerfiles allows you to configure them to your heart’s content if you happen to have a Docker daemon available.

However, the Kotlin integration is lacking. You have to downgrade your model representation to allow Quarkus to hydrate your data classes, moving from val to var and setting default values. Additionally, one needs to set Jackson annotations on each field. Finally, configuration properties don’t work well with data classes.

As with Micronaut, if Kotlin is a must-have for you, then you’d better choose Spring Boot over Quarkus. Otherwise, give Quarkus a try.

The complete source code for this post can be found on Github in Maven format.



Source link

ShareSendTweet
Previous Post

POCO F3 in New Moonlight Silver Color!? 😱💥🤯#pocof3 #shorts #tech

Next Post

Rick Ross – Warm Words in a Cold World (feat. Wale & Future) (Instrumental)

Related Posts

Java Outsourcing, a Strong Business, and Management Approaches

May 24, 2022
0
0
Java Outsourcing, a Strong Business, and Management Approaches
Software Development

Notably, outsourcing has made it possible for corporate entities all around the globe to continue existing. From information technology outsourcing...

Read more

Salesforce CRM Integration Methods to Know

May 23, 2022
0
0
Salesforce CRM Integration Methods to Know
Software Development

Salesforce users require seamless data exchange from external sources to make fast and insightful business decisions. This requires merging data...

Read more
Next Post
Rick Ross – Warm Words in a Cold World (feat. Wale & Future) (Instrumental)

Rick Ross - Warm Words in a Cold World (feat. Wale & Future) (Instrumental)

Leave a Reply Cancel reply

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

© 2021 GetUpdated – MW.

  • About
  • Advertise
  • Privacy & Policy
  • Terms & Conditions
  • Contact

No Result
View All Result
  • Home
  • Game Updates
    • Mobile Gaming
    • Playstation News
    • Xbox News
    • Switch News
    • MMORPG
    • Game News
    • IGN
    • Retro Gaming
  • Tech News
    • Apple Updates
    • Jailbreak News
    • Mobile News
  • Software Development
  • Photography
  • Contact
    • Advertise With Us
    • About

Welcome Back!

Login to your account below

Forgotten Password? Sign Up

Create New Account!

Fill the forms bellow to register

All fields are required. Log In

Retrieve your password

Please enter your username or email address to reset your password.

Log In
Are you sure want to unlock this post?
Unlock left : 0
Are you sure want to cancel subscription?