BAEL-6751 - reactive apis with micronaut (#14824)
* BAEL-6751 - reactive apis with micronaut * BAEL-6751 - reactive apis with micronaut * BAEL-6751 - added error handling * BAEL-6751 - removed unused property * BAEL-6751 - formatting changes * BAEL-6751 - added missing class * BAEL-6751 - moving module to parent pom * BAEL-6751 - moving version number to property
This commit is contained in:
		
							parent
							
								
									506c2cedc1
								
							
						
					
					
						commit
						39974e2d6d
					
				
							
								
								
									
										5
									
								
								microservices-modules/micronaut-reactive/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								microservices-modules/micronaut-reactive/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| ## Micronaut Reactive | ||||
| 
 | ||||
| This module contains articles about Micronaut Reactive | ||||
| 
 | ||||
| ### Relevant Articles: | ||||
							
								
								
									
										199
									
								
								microservices-modules/micronaut-reactive/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								microservices-modules/micronaut-reactive/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,199 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <groupId>com.baeldung</groupId> | ||||
|     <artifactId>micronaut-reactive</artifactId> | ||||
|     <version>0.1</version> | ||||
|     <packaging>${packaging}</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>io.micronaut.platform</groupId> | ||||
|         <artifactId>micronaut-parent</artifactId> | ||||
|         <version>4.1.2</version> | ||||
|     </parent> | ||||
|     <properties> | ||||
|         <packaging>jar</packaging> | ||||
|         <jdk.version>17</jdk.version> | ||||
|         <release.version>17</release.version> | ||||
|         <micronaut.runtime>netty</micronaut.runtime> | ||||
|         <micronaut.aot.enabled>false</micronaut.aot.enabled> | ||||
|         <micronaut.aot.packageName>com.baeldung.aot.generated</micronaut.aot.packageName> | ||||
|         <micronaut.test.resources.enabled>true</micronaut.test.resources.enabled> | ||||
|         <exec.mainClass>com.baeldung.micronautreactive.Application</exec.mainClass> | ||||
|         <micronaut-test-resources-testcontainers.version>2.1.0</micronaut-test-resources-testcontainers.version> | ||||
|     </properties> | ||||
| 
 | ||||
|     <repositories> | ||||
|         <repository> | ||||
|             <id>central</id> | ||||
|             <url>https://repo.maven.apache.org/maven2</url> | ||||
|         </repository> | ||||
|     </repositories> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut</groupId> | ||||
|             <artifactId>micronaut-http-server-netty</artifactId> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut.validation</groupId> | ||||
|             <artifactId>micronaut-validation</artifactId> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>jakarta.validation</groupId> | ||||
|             <artifactId>jakarta.validation-api</artifactId> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut.data</groupId> | ||||
|             <artifactId>micronaut-data-mongodb</artifactId> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut.mongodb</groupId> | ||||
|             <artifactId>micronaut-mongo-reactive</artifactId> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut.reactor</groupId> | ||||
|             <artifactId>micronaut-reactor</artifactId> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut.serde</groupId> | ||||
|             <artifactId>micronaut-serde-bson</artifactId> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>ch.qos.logback</groupId> | ||||
|             <artifactId>logback-classic</artifactId> | ||||
|             <scope>runtime</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.mongodb</groupId> | ||||
|             <artifactId>mongodb-driver-reactivestreams</artifactId> | ||||
|             <scope>runtime</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut.testresources</groupId> | ||||
|             <artifactId>micronaut-test-resources-client</artifactId> | ||||
|             <scope>provided</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut</groupId> | ||||
|             <artifactId>micronaut-http-client</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|         <!-- https://mvnrepository.com/artifact/io.micronaut.testresources/micronaut-test-resources-testcontainers --> | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut.testresources</groupId> | ||||
|             <artifactId>micronaut-test-resources-testcontainers</artifactId> | ||||
|             <version>${micronaut-test-resources-testcontainers.version}</version> | ||||
|         </dependency> | ||||
| 
 | ||||
|         <dependency> | ||||
|             <groupId>io.micronaut.test</groupId> | ||||
|             <artifactId>micronaut-test-junit5</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.junit.jupiter</groupId> | ||||
|             <artifactId>junit-jupiter-api</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.junit.jupiter</groupId> | ||||
|             <artifactId>junit-jupiter-engine</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
|     <build> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>io.micronaut.maven</groupId> | ||||
|                 <artifactId>micronaut-maven-plugin</artifactId> | ||||
|                 <configuration> | ||||
|                     <configFile>aot-${packaging}.properties</configFile> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-enforcer-plugin</artifactId> | ||||
|             </plugin> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <configuration> | ||||
|                     <!-- Uncomment to enable incremental compilation --> | ||||
|                     <!-- <useIncrementalCompilation>false</useIncrementalCompilation> --> | ||||
| 
 | ||||
|                     <annotationProcessorPaths combine.self="override"> | ||||
|                         <path> | ||||
|                             <groupId>io.micronaut</groupId> | ||||
|                             <artifactId>micronaut-inject-java</artifactId> | ||||
|                             <version>${micronaut.core.version}</version> | ||||
|                         </path> | ||||
| 
 | ||||
|                         <path> | ||||
|                             <groupId>io.micronaut.data</groupId> | ||||
|                             <artifactId>micronaut-data-processor</artifactId> | ||||
|                             <version>${micronaut.data.version}</version> | ||||
|                             <exclusions> | ||||
|                                 <exclusion> | ||||
|                                     <groupId>io.micronaut</groupId> | ||||
|                                     <artifactId>micronaut-inject</artifactId> | ||||
|                                 </exclusion> | ||||
|                             </exclusions> | ||||
|                         </path> | ||||
|                         <path> | ||||
|                             <groupId>io.micronaut.data</groupId> | ||||
|                             <artifactId>micronaut-data-document-processor</artifactId> | ||||
|                             <version>${micronaut.data.version}</version> | ||||
|                             <exclusions> | ||||
|                                 <exclusion> | ||||
|                                     <groupId>io.micronaut</groupId> | ||||
|                                     <artifactId>micronaut-inject</artifactId> | ||||
|                                 </exclusion> | ||||
|                             </exclusions> | ||||
|                         </path> | ||||
|                         <path> | ||||
|                             <groupId>io.micronaut</groupId> | ||||
|                             <artifactId>micronaut-graal</artifactId> | ||||
|                             <version>${micronaut.core.version}</version> | ||||
|                         </path> | ||||
|                         <path> | ||||
|                             <groupId>io.micronaut.serde</groupId> | ||||
|                             <artifactId>micronaut-serde-processor</artifactId> | ||||
|                             <version>${micronaut.serialization.version}</version> | ||||
|                             <exclusions> | ||||
|                                 <exclusion> | ||||
|                                     <groupId>io.micronaut</groupId> | ||||
|                                     <artifactId>micronaut-inject</artifactId> | ||||
|                                 </exclusion> | ||||
|                             </exclusions> | ||||
|                         </path> | ||||
|                         <path> | ||||
|                             <groupId>io.micronaut.validation</groupId> | ||||
|                             <artifactId>micronaut-validation-processor</artifactId> | ||||
|                             <version>${micronaut.validation.version}</version> | ||||
|                             <exclusions> | ||||
|                                 <exclusion> | ||||
|                                     <groupId>io.micronaut</groupId> | ||||
|                                     <artifactId>micronaut-inject</artifactId> | ||||
|                                 </exclusion> | ||||
|                             </exclusions> | ||||
|                         </path> | ||||
|                     </annotationProcessorPaths> | ||||
|                     <compilerArgs> | ||||
|                         <arg>-Amicronaut.processing.group=com.baeldung</arg> | ||||
|                         <arg>-Amicronaut.processing.module=micronaut-reactive</arg> | ||||
|                     </compilerArgs> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,10 @@ | ||||
| package com.baeldung.micronautreactive; | ||||
| 
 | ||||
| import io.micronaut.runtime.Micronaut; | ||||
| 
 | ||||
| public class Application { | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
|         Micronaut.run(Application.class, args); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,82 @@ | ||||
| package com.baeldung.micronautreactive.controller; | ||||
| 
 | ||||
| import com.baeldung.micronautreactive.dtos.BookNotFoundException; | ||||
| import com.baeldung.micronautreactive.entity.Book; | ||||
| import com.baeldung.micronautreactive.service.BookService; | ||||
| import io.micronaut.core.annotation.Nullable; | ||||
| import io.micronaut.http.HttpResponse; | ||||
| import io.micronaut.http.MutableHttpResponse; | ||||
| import io.micronaut.http.annotation.Error; | ||||
| import io.micronaut.http.annotation.*; | ||||
| import jakarta.validation.ConstraintViolationException; | ||||
| import jakarta.validation.Valid; | ||||
| import org.bson.types.ObjectId; | ||||
| import reactor.core.publisher.Flux; | ||||
| 
 | ||||
| @Controller("/books") | ||||
| public class BookController { | ||||
| 
 | ||||
|     private final BookService bookService; | ||||
| 
 | ||||
|     public BookController(BookService bookService) { | ||||
|         this.bookService = bookService; | ||||
|     } | ||||
| 
 | ||||
|     @Post | ||||
|     public String createBook(@Valid @Body Book book) { | ||||
|         @Nullable ObjectId bookId = bookService.save(book); | ||||
|         if (null == bookId) { | ||||
|             return "Book not created"; | ||||
|         } else { | ||||
|             return "Book created with id: " + bookId; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Put | ||||
|     public String updateBook(@Valid @Body Book book) { | ||||
|         @Nullable ObjectId bookId = bookService.update(book); | ||||
|         if (null == bookId) { | ||||
|             return "Book not updated"; | ||||
|         } else { | ||||
|             return "Book updated with id: " + bookId; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Delete("/{id}") | ||||
|     public String deleteBook(String id) throws BookNotFoundException { | ||||
|         Long bookId = bookService.deleteById(id); | ||||
|         if (1 == bookId) { | ||||
|             return "Book deleted"; | ||||
|         } else { | ||||
|             throw new BookNotFoundException(id); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Get("/{id}") | ||||
|     public Book findById(@PathVariable("id") String identifier) throws BookNotFoundException { | ||||
|         Book book = bookService.findById(identifier); | ||||
|         if (null == book) { | ||||
|             throw new BookNotFoundException(identifier); | ||||
|         } else { | ||||
|             return book; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Get("/published-after") | ||||
|     public Flux<Book> findByYearGreaterThan(@QueryValue(value = "year") int year) { | ||||
|         return bookService.findByYearGreaterThan(year); | ||||
|     } | ||||
| 
 | ||||
|     @Error(exception = ConstraintViolationException.class) | ||||
|     public MutableHttpResponse<String> onSavedFailed(ConstraintViolationException ex) { | ||||
|         return HttpResponse.badRequest(ex.getConstraintViolations().stream() | ||||
|           .map(cv -> cv.getPropertyPath() + " " + cv.getMessage()) | ||||
|           .toList().toString()); | ||||
|     } | ||||
| 
 | ||||
|     @Error(exception = BookNotFoundException.class) | ||||
|     public HttpResponse<String> onSavedFailed(BookNotFoundException ex) { | ||||
|         return HttpResponse.notFound(ex.getMessage()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,7 @@ | ||||
| package com.baeldung.micronautreactive.dtos; | ||||
| 
 | ||||
| public class BookNotFoundException extends Exception { | ||||
|     public BookNotFoundException(String id) { | ||||
|         super("Book with id " + id + " not found"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| package com.baeldung.micronautreactive.entity; | ||||
| 
 | ||||
| import io.micronaut.core.annotation.Introspected; | ||||
| import io.micronaut.serde.annotation.Serdeable; | ||||
| 
 | ||||
| @Serdeable | ||||
| public class Author { | ||||
|     private String firstName; | ||||
|     private String lastName; | ||||
| 
 | ||||
|     public Author() { | ||||
|     } | ||||
| 
 | ||||
|     public Author(String firstName, String lastName) { | ||||
|         this.firstName = firstName; | ||||
|         this.lastName = lastName; | ||||
|     } | ||||
| 
 | ||||
|     public String getFirstName() { | ||||
|         return firstName; | ||||
|     } | ||||
| 
 | ||||
|     public void setFirstName(String firstName) { | ||||
|         this.firstName = firstName; | ||||
|     } | ||||
| 
 | ||||
|     public String getLastName() { | ||||
|         return lastName; | ||||
|     } | ||||
| 
 | ||||
|     public void setLastName(String lastName) { | ||||
|         this.lastName = lastName; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,73 @@ | ||||
| package com.baeldung.micronautreactive.entity; | ||||
| 
 | ||||
| import io.micronaut.core.annotation.Generated; | ||||
| import io.micronaut.core.annotation.Nullable; | ||||
| import io.micronaut.data.annotation.Id; | ||||
| import io.micronaut.data.annotation.MappedEntity; | ||||
| import io.micronaut.serde.annotation.Serdeable; | ||||
| 
 | ||||
| import jakarta.validation.constraints.NotBlank; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import org.bson.types.ObjectId; | ||||
| 
 | ||||
| @Serdeable | ||||
| @MappedEntity | ||||
| public class Book { | ||||
|     @Id | ||||
|     @Generated | ||||
|     private @Nullable ObjectId id; | ||||
|     @NotBlank | ||||
|     private String title; | ||||
| 
 | ||||
|     @NotNull | ||||
|     private Author author; | ||||
|     private int year; | ||||
| 
 | ||||
|     public Book() { | ||||
|     } | ||||
| 
 | ||||
|     public Book(@Nullable ObjectId id, String title, Author author, int year) { | ||||
|         this.id = id; | ||||
|         this.title = title; | ||||
|         this.author = author; | ||||
|         this.year = year; | ||||
|     } | ||||
| 
 | ||||
|     public Book(String title, Author author, int year) { | ||||
|         this.title = title; | ||||
|         this.author = author; | ||||
|         this.year = year; | ||||
|     } | ||||
| 
 | ||||
|     public @Nullable ObjectId getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public void setId(@Nullable ObjectId id) { | ||||
|         this.id = id; | ||||
|     } | ||||
| 
 | ||||
|     public String getTitle() { | ||||
|         return title; | ||||
|     } | ||||
| 
 | ||||
|     public void setTitle(String title) { | ||||
|         this.title = title; | ||||
|     } | ||||
| 
 | ||||
|     public Author getAuthor() { | ||||
|         return author; | ||||
|     } | ||||
| 
 | ||||
|     public void setAuthor(Author author) { | ||||
|         this.author = author; | ||||
|     } | ||||
| 
 | ||||
|     public int getYear() { | ||||
|         return year; | ||||
|     } | ||||
| 
 | ||||
|     public void setYear(int year) { | ||||
|         this.year = year; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| package com.baeldung.micronautreactive.repository; | ||||
| 
 | ||||
| import com.baeldung.micronautreactive.entity.Book; | ||||
| import io.micronaut.context.annotation.Parameter; | ||||
| import io.micronaut.core.async.annotation.SingleResult; | ||||
| import io.micronaut.data.mongodb.annotation.MongoFindQuery; | ||||
| import io.micronaut.data.mongodb.annotation.MongoRepository; | ||||
| import io.micronaut.data.repository.reactive.ReactorCrudRepository; | ||||
| import org.bson.types.ObjectId; | ||||
| import reactor.core.publisher.Flux; | ||||
| 
 | ||||
| @MongoRepository | ||||
| public interface BookRepository extends ReactorCrudRepository<Book, ObjectId> { | ||||
| 
 | ||||
|     @MongoFindQuery("{year: {$gt: :year}}") | ||||
|     Flux<Book> findByYearGreaterThan(int year); | ||||
| } | ||||
| @ -0,0 +1,38 @@ | ||||
| package com.baeldung.micronautreactive.service; | ||||
| 
 | ||||
| import com.baeldung.micronautreactive.entity.Book; | ||||
| import com.baeldung.micronautreactive.repository.BookRepository; | ||||
| import jakarta.inject.Singleton; | ||||
| import org.bson.types.ObjectId; | ||||
| import reactor.core.publisher.Flux; | ||||
| 
 | ||||
| @Singleton | ||||
| public class BookService { | ||||
|     private final BookRepository bookRepository; | ||||
| 
 | ||||
|     public BookService(BookRepository bookRepository) { | ||||
|         this.bookRepository = bookRepository; | ||||
|     } | ||||
| 
 | ||||
|     public ObjectId save(Book book) { | ||||
|         Book savedBook = bookRepository.save(book).block(); | ||||
|         return null != savedBook ? savedBook.getId() : null; | ||||
|     } | ||||
| 
 | ||||
|     public ObjectId update(Book book) { | ||||
|         Book updatedBook = bookRepository.update(book).block(); | ||||
|         return null != updatedBook ? updatedBook.getId() : null; | ||||
|     } | ||||
| 
 | ||||
|     public Long deleteById(String id) { | ||||
|         return bookRepository.deleteById(new ObjectId(id)).block(); | ||||
|     } | ||||
| 
 | ||||
|     public Flux<Book> findByYearGreaterThan(int year) { | ||||
|         return bookRepository.findByYearGreaterThan(year); | ||||
|     } | ||||
| 
 | ||||
|     public Book findById(String id) { | ||||
|         return bookRepository.findById(new ObjectId(id)).block(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,4 @@ | ||||
| #Sun Aug 27 12:03:55 GMT 2023 | ||||
| micronaut.application.name=micronaut-reactive | ||||
| mongodb.uri: mongodb://${MONGO_HOST:localhost}:${MONGO_PORT:27017}/someDb | ||||
| 
 | ||||
| @ -0,0 +1,14 @@ | ||||
| <configuration> | ||||
| 
 | ||||
|     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | ||||
|         <!-- encoders are assigned the type | ||||
|              ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> | ||||
|         <encoder> | ||||
|             <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> | ||||
|         </encoder> | ||||
|     </appender> | ||||
| 
 | ||||
|     <root level="info"> | ||||
|         <appender-ref ref="STDOUT" /> | ||||
|     </root> | ||||
| </configuration> | ||||
| @ -0,0 +1,21 @@ | ||||
| package com.baeldung.micronautreactive; | ||||
| 
 | ||||
| import io.micronaut.runtime.EmbeddedApplication; | ||||
| import io.micronaut.test.extensions.junit5.annotation.MicronautTest; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.junit.jupiter.api.Assertions; | ||||
| 
 | ||||
| import jakarta.inject.Inject; | ||||
| 
 | ||||
| @MicronautTest(transactional = false) | ||||
| class MicronautReactiveTest { | ||||
| 
 | ||||
|     @Inject | ||||
|     EmbeddedApplication<?> application; | ||||
| 
 | ||||
|     @Test | ||||
|     void testItWorks() { | ||||
|         Assertions.assertTrue(application.isRunning()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -17,6 +17,7 @@ | ||||
|         <module>helidon</module> | ||||
|         <!-- <module>lagom</module> --> <!-- Not a maven project --> | ||||
|         <module>micronaut</module> | ||||
|         <module>micronaut-reactive</module> | ||||
|         <module>microprofile</module> | ||||
|         <module>msf4j</module> | ||||
|         <module>open-liberty</module> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user