Migration from @Stateless (BCE) to Quarkus

A typical BCE Jakarta EE application comprises a JAX-RS resource:


import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
    
@Path("ping")
public class MessageResource {

    @Inject
    MessageFetcher messageFetcher;

    @GET
    public String ping() {
        return "hello, " + this.messageFetcher.getMessage();
    }

}
and a corresponding implementation in the boundary package:

package com.airhacks.ping.boundary;
import com.airhacks.ping.control.MessageConfigurator;
import javax.ejb.Stateless;
import javax.inject.Inject;

@Stateless
public class MessageFetcher {

    @Inject
    MessageConfigurator configurator;

    public String getMessage() {
        return this.configurator.message();
    }

}

The boundary acts as a facade and usually coordinates multiple controls:


package com.airhacks.ping.control;

import javax.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;

public class MessageConfigurator {

    @Inject
    @ConfigProperty(name = "message")
    String message;

    public String message() {
        return this.message + " generated at: " + System.currentTimeMillis();
    }
}    

To run the code on quarkus you will have to replace @Stateless with @Transactional and @RequestScoped, or a stereotype which combines both:


@Stereotype
@Transactional
@RequestScoped
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Boundary {}    

Now the MessageFetcher looks like:


@Boundary
public class MessageFetcher {    }    

All controls have to annotated to be injectable on quarkus. A @Dependent (default) scope could be used for that purpose, or the following stereotype:


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Stereotype;

@Stereotype
@Dependent
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Control {}

The MessageConfigurator control has to be annotated with the @Control stereotype and looks like:


@Control    
public class MessageConfigurator { }

Both stereotype are used in the Web Push gateway: gatelink.

February / March 2020 Java and Web Events

  1. Cloud Native Patterns und Approaches mit Jakarta EE + MicroProfile #lowslides #cloudful
    JUG Oberpfalz OTH Weiden 2020-02-19
  2. Microprofile Productivity with Quarkus
    JUG BMW MUC 2020-02-20
  3. Kickass Web Components with a bit of Quarkus
    Free Meetup Mayflower MUC 2020-03-10
  4. Keynote: What Should Happen in 2020 with Java and Web
    Voxxed Days Bucharest Sheraton Hotel Bucharest 2020-03-13
  5. Session: 2020 Predictions Interactive On-Stage Hacking #slideless #nomigrations
    Voxxed Days Bucharest Sheraton Hotel Bucharest 2020-03-13
  6. From Java Developer to Web Guru in 1 hour - No slides
    JUG Session Google MUC Munich 2020-03-20
  7. MicroProfile with Quarkus
    Airhacks Workshops Airport MUC 2020-03-24
  8. Micro Frontends with Web Components
    Airhacks Workshops Airport MUC 2020-03-25
  9. Jakarta EE + MicroProfile + Kubernetes = The Productivity Dream #slideless
    Kubecon Cloud Native for Java (CN4J) RAI Amsterdam 2020-03-30

Paths "Subtraction" with Path#relativize

The method relativize computes the difference between an absolute path (src/main/java/com/airhacks) and it's root (src/main/java). This is useful for subtraction of a common path prefix:


import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Test;

public class PathSubstractionTest {

    @Test
    public void splitWithDot() {
        Path fromProjectRoot = Paths.get("src/main/java/com/airhacks");
        Path projectRoot = Paths.get("src/main/java");
        Path substracted = projectRoot.relativize(fromProjectRoot);
        String actual = substracted.toString();
        String expected = "com/airhacks";
        assertThat(actual, is(expected));
    }
}

String#split with a "dot"

String#split with a dot "." does return an empty array:


    String packages[] = "com.airhacks".split(".");
    assertThat(packages.length, is(0));

The split method parameter is a regular expression, and "dot" is Any character (may or may not match line terminators)

Escaping the dot solves the "problem":


    String packages[] = "com.airhacks".split("\\.");
    assertThat(packages.length, is(2));

2020 Predictions, Quarkus, Structuring Services, Transactions, DTOs--71st airhacks.tv

The 71st airhacks.tv episode is covering:

2020 predictions, missing JPA / JAX-RS features discussion, blobs in DB, the relation between JTA and DB transactions (also checkout airhacks.fm podcast discussion about transactions: "From PHP to Transactions"), dependencies and licensing, nashorn deprecation and GraalVM, Boundary Control Entity structure discussion, DTOs, JSON-B, JSON-P missing Quarkus features, classic Java EE vs. Quarkus, Quarkus extensions vs. dependencies
Any questions left? Ask now: https://gist.github.com/AdamBien/40fa453cb15b2e897024294a7fc3623a and get the answers at the next airhacks.tv.

WebApps Without Frameworks--A W-JAX 2019 Session

Building a simplistic application with Web Components, ES6+ (modules), lit-html and integrating a 3rd party custom element (UI5 DatePicker Web Component) with rollup.js but without frameworks and in 1h, from scratch [in German]:

Blackbox System Tests with Quarkus and MicroProfile REST Client

To System Test test a JAX-RS service as a blackbox:


@Path("/hello")
public class HelloResource {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello";
    }
}    

A dedicated quarkus project with installed MicroProfile REST Client extension (quarkus-rest-client) can be used as a testbed.

A proxy interface:


import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(baseUri = "http://localhost:8080")
public interface HelloResource {

    @GET
    @Path("hello")
    @Produces(MediaType.TEXT_PLAIN)
    String content();    
}    

is injectable directly into the system test:


import static org.junit.jupiter.api.Assertions.assertEquals;
import javax.inject.Inject;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class HelloResourceTest {

    @Inject
    @RestClient
    HelloResource resource;

    @Test
    public void hello() {
        String content = resource.content();
        System.out.println(content);
        assertEquals(content,"hello");
    }
    
}    

See it live and from scratch:

2020 predictions, JPA, JAX-RS, Blobs, JTA and DBs, DTO, JSON-P, JSON-B, Licensing -- the 71st airhacks.tv

Topics for the 71th airhacks.tv episode (first Monday of the month, 8pm CET):

  1. 2020 Predictions
  2. New JPA and JAX-RS features
  3. Binary files and DBs
  4. JTA transactions and DBs
  5. DTO, JSON-P and JSON-B
  6. 3rd party dependencies and licensing (xplr?)
  7. sheetFIT release

Any questions left? Ask now: https://gist.github.com/AdamBien/76c4af6d6e59d2632bb265fee112bb02 and get the answers at the next airhacks.tv.

The show is going to be streamed live: https://vimeo.com/event/19368

Online Workshops
realworldpatterns.com
...the last 150 posts
...the last 10 comments
License