August 30, 2018

Micronaut Mastery: Use Micronaut Beans In Spring Applications

We can add Micronaut beans to the application context of a Spring application. Micronaut has a MicronautBeanProcessor class that we need to register as Spring bean in the Spring application context. We can define which Micronaut bean types need to be added to the Spring application context via the constructor of the MicronautBeanProcessor class. This way we can use Micronaut from inside a Spring application. For example we can use the declarative HTTP client of Micronaut in our Spring applications.

First we need to add dependencies on Micronaut to our Spring application. In this example we will use the Micronaut HTTP client in our Spring application and use Gradle as build tool. We must add the following dependencies:

// File: build.gradle
...
dependencyManagement {
    imports {
        mavenBom 'io.micronaut:bom:1.0.0.M4'
    }
}
...
dependencies {
    ...
    annotationProcessor "io.micronaut:inject-java"
    compile "io.micronaut:http-client"
    compile "io.micronaut:spring"
    ...
}
...

Next we register a MicronautBeanProcessor bean in the Spring application context. We specify in the constructor that Micronaut beans annotated with @Client must be added to the Spring application context:

// File: src/main/java/mrhaki/micronaut/SampleApplication.java
package mrhaki.micronaut;

import io.micronaut.http.client.Client;
import io.micronaut.spring.beans.MicronautBeanProcessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class SampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

    @Bean
    public MicronautBeanProcessor httpClientMicronautBeanProcessor() {
        // Register beans with @Client annotation.
        // We could for example also use @Singleton
        // and others, because the constructor has
        // a variable number of arguments.
        return new MicronautBeanProcessor(Client.class);
    }

}

We add the source for our Micronaut declarative HTTP client, where we access httpbin.org as a remote webservice:

// File: src/main/java/mrhaki/micronaut/HttpBinClient.java
package mrhaki.micronaut;

import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.client.Client;

@Client("http://httpbin.org")
interface HttpBinClient {
    
    @Get("/uuid")
    ResponseUuidData uuid();
    
    @Post("/anything")
    ResponseData data(String message);
    
}

Inside a Spring controller we use the client as Spring bean:

// File: src/main/java/mrhaki/micronaut/HttpBinController.java
package mrhaki.micronaut;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;

@RestController
@RequestMapping("/sample")
public class HttpBinController {

    private final HttpBinClient client;

    // Inject Micronaut HTTP client via implicit
    // constructor injection.
    public HttpBinController(final HttpBinClient client) {
        this.client = client;
    }

    @GetMapping(value = "/uuid", produces = TEXT_PLAIN_VALUE)
    Mono<String> uuid() {
        return Mono.fromCallable(() -> client.uuid().getUuid().toString());
    }

    @GetMapping(value = "/data")
    Mono<ResponseData.MessageResponseData> data() {
        return Mono.fromCallable(() -> client.data("Micronaut rocks").getJson());
    }

}

Finally we have some POJO classes with the results from the remote web service calls:

// File: src/main/java/mrhaki/micronaut/ResponseUuidData.java
package mrhaki.micronaut;

import java.util.UUID;

public class ResponseUuidData {
    private UUID uuid;
    public UUID getUuid() { return uuid; }
    public void setUuid(final UUID uuid) { this.uuid = uuid; }
}
// File: src/main/java/mrhaki/micronaut/ResponseData.java
package mrhaki.micronaut;

public class ResponseData {
    private MessageResponseData json;
    public MessageResponseData getJson() { return json; }
    public void setJson(final MessageResponseData json) { this.json = json; }
    
    static class MessageResponseData {
        private String message;
        public String getMessage() { return message; }
        public void setMessage(final String message) { this.message = message; }
    }
}

It is time to start our Spring application and invoke /sample/uuid and /sample/data URLs to see the results:

$ curl -X GET http://localhost:8080/sample/uuid
7149a954-da9a-4bfb-ba04-4b9f814698fa
$ curl -X GET http://localhost:8080/sample/data
{"message":"Micronaut rocks"}

Written with Micronaut 1.0.0.M4 and Spring Boot 2.0.4.RELEASE.