├── cdi ├── .mvn │ ├── jvm.config │ └── wrapper │ │ └── maven-wrapper.properties ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── demo │ │ │ │ ├── CreatePostCommand.java │ │ │ │ ├── Post.java │ │ │ │ ├── PostNotFoundException.java │ │ │ │ ├── DemoApplication.java │ │ │ │ ├── CdiAwareVerticleFactory.java │ │ │ │ ├── Resources.java │ │ │ │ ├── DataInitializer.java │ │ │ │ ├── PostsHandler.java │ │ │ │ ├── PostRepository.java │ │ │ │ └── MainVerticle.java │ │ └── resources │ │ │ ├── logging.properties │ │ │ └── META-INF │ │ │ └── beans.xml │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── demo │ │ └── TestMainVerticle.java ├── .editorconfig └── .gitignore ├── docs ├── starter.png ├── _config.yml └── index.md ├── spring ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── demo │ │ │ │ ├── CreatePostCommand.java │ │ │ │ ├── Post.java │ │ │ │ ├── PostNotFoundException.java │ │ │ │ ├── SpringAwareVerticleFactory.java │ │ │ │ ├── DemoApplication.java │ │ │ │ ├── DataInitializer.java │ │ │ │ ├── PostsHandler.java │ │ │ │ ├── PostRepository.java │ │ │ │ └── MainVerticle.java │ │ └── resources │ │ │ └── logging.properties │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── demo │ │ └── TestMainVerticle.java └── .editorconfig ├── kotlin-co ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── src │ ├── main │ │ └── kotlin │ │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── PostNotFoundException.kt │ │ │ ├── Models.kt │ │ │ ├── DataInitializer.kt │ │ │ ├── PostsHandler.kt │ │ │ └── PostRepository.kt │ └── test │ │ └── kotlin │ │ └── com │ │ └── example │ │ └── demo │ │ └── TestMainVerticle.kt └── .editorconfig ├── renovate.json ├── mutiny-spring-hibernate ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── demo │ │ │ │ ├── CreatePostCommand.java │ │ │ │ ├── PostNotFoundException.java │ │ │ │ ├── DemoApplication.java │ │ │ │ ├── SpringAwareVerticleFactory.java │ │ │ │ ├── Post.java │ │ │ │ └── DataInitializer.java │ │ └── resources │ │ │ ├── logging.properties │ │ │ └── META-INF │ │ │ └── persistence.xml │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── demo │ │ └── TestMainVerticle.java └── .editorconfig ├── rxjava3 ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── demo │ │ │ │ ├── CreatePostCommand.java │ │ │ │ ├── Post.java │ │ │ │ ├── PostNotFoundException.java │ │ │ │ ├── DataInitializer.java │ │ │ │ ├── PostsHandler.java │ │ │ │ └── PostRepository.java │ │ └── resources │ │ │ └── logback.xml │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── demo │ │ └── TestMainVerticle.java ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── .editorconfig ├── README.adoc └── .gitignore ├── graphql-http ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── gql │ │ │ ├── types │ │ │ │ ├── PostStatus.java │ │ │ │ ├── CommentInput.java │ │ │ │ ├── CreatePostInput.java │ │ │ │ ├── Comment.java │ │ │ │ ├── Author.java │ │ │ │ └── Post.java │ │ │ ├── scalars │ │ │ │ ├── Scalars.java │ │ │ │ ├── UUIDScalar.java │ │ │ │ └── LocalDateTimeScalar.java │ │ │ ├── directives │ │ │ │ └── UpperCaseDirectiveWiring.java │ │ │ ├── CustomDataFetchingExceptionHandler.java │ │ │ └── DataLoaders.java │ │ │ ├── model │ │ │ ├── CommentEntity.java │ │ │ ├── AuthorEntity.java │ │ │ └── PostEntity.java │ │ │ ├── repository │ │ │ ├── PostNotFoundException.java │ │ │ ├── AuthorNotFoundException.java │ │ │ ├── CommentNotFoundException.java │ │ │ ├── AuthorRepository.java │ │ │ ├── CommentRepository.java │ │ │ └── PostRepository.java │ │ │ ├── service │ │ │ ├── AuthorService.java │ │ │ └── PostService.java │ │ │ └── DataInitializer.java │ │ └── resources │ │ ├── schema │ │ └── schema.graphql │ │ └── logback.xml ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties └── .editorconfig ├── graphql-transport-ws ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── gql │ │ │ ├── types │ │ │ │ ├── PostStatus.java │ │ │ │ ├── CommentInput.java │ │ │ │ ├── CreatePostInput.java │ │ │ │ ├── Comment.java │ │ │ │ ├── Author.java │ │ │ │ └── Post.java │ │ │ ├── scalars │ │ │ │ ├── Scalars.java │ │ │ │ ├── UUIDScalar.java │ │ │ │ └── LocalDateTimeScalar.java │ │ │ ├── directives │ │ │ │ └── UpperCaseDirectiveWiring.java │ │ │ ├── CustomDataFetchingExceptionHandler.java │ │ │ └── DataLoaders.java │ │ │ ├── model │ │ │ ├── AuthorEntity.java │ │ │ ├── CommentEntity.java │ │ │ └── PostEntity.java │ │ │ ├── repository │ │ │ ├── PostNotFoundException.java │ │ │ ├── AuthorNotFoundException.java │ │ │ ├── CommentNotFoundException.java │ │ │ ├── AuthorRepository.java │ │ │ ├── CommentRepository.java │ │ │ └── PostRepository.java │ │ │ ├── service │ │ │ ├── AuthorService.java │ │ │ └── PostService.java │ │ │ └── DataInitializer.java │ │ └── resources │ │ ├── schema │ │ └── schema.graphql │ │ └── logback.xml └── .mvn │ └── wrapper │ └── maven-wrapper.properties ├── kotlin ├── src │ ├── main │ │ └── kotlin │ │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── PostNotFoundException.kt │ │ │ ├── Models.kt │ │ │ ├── DataInitializer.kt │ │ │ ├── PostRepository.kt │ │ │ └── PostsHandler.kt │ └── test │ │ └── kotlin │ │ └── com │ │ └── example │ │ └── demo │ │ └── TestMainVerticle.kt ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── .editorconfig └── .gitignore ├── web ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── .editorconfig ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── PostNotFoundException.java │ │ │ ├── CreatePostCommand.java │ │ │ ├── Post.java │ │ │ ├── DataInitializer.java │ │ │ ├── PostsHandler.java │ │ │ └── PostRepository.java │ │ └── resources │ │ └── vertx-default-jul-logging.properties ├── README.adoc └── .gitignore ├── docker-compose.yml ├── .gitignore ├── .github └── workflows │ ├── cdi.yml │ ├── web.yml │ ├── spring.yml │ ├── kolin.yml │ ├── graphql-http.yml │ ├── graphql-transport-ws.yml │ ├── mutiny-spring-hibernate.yml │ ├── rxjava3.yml │ └── kotlin-co.yml ├── pg-initdb.d └── init.sql └── README.md /cdi/.mvn/jvm.config: -------------------------------------------------------------------------------- 1 | --add-opens java.base/java.lang=ALL-UNNAMED 2 | 3 | -------------------------------------------------------------------------------- /docs/starter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/vertx-sandbox/HEAD/docs/starter.png -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | title: Eclipse Vertx Notes 3 | description: Developer notes of Eclipse Vertx 4.x -------------------------------------------------------------------------------- /spring/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/vertx-sandbox/HEAD/spring/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /kotlin-co/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/vertx-sandbox/HEAD/kotlin-co/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/vertx-sandbox/HEAD/mutiny-spring-hibernate/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /rxjava3/src/main/java/com/example/demo/CreatePostCommand.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | public record CreatePostCommand(String title, String content) { 4 | } 5 | -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/CreatePostCommand.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | public record CreatePostCommand(String title, String content) { 4 | } 5 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/main/java/com/example/demo/CreatePostCommand.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | public record CreatePostCommand(String title, String content) { 4 | } 5 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/CreatePostCommand.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.io.Serializable; 4 | 5 | public record CreatePostCommand(String title, String content) {} 6 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/types/PostStatus.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | public enum PostStatus { 4 | DRAFT, 5 | PENDING_MODERATION, 6 | PUBLISHED 7 | } 8 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/types/PostStatus.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | public enum PostStatus { 4 | DRAFT, 5 | PENDING_MODERATION, 6 | PUBLISHED 7 | } 8 | -------------------------------------------------------------------------------- /kotlin-co/src/main/kotlin/com/example/demo/PostNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import java.util.* 4 | 5 | class PostNotFoundException(id: UUID) : RuntimeException("Post id: $id was not found. ") 6 | -------------------------------------------------------------------------------- /kotlin/src/main/kotlin/com/example/demo/PostNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import java.util.* 4 | 5 | class PostNotFoundException(id: UUID) : RuntimeException("Post id: $id was not found. ") 6 | -------------------------------------------------------------------------------- /kotlin-co/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip 4 | -------------------------------------------------------------------------------- /spring/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip 4 | -------------------------------------------------------------------------------- /cdi/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-rc-5/apache-maven-4.0.0-rc-5-bin.zip 4 | -------------------------------------------------------------------------------- /kotlin/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-rc-5/apache-maven-4.0.0-rc-5-bin.zip 4 | -------------------------------------------------------------------------------- /rxjava3/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-rc-5/apache-maven-4.0.0-rc-5-bin.zip 4 | -------------------------------------------------------------------------------- /web/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-rc-5/apache-maven-4.0.0-rc-5-bin.zip 4 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/Post.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record Post(UUID id, String title, String content, LocalDateTime createdAt) {} 7 | -------------------------------------------------------------------------------- /graphql-http/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-rc-5/apache-maven-4.0.0-rc-5-bin.zip 4 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip 4 | -------------------------------------------------------------------------------- /graphql-transport-ws/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-rc-5/apache-maven-4.0.0-rc-5-bin.zip 4 | -------------------------------------------------------------------------------- /rxjava3/src/main/java/com/example/demo/Post.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record Post(UUID id, String title, String content, LocalDateTime createdAt) { 7 | } 8 | -------------------------------------------------------------------------------- /cdi/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /web/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /kotlin/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /rxjava3/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /spring/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /graphql-http/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /kotlin-co/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/Post.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record Post( 7 | UUID id, 8 | String title, 9 | String content, 10 | LocalDateTime createdAt 11 | ) {} 12 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/PostNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.util.UUID; 4 | 5 | public class PostNotFoundException extends RuntimeException { 6 | public PostNotFoundException(UUID id) { 7 | super("Post id: " + id + " was not found. "); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/demo/PostNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.util.UUID; 4 | 5 | public class PostNotFoundException extends RuntimeException { 6 | public PostNotFoundException(UUID id) { 7 | super("Post id: " + id + " was not found. "); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /rxjava3/src/main/java/com/example/demo/PostNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.util.UUID; 4 | 5 | public class PostNotFoundException extends RuntimeException { 6 | public PostNotFoundException(UUID id) { 7 | super("Post id: " + id + " was not found. "); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/PostNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.util.UUID; 4 | 5 | public class PostNotFoundException extends RuntimeException { 6 | public PostNotFoundException(UUID id) { 7 | super("Post id: " + id + " was not found. "); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/model/CommentEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record CommentEntity( 7 | UUID id, 8 | String content, 9 | LocalDateTime createdAt, 10 | UUID postId 11 | ) { 12 | } 13 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/main/java/com/example/demo/PostNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.util.UUID; 4 | 5 | public class PostNotFoundException extends RuntimeException { 6 | public PostNotFoundException(UUID id) { 7 | super("Post id: " + id + " was not found. "); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/model/AuthorEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record AuthorEntity( 7 | UUID id, 8 | String name, 9 | String email, 10 | LocalDateTime createdAt 11 | ) { 12 | } 13 | 14 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/repository/PostNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import java.util.UUID; 4 | 5 | public class PostNotFoundException extends RuntimeException { 6 | public PostNotFoundException(UUID id) { 7 | super("Post: " + id + " was not found."); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/model/AuthorEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record AuthorEntity( 7 | UUID id, 8 | String name, 9 | String email, 10 | LocalDateTime createdAt 11 | ) { 12 | } 13 | 14 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/model/CommentEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record CommentEntity( 7 | UUID id, 8 | String content, 9 | LocalDateTime createdAt, 10 | UUID postId 11 | ) { 12 | } 13 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/repository/AuthorNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import java.util.UUID; 4 | 5 | public class AuthorNotFoundException extends RuntimeException { 6 | public AuthorNotFoundException(UUID id) { 7 | super("Author: " + id + " was not found."); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/repository/PostNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import java.util.UUID; 4 | 5 | public class PostNotFoundException extends RuntimeException { 6 | public PostNotFoundException(UUID id) { 7 | super("Post: " + id + " was not found."); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/repository/CommentNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import java.util.UUID; 4 | 5 | public class CommentNotFoundException extends RuntimeException { 6 | public CommentNotFoundException(UUID id) { 7 | super("Comment: " + id + " was not found."); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/repository/AuthorNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import java.util.UUID; 4 | 5 | public class AuthorNotFoundException extends RuntimeException { 6 | public AuthorNotFoundException(UUID id) { 7 | super("Author: " + id + " was not found."); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/repository/CommentNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import java.util.UUID; 4 | 5 | public class CommentNotFoundException extends RuntimeException { 6 | public CommentNotFoundException(UUID id) { 7 | super("Comment: " + id + " was not found."); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /cdi/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | 2 | java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n 3 | 4 | # Global logging level. Can be overridden by specific loggers 5 | .level=INFO 6 | 7 | # Component specific log levels 8 | #io.netty.level=INFO 9 | #io.vertx.core.level=FINEST 10 | #com.example.demo.level=FINEST 11 | -------------------------------------------------------------------------------- /spring/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | 2 | java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n 3 | 4 | # Global logging level. Can be overridden by specific loggers 5 | .level=INFO 6 | 7 | # Component specific log levels 8 | #io.netty.level=INFO 9 | #io.vertx.core.level=FINEST 10 | #com.example.demo.level=FINEST 11 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/model/PostEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record PostEntity( 7 | UUID id, 8 | String title, 9 | String content, 10 | String status, 11 | LocalDateTime createdAt, 12 | UUID authorId 13 | ) { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /web/src/main/resources/vertx-default-jul-logging.properties: -------------------------------------------------------------------------------- 1 | 2 | java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n 3 | 4 | # Global logging level. Can be overridden by specific loggers 5 | .level=INFO 6 | 7 | # Component specific log levels 8 | io.netty.level=INFO 9 | io.vertx.core.level=FINEST 10 | com.example.demo.level=FINEST 11 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/model/PostEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | 6 | public record PostEntity( 7 | UUID id, 8 | String title, 9 | String content, 10 | String status, 11 | LocalDateTime createdAt, 12 | UUID authorId 13 | ) { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | 2 | java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n 3 | 4 | # Global logging level. Can be overridden by specific loggers 5 | .level=INFO 6 | 7 | # Component specific log levels 8 | #io.netty.level=INFO 9 | #io.vertx.core.level=FINEST 10 | #com.example.demo.level=FINEST 11 | -------------------------------------------------------------------------------- /cdi/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/types/CommentInput.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class CommentInput { 13 | private String postId; 14 | private String content; 15 | } 16 | -------------------------------------------------------------------------------- /kotlin/src/main/kotlin/com/example/demo/Models.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import java.time.LocalDateTime 4 | import java.util.* 5 | 6 | data class Post( 7 | var id: UUID? = null, 8 | var title: String, 9 | var content: String, 10 | var createdAt: LocalDateTime? = LocalDateTime.now() 11 | ) 12 | 13 | data class CreatePostCommand( 14 | val title: String, 15 | val content: String 16 | ) 17 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # version: '3.7' # specify docker-compose version 2 | 3 | services: 4 | postgres: 5 | image: postgres 6 | ports: 7 | - "5432:5432" 8 | restart: always 9 | environment: 10 | POSTGRES_PASSWORD: password 11 | POSTGRES_DB: blogdb 12 | POSTGRES_USER: user 13 | volumes: 14 | - ./data:/var/lib/postgresql 15 | - ./pg-initdb.d:/docker-entrypoint-initdb.d 16 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/types/CommentInput.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class CommentInput { 13 | private String postId; 14 | private String content; 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | .idea 25 | *.iml 26 | 27 | .project 28 | .classpath 29 | .vscode 30 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/types/CreatePostInput.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.io.Serializable; 9 | import java.util.Objects; 10 | 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class CreatePostInput { 16 | 17 | String title; 18 | String content; 19 | } 20 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/types/CreatePostInput.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.io.Serializable; 9 | import java.util.Objects; 10 | 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class CreatePostInput { 16 | 17 | String title; 18 | String content; 19 | } 20 | -------------------------------------------------------------------------------- /kotlin-co/src/main/kotlin/com/example/demo/Models.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import java.time.LocalDateTime 4 | import java.util.* 5 | 6 | data class Post( 7 | var id: UUID? = null, 8 | var title: String, 9 | var content: String, 10 | var createdAt: LocalDateTime? = LocalDateTime.now() 11 | ) 12 | 13 | data class CreatePostCommand( 14 | val title: String, 15 | val content: String 16 | ) 17 | 18 | data class UpdatePostCommand( 19 | val title: String, 20 | val content: String 21 | ) 22 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/demo/CreatePostCommand.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.util.Objects; 4 | 5 | public record CreatePostCommand(String title, String content) { 6 | public CreatePostCommand { 7 | Objects.requireNonNull(title, "title must not be null"); 8 | Objects.requireNonNull(content, "content must not be null"); 9 | } 10 | 11 | public static CreatePostCommand of(String title, String content) { 12 | return new CreatePostCommand(title, content); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/types/Comment.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | @Data 11 | @Builder 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class Comment { 15 | 16 | private String id; 17 | 18 | private String content; 19 | 20 | private LocalDateTime createdAt; 21 | 22 | private String postId; 23 | } 24 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/types/Comment.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | @Data 11 | @Builder 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class Comment { 15 | 16 | private String id; 17 | 18 | private String content; 19 | 20 | private LocalDateTime createdAt; 21 | 22 | private String postId; 23 | } 24 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/demo/Post.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.time.LocalDateTime; 4 | import java.util.UUID; 5 | import java.util.Objects; 6 | 7 | public record Post(UUID id, String title, String content, LocalDateTime createdAt) { 8 | 9 | public Post { 10 | Objects.requireNonNull(title, "title must not be null"); 11 | Objects.requireNonNull(content, "content must not be null"); 12 | } 13 | 14 | public static Post of(String title, String content) { 15 | return new Post(null, title, content, null); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/types/Author.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class Author { 17 | 18 | private String id; 19 | 20 | private String name; 21 | 22 | private String email; 23 | 24 | private LocalDateTime createdAt; 25 | 26 | @Builder.Default 27 | private List posts = new ArrayList<>(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/types/Author.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class Author { 17 | 18 | private String id; 19 | 20 | private String name; 21 | 22 | private String email; 23 | 24 | private LocalDateTime createdAt; 25 | 26 | @Builder.Default 27 | private List posts = new ArrayList<>(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/types/Post.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class Post { 17 | private String id; 18 | private String title; 19 | private String content; 20 | 21 | @Builder.Default 22 | private List comments = new ArrayList<>(); 23 | private PostStatus status; 24 | private LocalDateTime createdAt; 25 | 26 | private String authorId; 27 | private Author author; 28 | } 29 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/types/Post.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.types; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class Post { 17 | private String id; 18 | private String title; 19 | private String content; 20 | 21 | @Builder.Default 22 | private List comments = new ArrayList<>(); 23 | private PostStatus status; 24 | private LocalDateTime createdAt; 25 | 26 | private String authorId; 27 | private Author author; 28 | } 29 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/scalars/Scalars.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.scalars; 2 | 3 | import graphql.schema.GraphQLScalarType; 4 | 5 | public class Scalars { 6 | 7 | public static GraphQLScalarType uuidType() { 8 | return GraphQLScalarType.newScalar() 9 | .name("UUID") 10 | .description("UUID type") 11 | .coercing(new UUIDScalar()) 12 | .build(); 13 | } 14 | 15 | public static GraphQLScalarType localDateTimeType() { 16 | return GraphQLScalarType.newScalar() 17 | .name("LocalDateTime") 18 | .description("LocalDateTime type") 19 | .coercing(new LocalDateTimeScalar()) 20 | .build(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /web/README.adoc: -------------------------------------------------------------------------------- 1 | = Demo 2 | 3 | image:https://img.shields.io/badge/vert.x-4.0.0-purple.svg[link="https://vertx.io"] 4 | 5 | This application was generated using http://start.vertx.io 6 | 7 | == Building 8 | 9 | To launch your tests: 10 | ``` 11 | ./mvnw clean test 12 | ``` 13 | 14 | To package your application: 15 | ``` 16 | ./mvnw clean package 17 | ``` 18 | 19 | To run your application: 20 | ``` 21 | ./mvnw clean compile exec:java 22 | ``` 23 | 24 | == Help 25 | 26 | * https://vertx.io/docs/[Vert.x Documentation] 27 | * https://stackoverflow.com/questions/tagged/vert.x?sort=newest&pageSize=15[Vert.x Stack Overflow] 28 | * https://groups.google.com/forum/?fromgroups#!forum/vertx[Vert.x User Group] 29 | * https://gitter.im/eclipse-vertx/vertx-users[Vert.x Gitter] 30 | 31 | 32 | -------------------------------------------------------------------------------- /rxjava3/README.adoc: -------------------------------------------------------------------------------- 1 | = Demo 2 | 3 | image:https://img.shields.io/badge/vert.x-4.0.0-purple.svg[link="https://vertx.io"] 4 | 5 | This application was generated using http://start.vertx.io 6 | 7 | == Building 8 | 9 | To launch your tests: 10 | ``` 11 | ./mvnw clean test 12 | ``` 13 | 14 | To package your application: 15 | ``` 16 | ./mvnw clean package 17 | ``` 18 | 19 | To run your application: 20 | ``` 21 | ./mvnw clean compile exec:java 22 | ``` 23 | 24 | == Help 25 | 26 | * https://vertx.io/docs/[Vert.x Documentation] 27 | * https://stackoverflow.com/questions/tagged/vert.x?sort=newest&pageSize=15[Vert.x Stack Overflow] 28 | * https://groups.google.com/forum/?fromgroups#!forum/vertx[Vert.x User Group] 29 | * https://gitter.im/eclipse-vertx/vertx-users[Vert.x Gitter] 30 | 31 | 32 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/scalars/Scalars.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.scalars; 2 | 3 | import graphql.schema.GraphQLScalarType; 4 | 5 | public class Scalars { 6 | 7 | public static GraphQLScalarType uuidType() { 8 | return GraphQLScalarType.newScalar() 9 | .name("UUID") 10 | .description("UUID type") 11 | .coercing(new UUIDScalar()) 12 | .build(); 13 | } 14 | 15 | public static GraphQLScalarType localDateTimeType() { 16 | return GraphQLScalarType.newScalar() 17 | .name("LocalDateTime") 18 | .description("LocalDateTime type") 19 | .coercing(new LocalDateTimeScalar()) 20 | .build(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | * [Building RESTful APIs with Eclipse Vertx](./rest.md) 5 | * [Building RESTful APIs with Eclipse Vertx and RxJava 3](./rxjava3.md) 6 | * [Exception Handling and Validation Handlers](./validation.md) 7 | * [Consuming RESTful APIs with Vertx HttpClient](./client.md) 8 | * [Building RESTful APIs with Eclipse Vertx and Kotlin](./kotlin.md) 9 | * [Building RESTful APIs with Eclipse Vertx and Kotlin Coroutines](./kotlin-co.md) 10 | * [Building RESTful APIs with Eclipse Vertx, SmallRye Mutiny, Spring and Hibernate](./hibernate.md) 11 | * [Integrate Vertx Application with Spring](./spring.md) 12 | * [Integrate Vertx Application with CDI](./cdi.md) 13 | * [Building GraphQL APIs with Eclipse Vertx](./graphql.md) 14 | * [Consuming GraphQL APIs with Vertx WebClient](./graphql-client.md) 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/cdi.yml: -------------------------------------------------------------------------------- 1 | name: cdi 2 | 3 | on: 4 | push: 5 | paths: 6 | - "cdi/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "cdi/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | - name: Build cdi 34 | run: mvn clean install --file cdi/pom.xml 35 | -------------------------------------------------------------------------------- /.github/workflows/web.yml: -------------------------------------------------------------------------------- 1 | name: web 2 | 3 | on: 4 | push: 5 | paths: 6 | - "web/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "web/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | 34 | - name: Build web 35 | run: mvn clean install --file web/pom.xml 36 | 37 | 38 | -------------------------------------------------------------------------------- /.github/workflows/spring.yml: -------------------------------------------------------------------------------- 1 | name: spring 2 | 3 | on: 4 | push: 5 | paths: 6 | - "spring/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "spring/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | - name: Build spring 34 | run: mvn clean install --file spring/pom.xml 35 | -------------------------------------------------------------------------------- /.github/workflows/kolin.yml: -------------------------------------------------------------------------------- 1 | name: kotlin 2 | 3 | on: 4 | push: 5 | paths: 6 | - "kotlin/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "kotlin/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | - name: Build kotlin 34 | run: mvn clean install --file kotlin/pom.xml 35 | -------------------------------------------------------------------------------- /.github/workflows/graphql-http.yml: -------------------------------------------------------------------------------- 1 | name: graphql-http 2 | 3 | on: 4 | push: 5 | paths: 6 | - "graphql-http/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "graphql-http/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | - name: Build graphql-http 34 | run: mvn clean install --file graphql-http/pom.xml -------------------------------------------------------------------------------- /.github/workflows/graphql-transport-ws.yml: -------------------------------------------------------------------------------- 1 | name: graphql-transport-ws 2 | 3 | on: 4 | push: 5 | paths: 6 | - "graphql-transport-ws/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "graphql-transport-ws/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | - name: Build graphql 34 | run: mvn clean install --file graphql-transport-ws/pom.xml 35 | -------------------------------------------------------------------------------- /.github/workflows/mutiny-spring-hibernate.yml: -------------------------------------------------------------------------------- 1 | name: mutiny-spring-hibernate 2 | 3 | on: 4 | push: 5 | paths: 6 | - "mutiny-spring-hibernate/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "mutiny-spring-hibernate/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | jobs: 17 | 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | - name: Build with Maven 34 | run: mvn clean install --file mutiny-spring-hibernate/pom.xml 35 | 36 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/directives/UpperCaseDirectiveWiring.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.directives; 2 | 3 | import graphql.schema.*; 4 | import graphql.schema.idl.SchemaDirectiveWiring; 5 | import graphql.schema.idl.SchemaDirectiveWiringEnvironment; 6 | 7 | public class UpperCaseDirectiveWiring implements SchemaDirectiveWiring { 8 | @Override 9 | public GraphQLFieldDefinition onField(SchemaDirectiveWiringEnvironment env) { 10 | 11 | var field = env.getElement(); 12 | var dataFetcher = DataFetcherFactories.wrapDataFetcher(env.getFieldDataFetcher(), 13 | (dataFetchingEnvironment, value) -> { 14 | if (value instanceof String s) { 15 | return s.toUpperCase(); 16 | } 17 | return value; 18 | } 19 | ); 20 | 21 | env.setFieldDataFetcher(dataFetcher); 22 | return field; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/directives/UpperCaseDirectiveWiring.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.directives; 2 | 3 | import graphql.schema.*; 4 | import graphql.schema.idl.SchemaDirectiveWiring; 5 | import graphql.schema.idl.SchemaDirectiveWiringEnvironment; 6 | 7 | public class UpperCaseDirectiveWiring implements SchemaDirectiveWiring { 8 | @Override 9 | public GraphQLFieldDefinition onField(SchemaDirectiveWiringEnvironment env) { 10 | 11 | var field = env.getElement(); 12 | var dataFetcher = DataFetcherFactories.wrapDataFetcher(env.getFieldDataFetcher(), 13 | (dataFetchingEnvironment, value) -> { 14 | if (value instanceof String s) { 15 | return s.toUpperCase(); 16 | } 17 | return value; 18 | } 19 | ); 20 | 21 | env.setFieldDataFetcher(dataFetcher); 22 | return field; 23 | } 24 | } -------------------------------------------------------------------------------- /pg-initdb.d/init.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; 2 | 3 | CREATE TABLE IF NOT EXISTS users ( 4 | id UUID DEFAULT uuid_generate_v4(), 5 | name VARCHAR(255) NOT NULL, 6 | email VARCHAR(255) NOT NULL, 7 | password VARCHAR(255) NOT NULL DEFAULT 'password', 8 | created_at TIMESTAMP, 9 | version INTEGER, 10 | PRIMARY KEY (id) 11 | ); 12 | 13 | CREATE TABLE IF NOT EXISTS posts ( 14 | id UUID DEFAULT uuid_generate_v4(), 15 | title VARCHAR(255), 16 | content VARCHAR(255), 17 | status VARCHAR(255) DEFAULT 'DRAFT', 18 | author_id UUID REFERENCES users, 19 | created_at TIMESTAMP NOT NULL DEFAULT LOCALTIMESTAMP, 20 | updated_at TIMESTAMP, 21 | version INTEGER, 22 | PRIMARY KEY (id) 23 | ); 24 | 25 | CREATE TABLE IF NOT EXISTS comments ( 26 | id UUID DEFAULT uuid_generate_v4(), 27 | content VARCHAR(255), 28 | post_id UUID REFERENCES posts ON DELETE CASCADE, 29 | created_at TIMESTAMP NOT NULL DEFAULT LOCALTIMESTAMP, 30 | version INTEGER, 31 | PRIMARY KEY (id) 32 | ); 33 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.core.spi.VerticleFactory; 5 | import org.jboss.weld.environment.se.Weld; 6 | 7 | import java.util.logging.Logger; 8 | 9 | public class DemoApplication { 10 | 11 | private static final Logger LOGGER = Logger.getLogger(DemoApplication.class.getName()); 12 | 13 | public static void main(String[] args) { 14 | var weld = new Weld(); 15 | var container = weld.initialize(); 16 | Vertx vertx = container.select(Vertx.class).get(); 17 | VerticleFactory factory = container.select(VerticleFactory.class).get(); 18 | 19 | LOGGER.info("vertx clazz:" + vertx.getClass().getName());//Weld does not create proxy classes at runtime on @Singleton beans. 20 | LOGGER.info("factory clazz:" + factory.getClass().getName()); 21 | // deploy MainVerticle via verticle identifier name 22 | vertx.deployVerticle(factory.prefix() + ":" + MainVerticle.class.getName()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/rxjava3.yml: -------------------------------------------------------------------------------- 1 | name: rxjava3 2 | 3 | on: 4 | push: 5 | paths: 6 | - "rxjava3/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "rxjava3/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | 34 | - name: Test with CURL 35 | run: | 36 | mvn clean package exec:java -DskipTests --file rxjava3/pom.xml & 37 | sleep 10 38 | echo ">>> print cURL result <<<" 39 | curl http://localhost:8888/hello & 40 | 41 | - name: Build rxjava3 42 | run: mvn clean install --file rxjava3/pom.xml 43 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/CdiAwareVerticleFactory.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Deployable; 4 | import io.vertx.core.Promise; 5 | import io.vertx.core.Verticle; 6 | import io.vertx.core.VerticleBase; 7 | import io.vertx.core.spi.VerticleFactory; 8 | 9 | import jakarta.enterprise.context.ApplicationScoped; 10 | import jakarta.enterprise.inject.Instance; 11 | import jakarta.inject.Inject; 12 | import java.util.concurrent.Callable; 13 | 14 | // see: https://github.com/vert-x3/vertx-examples/blob/4.x/spring-examples/spring-verticle-factory/src/main/java/io/vertx/examples/spring/verticlefactory/SpringVerticleFactory.java 15 | @ApplicationScoped 16 | public class CdiAwareVerticleFactory implements VerticleFactory { 17 | 18 | @Inject 19 | private Instance instance; 20 | 21 | @Override 22 | public String prefix() { 23 | return "cdi"; 24 | } 25 | 26 | @Override 27 | public void createVerticle2(String verticleName, ClassLoader classLoader, Promise> promise) { 28 | String clazz = VerticleFactory.removePrefix(verticleName); 29 | promise.complete(() -> (VerticleBase) instance.select(Class.forName(clazz)).get()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/scalars/UUIDScalar.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.scalars; 2 | 3 | import graphql.language.StringValue; 4 | import graphql.schema.Coercing; 5 | import graphql.schema.CoercingParseLiteralException; 6 | import graphql.schema.CoercingParseValueException; 7 | import graphql.schema.CoercingSerializeException; 8 | 9 | import java.util.UUID; 10 | 11 | public class UUIDScalar implements Coercing { 12 | @Override 13 | public String serialize(Object o) throws CoercingSerializeException { 14 | if (o instanceof UUID) { 15 | return ((UUID) o).toString(); 16 | } else { 17 | throw new CoercingSerializeException("Not a valid UUID"); 18 | } 19 | } 20 | 21 | @Override 22 | public UUID parseValue(Object o) throws CoercingParseValueException { 23 | return UUID.fromString(o.toString()); 24 | } 25 | 26 | @Override 27 | public UUID parseLiteral(Object input) throws CoercingParseLiteralException { 28 | if (input instanceof StringValue) { 29 | return UUID.fromString(((StringValue) input).getValue()); 30 | } 31 | 32 | throw new CoercingParseLiteralException("Value is not a valid UUID string"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/scalars/UUIDScalar.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.scalars; 2 | 3 | import graphql.language.StringValue; 4 | import graphql.schema.Coercing; 5 | import graphql.schema.CoercingParseLiteralException; 6 | import graphql.schema.CoercingParseValueException; 7 | import graphql.schema.CoercingSerializeException; 8 | 9 | import java.util.UUID; 10 | 11 | public class UUIDScalar implements Coercing { 12 | @Override 13 | public String serialize(Object o) throws CoercingSerializeException { 14 | if (o instanceof UUID) { 15 | return ((UUID) o).toString(); 16 | } else { 17 | throw new CoercingSerializeException("Not a valid UUID"); 18 | } 19 | } 20 | 21 | @Override 22 | public UUID parseValue(Object o) throws CoercingParseValueException { 23 | return UUID.fromString(o.toString()); 24 | } 25 | 26 | @Override 27 | public UUID parseLiteral(Object input) throws CoercingParseLiteralException { 28 | if (input instanceof StringValue) { 29 | return UUID.fromString(((StringValue) input).getValue()); 30 | } 31 | 32 | throw new CoercingParseLiteralException("Value is not a valid UUID string"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /graphql-http/src/main/resources/schema/schema.graphql: -------------------------------------------------------------------------------- 1 | directive @uppercase on FIELD_DEFINITION 2 | 3 | scalar LocalDateTime 4 | scalar UUID 5 | scalar Upload 6 | 7 | type Post { 8 | id: ID! 9 | title: String! @uppercase 10 | content: String 11 | comments: [Comment] 12 | status: PostStatus 13 | createdAt: LocalDateTime 14 | authorId: String 15 | author: Author 16 | } 17 | 18 | type Author { 19 | id: ID! 20 | name: String! 21 | email: String! 22 | createdAt: LocalDateTime 23 | posts: [Post] 24 | } 25 | type Comment { 26 | id: ID! 27 | content: String! 28 | createdAt: LocalDateTime 29 | postId: String! 30 | } 31 | 32 | input CreatePostInput { 33 | title: String! 34 | content: String! 35 | } 36 | 37 | input CommentInput { 38 | postId: String! 39 | content: String! 40 | } 41 | 42 | type Query { 43 | allPosts: [Post!]! 44 | postById(postId: String!): Post 45 | } 46 | 47 | type Mutation { 48 | createPost(createPostInput: CreatePostInput!): UUID! 49 | upload(file: Upload!): Boolean 50 | addComment(commentInput: CommentInput!): UUID! 51 | } 52 | 53 | type Subscription{ 54 | commentAdded: Comment! 55 | } 56 | 57 | enum PostStatus { 58 | DRAFT 59 | PENDING_MODERATION 60 | PUBLISHED 61 | } 62 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/service/AuthorService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.gql.types.Author; 4 | import com.example.demo.model.AuthorEntity; 5 | import com.example.demo.repository.AuthorRepository; 6 | import io.vertx.core.Future; 7 | import lombok.RequiredArgsConstructor; 8 | 9 | import java.util.Collection; 10 | import java.util.List; 11 | import java.util.UUID; 12 | import java.util.function.Function; 13 | 14 | @RequiredArgsConstructor 15 | public class AuthorService { 16 | private static final Function MAPPER = a -> Author.builder() 17 | .id(a.id().toString()) 18 | .name(a.name()) 19 | .email(a.email()) 20 | .createdAt(a.createdAt()) 21 | .build(); 22 | final AuthorRepository authors; 23 | 24 | public Future getAuthorById(String id) { 25 | var authorEntity = this.authors.findById(UUID.fromString(id)); 26 | return authorEntity.map(MAPPER); 27 | } 28 | 29 | public Future> getAuthorByIdIn(Collection ids) { 30 | var uuids = ids.stream().map(UUID::fromString).toList(); 31 | var authorEntities = this.authors.findByIdIn(uuids); 32 | return authorEntities.map( 33 | entities -> entities.stream().map(MAPPER).toList() 34 | ); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/resources/schema/schema.graphql: -------------------------------------------------------------------------------- 1 | directive @uppercase on FIELD_DEFINITION 2 | 3 | scalar LocalDateTime 4 | scalar UUID 5 | scalar Upload 6 | 7 | type Post { 8 | id: ID! 9 | title: String! @uppercase 10 | content: String 11 | comments: [Comment] 12 | status: PostStatus 13 | createdAt: LocalDateTime 14 | authorId: String 15 | author: Author 16 | } 17 | 18 | type Author { 19 | id: ID! 20 | name: String! 21 | email: String! 22 | createdAt: LocalDateTime 23 | posts: [Post] 24 | } 25 | type Comment { 26 | id: ID! 27 | content: String! 28 | createdAt: LocalDateTime 29 | postId: String! 30 | } 31 | 32 | input CreatePostInput { 33 | title: String! 34 | content: String! 35 | } 36 | 37 | input CommentInput { 38 | postId: String! 39 | content: String! 40 | } 41 | 42 | type Query { 43 | allPosts: [Post!]! 44 | postById(postId: String!): Post 45 | } 46 | 47 | type Mutation { 48 | createPost(createPostInput: CreatePostInput!): UUID! 49 | # upload is not available for websocket transport protocol 50 | #upload(file: Upload!): Boolean 51 | addComment(commentInput: CommentInput!): UUID! 52 | } 53 | 54 | type Subscription{ 55 | commentAdded: Comment! 56 | } 57 | 58 | enum PostStatus { 59 | DRAFT 60 | PENDING_MODERATION 61 | PUBLISHED 62 | } 63 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/service/AuthorService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.gql.types.Author; 4 | import com.example.demo.model.AuthorEntity; 5 | import com.example.demo.repository.AuthorRepository; 6 | import io.vertx.core.Future; 7 | import lombok.RequiredArgsConstructor; 8 | 9 | import java.util.Collection; 10 | import java.util.List; 11 | import java.util.UUID; 12 | import java.util.function.Function; 13 | 14 | @RequiredArgsConstructor 15 | public class AuthorService { 16 | private static final Function MAPPER = a -> Author.builder() 17 | .id(a.id().toString()) 18 | .name(a.name()) 19 | .email(a.email()) 20 | .createdAt(a.createdAt()) 21 | .build(); 22 | final AuthorRepository authors; 23 | 24 | public Future getAuthorById(String id) { 25 | var authorEntity = this.authors.findById(UUID.fromString(id)); 26 | return authorEntity.map(MAPPER); 27 | } 28 | 29 | public Future> getAuthorByIdIn(Collection ids) { 30 | var uuids = ids.stream().map(UUID::fromString).toList(); 31 | var authorEntities = this.authors.findByIdIn(uuids); 32 | return authorEntities.map( 33 | entities -> entities.stream().map(MAPPER).toList() 34 | ); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /kotlin-co/src/main/kotlin/com/example/demo/DataInitializer.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import io.vertx.kotlin.coroutines.coAwait 4 | import io.vertx.sqlclient.Pool 5 | import io.vertx.sqlclient.SqlConnection 6 | import io.vertx.sqlclient.Tuple 7 | import java.util.logging.Logger 8 | 9 | class DataInitializer(private val client: Pool) { 10 | 11 | suspend fun run() { 12 | LOGGER.info("Data initialization is starting...") 13 | val first = Tuple.of("Hello Vertx", "My first post of Vertx") 14 | val second = Tuple.of("Hello Again, Vertx", "My second post of Vertx") 15 | 16 | 17 | val result = client 18 | .withTransaction { conn: SqlConnection -> 19 | conn.query("DELETE FROM posts") 20 | .execute() 21 | .flatMap { 22 | conn.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)") 23 | .executeBatch(listOf(first, second)) 24 | } 25 | .flatMap { 26 | conn.query("SELECT * FROM posts") 27 | .execute() 28 | } 29 | 30 | } 31 | .coAwait() 32 | 33 | result.forEach { println(it.toJson()) } 34 | LOGGER.info("Data initialization is done...") 35 | } 36 | 37 | companion object { 38 | private val LOGGER = Logger.getLogger(DataInitializer::class.java.name) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.spi.VerticleFactory; 4 | import io.vertx.mutiny.core.Vertx; 5 | import org.hibernate.reactive.mutiny.Mutiny; 6 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.ComponentScan; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import jakarta.persistence.Persistence; 12 | 13 | @Configuration 14 | @ComponentScan 15 | public class DemoApplication { 16 | 17 | public static void main(String[] args) { 18 | var context = new AnnotationConfigApplicationContext(DemoApplication.class); 19 | var vertx = context.getBean(Vertx.class); 20 | var factory = context.getBean(VerticleFactory.class); 21 | 22 | // deploy MainVerticle via verticle identifier name 23 | vertx.deployVerticleAndAwait(factory.prefix() + ":" + MainVerticle.class.getName()); 24 | } 25 | 26 | @Bean 27 | public Vertx vertx(VerticleFactory verticleFactory) { 28 | Vertx vertx = Vertx.vertx(); 29 | vertx.registerVerticleFactory(verticleFactory); 30 | return vertx; 31 | } 32 | 33 | @Bean 34 | public Mutiny.SessionFactory sessionFactory() { 35 | return Persistence.createEntityManagerFactory("blogPU") 36 | .unwrap(Mutiny.SessionFactory.class); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/scalars/LocalDateTimeScalar.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.scalars; 2 | 3 | 4 | import graphql.language.StringValue; 5 | import graphql.schema.Coercing; 6 | import graphql.schema.CoercingParseLiteralException; 7 | import graphql.schema.CoercingParseValueException; 8 | import graphql.schema.CoercingSerializeException; 9 | 10 | import java.time.LocalDateTime; 11 | import java.time.format.DateTimeFormatter; 12 | 13 | 14 | public class LocalDateTimeScalar implements Coercing { 15 | @Override 16 | public String serialize(Object dataFetcherResult) throws CoercingSerializeException { 17 | if (dataFetcherResult instanceof LocalDateTime) { 18 | return ((LocalDateTime) dataFetcherResult).format(DateTimeFormatter.ISO_DATE_TIME); 19 | } else { 20 | throw new CoercingSerializeException("Not a valid DateTime"); 21 | } 22 | } 23 | 24 | @Override 25 | public LocalDateTime parseValue(Object input) throws CoercingParseValueException { 26 | return LocalDateTime.parse(input.toString(), DateTimeFormatter.ISO_DATE_TIME); 27 | } 28 | 29 | @Override 30 | public LocalDateTime parseLiteral(Object input) throws CoercingParseLiteralException { 31 | if (input instanceof StringValue) { 32 | return LocalDateTime.parse(((StringValue) input).getValue(), DateTimeFormatter.ISO_DATE_TIME); 33 | } 34 | 35 | throw new CoercingParseLiteralException("Value is not a valid ISO date time"); 36 | } 37 | } -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/SpringAwareVerticleFactory.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Deployable; 4 | import io.vertx.core.Promise; 5 | import io.vertx.core.Verticle; 6 | import io.vertx.core.VerticleBase; 7 | import io.vertx.core.spi.VerticleFactory; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.context.ApplicationContextAware; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.concurrent.Callable; 14 | 15 | // see: https://github.com/vert-x3/vertx-examples/blob/4.x/spring-examples/spring-verticle-factory/src/main/java/io/vertx/examples/spring/verticlefactory/SpringVerticleFactory.java 16 | @Component 17 | public class SpringAwareVerticleFactory implements VerticleFactory, ApplicationContextAware { 18 | 19 | private ApplicationContext applicationContext; 20 | 21 | @Override 22 | public String prefix() { 23 | return "spring"; 24 | } 25 | 26 | @Override 27 | public void createVerticle2(String verticleName, ClassLoader classLoader, Promise> promise) { 28 | String clazz = VerticleFactory.removePrefix(verticleName); 29 | promise.complete(() -> (VerticleBase) applicationContext.getBean(Class.forName(clazz))); 30 | } 31 | 32 | @Override 33 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 34 | this.applicationContext = applicationContext; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/scalars/LocalDateTimeScalar.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql.scalars; 2 | 3 | 4 | import graphql.language.StringValue; 5 | import graphql.schema.Coercing; 6 | import graphql.schema.CoercingParseLiteralException; 7 | import graphql.schema.CoercingParseValueException; 8 | import graphql.schema.CoercingSerializeException; 9 | 10 | import java.time.LocalDateTime; 11 | import java.time.format.DateTimeFormatter; 12 | 13 | 14 | public class LocalDateTimeScalar implements Coercing { 15 | @Override 16 | public String serialize(Object dataFetcherResult) throws CoercingSerializeException { 17 | if (dataFetcherResult instanceof LocalDateTime) { 18 | return ((LocalDateTime) dataFetcherResult).format(DateTimeFormatter.ISO_DATE_TIME); 19 | } else { 20 | throw new CoercingSerializeException("Not a valid DateTime"); 21 | } 22 | } 23 | 24 | @Override 25 | public LocalDateTime parseValue(Object input) throws CoercingParseValueException { 26 | return LocalDateTime.parse(input.toString(), DateTimeFormatter.ISO_DATE_TIME); 27 | } 28 | 29 | @Override 30 | public LocalDateTime parseLiteral(Object input) throws CoercingParseLiteralException { 31 | if (input instanceof StringValue) { 32 | return LocalDateTime.parse(((StringValue) input).getValue(), DateTimeFormatter.ISO_DATE_TIME); 33 | } 34 | 35 | throw new CoercingParseLiteralException("Value is not a valid ISO date time"); 36 | } 37 | } -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/main/java/com/example/demo/SpringAwareVerticleFactory.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.smallrye.mutiny.vertx.core.AbstractVerticle; 4 | import io.vertx.core.Deployable; 5 | import io.vertx.core.Promise; 6 | import io.vertx.core.VerticleBase; 7 | import io.vertx.core.spi.VerticleFactory; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.context.ApplicationContextAware; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.concurrent.Callable; 14 | 15 | // see: https://github.com/vert-x3/vertx-examples/blob/4.x/spring-examples/spring-verticle-factory/src/main/java/io/vertx/examples/spring/verticlefactory/SpringVerticleFactory.java 16 | @Component 17 | public class SpringAwareVerticleFactory implements VerticleFactory, ApplicationContextAware { 18 | 19 | private ApplicationContext applicationContext; 20 | 21 | @Override 22 | public String prefix() { 23 | return "spring"; 24 | } 25 | 26 | @Override 27 | public void createVerticle2(String verticleName, ClassLoader classLoader, Promise> promise) { 28 | String clazz = VerticleFactory.removePrefix(verticleName); 29 | promise.complete(() -> (AbstractVerticle) applicationContext.getBean(Class.forName(clazz))); 30 | } 31 | 32 | @Override 33 | public void setApplicationContext(ApplicationContext appContext) throws BeansException { 34 | this.applicationContext = appContext; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | org.hibernate.reactive.provider.ReactivePersistenceProvider 8 | com.example.demo.Post 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 19 | 21 | 22 | 23 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /rxjava3/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | %green(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{10}): %msg%n%throwable 11 | 12 | 13 | 14 | 15 | 17 | ${LOGS}/app.log 18 | 20 | %d %p %C [%t] %m%n 21 | 22 | 23 | 25 | 26 | ${LOGS}/logs/app-%d{yyyy-MM-dd}.%i.log 27 | 28 | 30 | 10MB 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/Resources.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.core.spi.VerticleFactory; 5 | import io.vertx.pgclient.PgBuilder; 6 | import io.vertx.pgclient.PgConnectOptions; 7 | import io.vertx.sqlclient.Pool; 8 | import io.vertx.sqlclient.PoolOptions; 9 | import jakarta.enterprise.context.ApplicationScoped; 10 | import jakarta.enterprise.inject.Disposes; 11 | import jakarta.enterprise.inject.Produces; 12 | import jakarta.inject.Singleton; 13 | 14 | import java.util.logging.Logger; 15 | 16 | @ApplicationScoped 17 | public class Resources { 18 | private final static Logger LOGGER = Logger.getLogger(Resources.class.getName()); 19 | 20 | @Produces 21 | @Singleton 22 | public Vertx vertx(VerticleFactory verticleFactory) { 23 | Vertx vertx = Vertx.vertx(); 24 | vertx.registerVerticleFactory(verticleFactory); 25 | return vertx; 26 | } 27 | 28 | @Produces 29 | public Pool pgPool(Vertx vertx) { 30 | PgConnectOptions connectOptions = new PgConnectOptions() 31 | .setPort(5432) 32 | .setHost("localhost") 33 | .setDatabase("blogdb") 34 | .setUser("user") 35 | .setPassword("password"); 36 | 37 | // Pool Options 38 | PoolOptions poolOptions = new PoolOptions().setMaxSize(5); 39 | 40 | // Create the pool from the data object 41 | return PgBuilder.pool() 42 | .with(poolOptions) 43 | .connectingTo(connectOptions) 44 | .using(vertx) 45 | .build(); 46 | } 47 | 48 | public void disposesPgPool(@Disposes Pool pgPool) { 49 | LOGGER.info("disposing PgPool..."); 50 | pgPool.close().onSuccess(v -> LOGGER.info("PgPool is closed successfully.")); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/kotlin-co.yml: -------------------------------------------------------------------------------- 1 | cache: 'maven'name: kotlin-co 2 | 3 | on: 4 | push: 5 | paths: 6 | - "kotlin-co/**" 7 | branches: 8 | - master 9 | pull_request: 10 | paths: 11 | - "kotlin-co/**" 12 | types: 13 | - opened 14 | - synchronize 15 | - reopened 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | - name: Set up Java 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: 'zulu' 26 | java-version: '21' 27 | cache: 'maven' 28 | 29 | - name: Start up databases via Docker Compose 30 | run: | 31 | docker compose up -d postgres 32 | docker ps -a 33 | - name: Build kotlin-co 34 | run: mvn clean install --file kotlin-co/pom.xml 35 | # automerge: 36 | # name: Merge pull request 37 | # runs-on: ubuntu-latest 38 | # needs: [build] 39 | # if: > 40 | # github.event_name == 'pull_request' && 41 | # github.event.pull_request.draft == false && ( 42 | # github.event.action == 'opened' || 43 | # github.event.action == 'reopened' || 44 | # github.event.action == 'synchronize' 45 | # ) && ( 46 | # github.actor == 'dependabot[bot]' 47 | # ) 48 | # steps: 49 | # - name: Merge 50 | # uses: actions/github-script@v4.0.2 51 | # with: 52 | # script: | 53 | # const pullRequest = context.payload.pull_request 54 | # const repository = context.repo 55 | 56 | # await github.pulls.merge({ 57 | # merge_method: "merge", 58 | # owner: repository.owner, 59 | # pull_number: pullRequest.number, 60 | # repo: repository.repo, 61 | # }) 62 | # github-token: ${{env.REPO_TOKEN}} 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vertx Sandbox 2 | 3 | Eclipse Vertx playground 4 | 5 | 6 | ## Notes 7 | 8 | Read it online: [https://hantsy.github.io/vertx-sandbox/](https://hantsy.github.io/vertx-sandbox/) 9 | 10 | ## Sample Codes 11 | | name | description | 12 | | :----------------------------------------------------------- | ------------------------------------------------------------ | 13 | | [web](https://github.com/hantsy/vertx-sandbox/tree/master/web)| Simple CRUD RESTful APIs with PgClient example| 14 | | [spring](https://github.com/hantsy/vertx-sandbox/tree/master/spring)| Spring integration example| 15 | | [cdi](https://github.com/hantsy/vertx-sandbox/tree/master/cdi)| Weld/CDI integration example| 16 | | [rxjava3](https://github.com/hantsy/vertx-sandbox/tree/master/rxjava3)| Simple CRUD RESTful APIs example but using RxJava3| 17 | | [mutiny-spring-hibernate](https://github.com/hantsy/vertx-sandbox/tree/master/mutiny-spring-hibernate)| Simple CRUD RESTful APIs example with SmallRye Mutiny bindings, Spring and Hibernate Reactive| 18 | | [kotlin](https://github.com/hantsy/vertx-sandbox/tree/master/kotlin)| Simple CRUD RESTful APIs example written in Kotlin| 19 | | [kotlin-co](https://github.com/hantsy/vertx-sandbox/tree/master/kotlin-co)| Simple CRUD RESTful APIs example written in Kotlin Coroutines| 20 | | [graphql-http](https://github.com/hantsy/vertx-sandbox/tree/master/graphql-http)| GraphQL example using HTTP protocol| 21 | | [graphql-transport-ws](https://github.com/hantsy/vertx-sandbox/tree/master/graphql-transport-ws)| GraphQL example using [GraphQL over WebSocket](https://github.com/enisdenjo/graphql-ws) protocol | 22 | 23 | 24 | ## Reference 25 | 26 | * [Vertx Documentation](https://vertx.io/docs/) 27 | * [Building Reactive Microservices in Java](https://developers.redhat.com/promotions/building-reactive-microservices-in-java) 28 | -------------------------------------------------------------------------------- /kotlin/src/main/kotlin/com/example/demo/DataInitializer.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import io.vertx.sqlclient.* 4 | import java.util.concurrent.CountDownLatch 5 | import java.util.concurrent.TimeUnit 6 | import java.util.logging.Level 7 | import java.util.logging.Logger 8 | import java.util.stream.StreamSupport 9 | 10 | class DataInitializer(private val client: Pool) { 11 | 12 | fun run() { 13 | LOGGER.info("Data initialization is starting...") 14 | val first = Tuple.of("Hello Quarkus", "My first post of Quarkus") 15 | val second = Tuple.of("Hello Again, Quarkus", "My second post of Quarkus") 16 | 17 | val latch = CountDownLatch(1) 18 | client 19 | .withTransaction { conn: SqlConnection -> 20 | conn.query("DELETE FROM posts").execute() 21 | .flatMap { 22 | conn.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)") 23 | .executeBatch(listOf(first, second)) 24 | } 25 | .flatMap { 26 | conn.query( 27 | "SELECT * FROM posts" 28 | ).execute() 29 | } 30 | } 31 | .onSuccess { data: RowSet -> 32 | StreamSupport.stream(data.spliterator(), true) 33 | .forEach { 34 | LOGGER.log(Level.INFO, "saved data:{0}", it!!.toJson()) 35 | } 36 | } 37 | .onComplete { 38 | LOGGER.info("Data initialization is completed...") 39 | latch.countDown() 40 | } 41 | .onFailure { LOGGER.warning("Data initialization is failed:" + it.message) } 42 | 43 | latch.await(1000, TimeUnit.MILLISECONDS) 44 | } 45 | 46 | companion object { 47 | private val LOGGER = Logger.getLogger(DataInitializer::class.java.name) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/main/java/com/example/demo/Post.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import jakarta.persistence.*; 4 | import org.hibernate.annotations.CreationTimestamp; 5 | 6 | import java.time.LocalDateTime; 7 | import java.util.Objects; 8 | import java.util.UUID; 9 | 10 | 11 | @Entity 12 | @Table(name = "posts") 13 | public class Post { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.UUID) 17 | UUID id; 18 | String title; 19 | String content; 20 | 21 | @Column(name = "created_at") 22 | @CreationTimestamp 23 | LocalDateTime createdAt = LocalDateTime.now(); 24 | 25 | public Post() { 26 | } 27 | 28 | public static Post of(String title, String content) { 29 | Post post = new Post(); 30 | post.title = title; 31 | post.content = content; 32 | return post; 33 | } 34 | 35 | public UUID getId() { 36 | return id; 37 | } 38 | 39 | public void setId(UUID id) { 40 | this.id = id; 41 | } 42 | 43 | public String getTitle() { 44 | return title; 45 | } 46 | 47 | public void setTitle(String title) { 48 | this.title = title; 49 | } 50 | 51 | public String getContent() { 52 | return content; 53 | } 54 | 55 | public void setContent(String content) { 56 | this.content = content; 57 | } 58 | 59 | public LocalDateTime getCreatedAt() { 60 | return createdAt; 61 | } 62 | 63 | public void setCreatedAt(LocalDateTime createdAt) { 64 | this.createdAt = createdAt; 65 | } 66 | 67 | @Override 68 | public boolean equals(Object o) { 69 | if (!(o instanceof Post post)) return false; 70 | return Objects.equals(title, post.title) && Objects.equals(content, post.content) && Objects.equals(createdAt, post.createdAt); 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | return Objects.hash(title, content, createdAt); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.core.spi.VerticleFactory; 5 | import io.vertx.pgclient.PgBuilder; 6 | import io.vertx.pgclient.PgConnectOptions; 7 | import io.vertx.sqlclient.Pool; 8 | import io.vertx.sqlclient.PoolOptions; 9 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.ComponentScan; 12 | import org.springframework.context.annotation.Configuration; 13 | 14 | @Configuration 15 | @ComponentScan 16 | public class DemoApplication { 17 | 18 | public static void main(String[] args) { 19 | var context = new AnnotationConfigApplicationContext(DemoApplication.class); 20 | var vertx = context.getBean(Vertx.class); 21 | var factory = context.getBean(VerticleFactory.class); 22 | 23 | // deploy MainVerticle via verticle identifier name 24 | vertx.deployVerticle(factory.prefix() + ":" + MainVerticle.class.getName()); 25 | } 26 | 27 | @Bean 28 | public Vertx vertx(VerticleFactory verticleFactory) { 29 | Vertx vertx = Vertx.vertx(); 30 | vertx.registerVerticleFactory(verticleFactory); 31 | return vertx; 32 | } 33 | 34 | @Bean 35 | public Pool pgPool(Vertx vertx) { 36 | PgConnectOptions connectOptions = new PgConnectOptions() 37 | .setPort(5432) 38 | .setHost("localhost") 39 | .setDatabase("blogdb") 40 | .setUser("user") 41 | .setPassword("password"); 42 | 43 | // Pool Options 44 | PoolOptions poolOptions = new PoolOptions().setMaxSize(5); 45 | 46 | // Create the pool from the data object 47 | return PgBuilder.pool() 48 | .with(poolOptions) 49 | .connectingTo(connectOptions) 50 | .using(vertx) 51 | .build(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /graphql-http/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | %green(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{10}): %msg%n%throwable 11 | 12 | 13 | 14 | 15 | 17 | ${LOGS}/app.log 18 | 20 | %d %p %C [%t] %m%n 21 | 22 | 23 | 25 | 26 | app-%d{yyyy-MM-dd}.%i.log 27 | 28 | 30 | 10MB 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/CustomDataFetchingExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql; 2 | 3 | import com.example.demo.repository.AuthorNotFoundException; 4 | import com.example.demo.repository.PostNotFoundException; 5 | import graphql.ErrorClassification; 6 | import graphql.GraphQLError; 7 | import graphql.GraphqlErrorBuilder; 8 | import graphql.execution.DataFetcherExceptionHandler; 9 | import graphql.execution.DataFetcherExceptionHandlerParameters; 10 | import graphql.execution.DataFetcherExceptionHandlerResult; 11 | import graphql.execution.SimpleDataFetcherExceptionHandler; 12 | import lombok.extern.slf4j.Slf4j; 13 | 14 | import java.util.concurrent.CompletableFuture; 15 | 16 | @Slf4j 17 | public class CustomDataFetchingExceptionHandler implements DataFetcherExceptionHandler { 18 | private final SimpleDataFetcherExceptionHandler defaultHandler = new SimpleDataFetcherExceptionHandler(); 19 | 20 | @Override 21 | public CompletableFuture handleException(DataFetcherExceptionHandlerParameters handlerParameters) { 22 | Throwable exception = handlerParameters.getException(); 23 | if (exception instanceof AuthorNotFoundException || exception instanceof PostNotFoundException) { 24 | log.debug("caught exception: {}", exception); 25 | enum MyErrorType implements ErrorClassification { 26 | NOT_FOUND 27 | } 28 | GraphQLError graphqlError = GraphqlErrorBuilder.newError() 29 | .message(exception.getMessage()) 30 | .errorType(MyErrorType.NOT_FOUND) 31 | .path(handlerParameters.getPath()) 32 | .build(); 33 | return CompletableFuture 34 | .completedFuture( 35 | DataFetcherExceptionHandlerResult.newResult() 36 | .error(graphqlError) 37 | .build() 38 | ); 39 | } else { 40 | return defaultHandler.handleException(handlerParameters); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/CustomDataFetchingExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql; 2 | 3 | import com.example.demo.repository.AuthorNotFoundException; 4 | import com.example.demo.repository.PostNotFoundException; 5 | import graphql.ErrorClassification; 6 | import graphql.GraphQLError; 7 | import graphql.GraphqlErrorBuilder; 8 | import graphql.execution.DataFetcherExceptionHandler; 9 | import graphql.execution.DataFetcherExceptionHandlerParameters; 10 | import graphql.execution.DataFetcherExceptionHandlerResult; 11 | import graphql.execution.SimpleDataFetcherExceptionHandler; 12 | import lombok.extern.slf4j.Slf4j; 13 | 14 | import java.util.concurrent.CompletableFuture; 15 | 16 | @Slf4j 17 | public class CustomDataFetchingExceptionHandler implements DataFetcherExceptionHandler { 18 | private final SimpleDataFetcherExceptionHandler defaultHandler = new SimpleDataFetcherExceptionHandler(); 19 | 20 | @Override 21 | public CompletableFuture handleException(DataFetcherExceptionHandlerParameters handlerParameters) { 22 | Throwable exception = handlerParameters.getException(); 23 | if (exception instanceof AuthorNotFoundException || exception instanceof PostNotFoundException) { 24 | log.debug("caught exception: {}", exception); 25 | enum TypedError implements ErrorClassification { 26 | NOT_FOUND 27 | } 28 | GraphQLError graphqlError = GraphqlErrorBuilder.newError() 29 | .message(exception.getMessage()) 30 | .errorType(TypedError.NOT_FOUND) 31 | .path(handlerParameters.getPath()) 32 | .build(); 33 | return CompletableFuture.completedFuture( 34 | DataFetcherExceptionHandlerResult.newResult() 35 | .error(graphqlError) 36 | .build() 37 | ); 38 | } else { 39 | return defaultHandler.handleException(handlerParameters); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/main/java/com/example/demo/DataInitializer.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | 4 | import org.hibernate.reactive.mutiny.Mutiny; 5 | import org.springframework.context.event.ContextRefreshedEvent; 6 | import org.springframework.context.event.EventListener; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.concurrent.CountDownLatch; 10 | import java.util.concurrent.TimeUnit; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | 14 | @Component 15 | public class DataInitializer { 16 | 17 | private final static Logger LOGGER = Logger.getLogger(DataInitializer.class.getName()); 18 | 19 | private final Mutiny.SessionFactory sessionFactory; 20 | 21 | public DataInitializer(Mutiny.SessionFactory sessionFactory) { 22 | this.sessionFactory = sessionFactory; 23 | } 24 | 25 | @EventListener(ContextRefreshedEvent.class) 26 | public void run() throws InterruptedException { 27 | LOGGER.info("Data initialization is starting..."); 28 | 29 | Post first = Post.of("Hello Quarkus", "My first post of Quarkus"); 30 | Post second = Post.of("Hello Again, Quarkus", "My second post of Quarkus"); 31 | 32 | var latch = new CountDownLatch(1); 33 | sessionFactory 34 | .withTransaction( 35 | (conn, tx) -> conn.createMutationQuery("DELETE FROM Post").executeUpdate() 36 | .flatMap(r -> conn.persistAll(first, second)) 37 | .chain(conn::flush) 38 | .flatMap(r -> conn.createSelectionQuery("SELECT p from Post p", Post.class).getResultList()) 39 | ) 40 | .onTermination().invoke(latch::countDown) 41 | .subscribe() 42 | .with( 43 | data -> LOGGER.log(Level.INFO, "saved data:{0}", data), 44 | throwable -> LOGGER.warning("Data initialization is failed:" + throwable.getMessage()) 45 | ); 46 | 47 | latch.await(500, TimeUnit.MILLISECONDS); 48 | LOGGER.log(Level.INFO, "Data initialization done."); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | %green(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{10}): %msg%n%throwable 11 | 12 | 13 | 14 | 15 | 17 | ${LOGS}/app.log 18 | 20 | %d %p %C [%t] %m%n 21 | 22 | 23 | 25 | 26 | app-%d{yyyy-MM-dd}.%i.log 27 | 28 | 30 | 10MB 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/DataInitializer.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | 4 | import io.vertx.sqlclient.Pool; 5 | import io.vertx.sqlclient.Tuple; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.SneakyThrows; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import java.util.List; 11 | import java.util.concurrent.CountDownLatch; 12 | import java.util.concurrent.TimeUnit; 13 | import java.util.logging.Level; 14 | import java.util.stream.StreamSupport; 15 | 16 | @Slf4j 17 | @RequiredArgsConstructor 18 | public class DataInitializer { 19 | private final Pool client; 20 | 21 | 22 | public static DataInitializer create(Pool client) { 23 | return new DataInitializer(client); 24 | } 25 | 26 | @SneakyThrows 27 | public void run() { 28 | log.info("Data initialization is starting..."); 29 | 30 | Tuple first = Tuple.of("Hello Vertx", "My first post of Vertx"); 31 | Tuple second = Tuple.of("Hello Again, Vertx", "My second post of Vertx"); 32 | 33 | var latch = new CountDownLatch(1); 34 | client 35 | .withTransaction( 36 | conn -> conn.query("DELETE FROM posts").execute() 37 | .flatMap(r -> conn.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)") 38 | .executeBatch(List.of(first, second)) 39 | ) 40 | .flatMap(r -> conn.query("SELECT * FROM posts").execute()) 41 | ) 42 | .onSuccess(data -> StreamSupport.stream(data.spliterator(), true) 43 | .forEach(row -> log.info("saved data:{}", new Object[]{row.toJson()})) 44 | ) 45 | .onComplete( 46 | r -> { 47 | log.info("Data initialization is complete..."); 48 | latch.countDown(); 49 | } 50 | ) 51 | .onFailure( 52 | throwable -> log.debug("Data initialization is failed:{}", throwable.getMessage()) 53 | ); 54 | 55 | latch.await(100, TimeUnit.MILLISECONDS); 56 | log.debug("Data initialization is done..."); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rxjava3/src/main/java/com/example/demo/DataInitializer.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.rxjava3.sqlclient.*; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.List; 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.TimeUnit; 10 | 11 | public class DataInitializer { 12 | private static final Logger log = LoggerFactory.getLogger(DataInitializer.class); 13 | 14 | private final Pool client; 15 | 16 | public DataInitializer(Pool client) { 17 | this.client = client; 18 | } 19 | 20 | public static DataInitializer create(Pool client) { 21 | return new DataInitializer(client); 22 | } 23 | 24 | public void run() { 25 | log.info("Data initialization is starting..."); 26 | 27 | Tuple first = Tuple.of("Hello Vertx", "My first post of Vertx"); 28 | Tuple second = Tuple.of("Hello Again, Vertx", "My second post of Vertx"); 29 | 30 | var latch = new CountDownLatch(1); 31 | 32 | client 33 | .rxWithTransaction( 34 | (SqlConnection tx) -> tx.query("DELETE FROM posts").rxExecute() 35 | .flatMap(result -> tx.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)").rxExecuteBatch(List.of(first, second))) 36 | .toMaybe() 37 | ) 38 | .flatMapSingle(d -> client.query("SELECT * FROM posts").rxExecute()) 39 | .doOnTerminate(latch::countDown) 40 | .subscribe( 41 | (RowSet data) -> { 42 | data.forEach(row -> log.info("saved row: {}", row.toJson())); 43 | log.debug("Data initialization is completed successfully..."); 44 | }, 45 | err -> { 46 | log.warn("failed to initializing: {}", err.getMessage()); 47 | } 48 | ); 49 | 50 | try { 51 | latch.await(1000, TimeUnit.MILLISECONDS); 52 | log.info("Data initialization is done..."); 53 | } catch (InterruptedException e) { 54 | throw new RuntimeException(e); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/gql/DataLoaders.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql; 2 | 3 | import com.example.demo.gql.types.Author; 4 | import com.example.demo.gql.types.Comment; 5 | import com.example.demo.service.AuthorService; 6 | import com.example.demo.service.PostService; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.dataloader.*; 10 | 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | 16 | @Slf4j 17 | @RequiredArgsConstructor 18 | public class DataLoaders { 19 | final AuthorService authorService; 20 | final PostService postService; 21 | 22 | public DataLoader authorsLoader() { 23 | BatchLoaderWithContext batchLoader = (List keys, BatchLoaderEnvironment environment) -> 24 | authorService.getAuthorByIdIn(keys).toCompletionStage(); 25 | 26 | return DataLoaderFactory.newDataLoader(batchLoader); 27 | } 28 | 29 | public DataLoader> commentsLoader() { 30 | MappedBatchLoaderWithContext> batchLoader = (Set keys, BatchLoaderEnvironment environment) -> 31 | postService.getCommentsByPostIdIn(keys) 32 | .map( 33 | comments -> { 34 | log.info("comments of post: {}", comments); 35 | Map> mappedComments = new HashMap<>(); 36 | keys.forEach( 37 | k -> mappedComments.put(k, comments 38 | .stream() 39 | .filter(c -> c.getPostId().equals(k)).toList()) 40 | ); 41 | log.info("mapped comments: {}", mappedComments); 42 | return mappedComments; 43 | } 44 | ) 45 | .toCompletionStage(); 46 | return DataLoaderFactory.newMappedDataLoader(batchLoader); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /kotlin-co/src/test/kotlin/com/example/demo/TestMainVerticle.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference 4 | import io.kotest.matchers.equals.shouldBeEqual 5 | import io.vertx.core.Vertx 6 | import io.vertx.core.json.jackson.DatabindCodec 7 | import io.vertx.ext.web.client.WebClient 8 | import io.vertx.ext.web.client.WebClientOptions 9 | import io.vertx.kotlin.coroutines.coAwait 10 | import kotlinx.coroutines.test.runTest 11 | import org.junit.jupiter.api.AfterEach 12 | import org.junit.jupiter.api.BeforeEach 13 | import org.junit.jupiter.api.Test 14 | import java.util.* 15 | import java.util.logging.Level 16 | import java.util.logging.Logger 17 | import kotlin.time.Duration.Companion.milliseconds 18 | 19 | // see: https://github.com/vietj/kotlin-conf-inter-reactive/blob/master/src/test/kotlin/com/julienviet/movierating/MovieRatingTest.kt 20 | class TestMainVerticle { 21 | companion object { 22 | private val LOGGER = Logger.getLogger(TestMainVerticle::class.java.name) 23 | } 24 | 25 | lateinit var vertx: Vertx 26 | lateinit var client: WebClient 27 | 28 | @BeforeEach 29 | fun setUp() = runTest { 30 | vertx = Vertx.vertx() 31 | client = WebClient.create(vertx, WebClientOptions().setDefaultPort(8888)) 32 | 33 | vertx.deployVerticle(MainVerticle()) 34 | .onComplete { 35 | LOGGER.log(Level.INFO, "Deployed MainVerticle: $it") 36 | } 37 | .coAwait() 38 | } 39 | 40 | @AfterEach 41 | fun tearDown() { 42 | vertx.close() 43 | } 44 | 45 | @Test 46 | fun `get all posts`() = runTest { 47 | val response = client.get("/posts").send().coAwait() 48 | response.statusCode() shouldBeEqual 200 49 | LOGGER.info("response :${response.bodyAsString()}") 50 | val body = response.bodyAsString() 51 | val posts: List = DatabindCodec.mapper().readValue(body, object : TypeReference>() {}) 52 | LOGGER.info("posts: ${posts}") 53 | //posts.size() shouldBeEqual 2 54 | } 55 | 56 | @Test 57 | fun `get post by none-existing id`() = runTest(timeout = 500.milliseconds) { 58 | val id = UUID.randomUUID() 59 | val response = client.get("/posts/$id").send().coAwait() 60 | response.statusCode() shouldBeEqual 404 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/DataInitializer.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | 4 | import io.vertx.sqlclient.Pool; 5 | import io.vertx.sqlclient.Tuple; 6 | import org.springframework.context.event.ContextRefreshedEvent; 7 | import org.springframework.context.event.EventListener; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.util.List; 11 | import java.util.concurrent.CountDownLatch; 12 | import java.util.concurrent.TimeUnit; 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | import java.util.stream.StreamSupport; 16 | 17 | @Component 18 | public class DataInitializer { 19 | 20 | private final static Logger LOGGER = Logger.getLogger(DataInitializer.class.getName()); 21 | 22 | private final Pool client; 23 | 24 | public DataInitializer(Pool client) { 25 | this.client = client; 26 | } 27 | 28 | @EventListener(ContextRefreshedEvent.class) 29 | public void run() throws Exception { 30 | LOGGER.info("Data initialization is starting..."); 31 | 32 | Tuple first = Tuple.of("Hello Quarkus", "My first post of Quarkus"); 33 | Tuple second = Tuple.of("Hello Again, Quarkus", "My second post of Quarkus"); 34 | 35 | var latch = new CountDownLatch(1); 36 | client 37 | .withTransaction( 38 | conn -> conn.query("DELETE FROM posts").execute() 39 | .flatMap(r -> conn.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)") 40 | .executeBatch(List.of(first, second)) 41 | ) 42 | .flatMap(r -> conn.query("SELECT * FROM posts").execute()) 43 | ) 44 | .onSuccess(data -> StreamSupport.stream(data.spliterator(), true) 45 | .forEach(row -> LOGGER.log(Level.INFO, "saved data:{0}", new Object[]{row.toJson()})) 46 | ) 47 | .onComplete( 48 | r -> { 49 | LOGGER.info("Data initialization is completed..."); 50 | latch.countDown(); 51 | } 52 | ) 53 | .onFailure( 54 | throwable -> LOGGER.warning("Data initialization is failed:" + throwable.getMessage()) 55 | ); 56 | 57 | latch.await(1000, TimeUnit.MILLISECONDS); 58 | LOGGER.log(Level.INFO, "Data initialization is done..."); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/repository/AuthorRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.model.AuthorEntity; 4 | import io.vertx.core.Future; 5 | import io.vertx.sqlclient.*; 6 | import lombok.RequiredArgsConstructor; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.UUID; 11 | import java.util.function.Function; 12 | import java.util.stream.StreamSupport; 13 | 14 | @RequiredArgsConstructor 15 | public class AuthorRepository { 16 | private static final Function MAPPER = (Row row) -> new AuthorEntity( 17 | row.getUUID("id"), 18 | row.getString("name"), 19 | row.getString("email"), 20 | row.getLocalDateTime("created_at") 21 | ); 22 | 23 | private final Pool client; 24 | 25 | public Future> findAll() { 26 | return client.query("SELECT * FROM users ORDER BY created_at DESC ") 27 | .execute() 28 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 29 | .map(MAPPER) 30 | .toList() 31 | ); 32 | } 33 | 34 | public Future deleteAll() { 35 | return client.query("DELETE FROM users").execute() 36 | .map(SqlResult::rowCount); 37 | } 38 | 39 | 40 | public Future findById(UUID id) { 41 | Objects.requireNonNull(id, "id can not be null"); 42 | return client.preparedQuery("SELECT * FROM users WHERE id=$1").execute(Tuple.of(id)) 43 | .map(RowSet::iterator) 44 | .map(iterator -> { 45 | if (iterator.hasNext()) return MAPPER.apply(iterator.next()); 46 | throw new AuthorNotFoundException(id); 47 | }); 48 | } 49 | 50 | 51 | public Future> findByIdIn(List uuids) { 52 | return client.preparedQuery("SELECT * FROM users WHERE id = any($1)").execute(Tuple.of(uuids.toArray(new UUID[0]))) 53 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 54 | .map(MAPPER) 55 | .toList() 56 | ); 57 | } 58 | 59 | public Future create(String name, String email) { 60 | return client.preparedQuery("INSERT INTO users(name, email) VALUES ($1, $2) RETURNING (id)") 61 | .execute(Tuple.of(name, email)) 62 | .map(rs -> rs.iterator().next().getUUID("id")); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/demo/DataInitializer.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | 4 | import io.vertx.sqlclient.Pool; 5 | import io.vertx.sqlclient.Tuple; 6 | 7 | import java.util.List; 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.logging.Level; 11 | import java.util.logging.Logger; 12 | import java.util.stream.StreamSupport; 13 | 14 | public class DataInitializer { 15 | 16 | private final static Logger LOGGER = Logger.getLogger(DataInitializer.class.getName()); 17 | 18 | private final Pool client; 19 | 20 | public DataInitializer(Pool client) { 21 | this.client = client; 22 | } 23 | 24 | public static DataInitializer create(Pool client) { 25 | return new DataInitializer(client); 26 | } 27 | 28 | public void run() throws InterruptedException { 29 | LOGGER.info("Data initialization is starting..."); 30 | 31 | Tuple first = Tuple.of("Hello Quarkus", "My first post of Quarkus"); 32 | Tuple second = Tuple.of("Hello Again, Quarkus", "My second post of Quarkus"); 33 | 34 | CountDownLatch latch = new CountDownLatch(1); 35 | client 36 | .withTransaction( 37 | conn -> conn.query("DELETE FROM posts").execute() 38 | .flatMap(r -> conn.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)") 39 | .executeBatch(List.of(first, second)) 40 | ) 41 | .flatMap(r -> conn.query("SELECT * FROM posts").execute()) 42 | ) 43 | .onSuccess(data -> { 44 | StreamSupport.stream(data.spliterator(), true) 45 | .forEach(row -> LOGGER.log(Level.INFO, "saved data:{0}", new Object[]{row.toJson()})); 46 | LOGGER.info("Data initialization is done sucessfully..."); 47 | latch.countDown(); 48 | } 49 | ) 50 | .onComplete( 51 | data -> { 52 | LOGGER.info("Data initialization is completed..."); 53 | } 54 | ) 55 | .onFailure( 56 | throwable -> { 57 | latch.countDown(); 58 | LOGGER.warning("Data initialization is failed:" + throwable.getMessage()); 59 | } 60 | ); 61 | 62 | latch.await(5000, TimeUnit.MICROSECONDS); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/DataInitializer.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.sqlclient.Pool; 4 | import io.vertx.sqlclient.Tuple; 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | import jakarta.enterprise.context.Initialized; 7 | import jakarta.enterprise.event.Observes; 8 | import jakarta.inject.Inject; 9 | 10 | import java.util.List; 11 | import java.util.concurrent.CountDownLatch; 12 | import java.util.concurrent.TimeUnit; 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | import java.util.stream.StreamSupport; 16 | 17 | @ApplicationScoped 18 | public class DataInitializer { 19 | 20 | private final static Logger LOGGER = Logger.getLogger(DataInitializer.class.getName()); 21 | 22 | private Pool client; 23 | 24 | public DataInitializer() { 25 | } 26 | 27 | @Inject 28 | public DataInitializer(Pool client) { 29 | this.client = client; 30 | } 31 | 32 | public void run(@Observes @Initialized(ApplicationScoped.class) Object o) throws InterruptedException { 33 | LOGGER.info("Data initialization is starting..."); 34 | 35 | Tuple first = Tuple.of("Hello Quarkus", "My first post of Quarkus"); 36 | Tuple second = Tuple.of("Hello Again, Quarkus", "My second post of Quarkus"); 37 | 38 | var latch = new CountDownLatch(1); 39 | client 40 | .withTransaction( 41 | conn -> conn.query("DELETE FROM posts").execute() 42 | .flatMap(r -> conn.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)") 43 | .executeBatch(List.of(first, second)) 44 | ) 45 | .flatMap(r -> conn.query("SELECT * FROM posts").execute()) 46 | ) 47 | .onSuccess(data -> StreamSupport.stream(data.spliterator(), true) 48 | .forEach(row -> LOGGER.log(Level.INFO, "saved data:{0}", new Object[]{row.toJson()})) 49 | ) 50 | .onComplete( 51 | r -> { 52 | LOGGER.info("Data initialization is completed..."); 53 | latch.countDown(); 54 | } 55 | ) 56 | .onFailure( 57 | throwable -> LOGGER.warning("Data initialization is failed:" + throwable.getMessage()) 58 | ); 59 | 60 | latch.await(1000, TimeUnit.MILLISECONDS); 61 | LOGGER.log(Level.INFO, "Data initialization is done..."); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/gql/DataLoaders.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.gql; 2 | 3 | import com.example.demo.gql.types.Author; 4 | import com.example.demo.gql.types.Comment; 5 | import com.example.demo.service.AuthorService; 6 | import com.example.demo.service.PostService; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.dataloader.*; 10 | 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | import java.util.concurrent.CompletionStage; 16 | 17 | @Slf4j 18 | @RequiredArgsConstructor 19 | public class DataLoaders { 20 | final AuthorService authorService; 21 | final PostService postService; 22 | 23 | public DataLoader authorsLoader() { 24 | var batchLoader = new BatchLoaderWithContext() { 25 | @Override 26 | public CompletionStage> load(List keys, BatchLoaderEnvironment batchLoaderEnvironment) { 27 | return authorService.getAuthorByIdIn(keys).toCompletionStage(); 28 | } 29 | }; 30 | 31 | return DataLoaderFactory.newDataLoader(batchLoader); 32 | } 33 | 34 | public DataLoader> commentsLoader() { 35 | var batchLoader = new MappedBatchLoaderWithContext>() { 36 | @Override 37 | public CompletionStage>> load( 38 | Set keys, 39 | BatchLoaderEnvironment batchLoaderEnvironment 40 | ) { 41 | return postService.getCommentsByPostIdIn(keys) 42 | .map( 43 | comments -> { 44 | log.info("comments of post: {}", comments); 45 | Map> mappedComments = new HashMap<>(); 46 | keys.forEach( 47 | k -> mappedComments.put(k, comments 48 | .stream() 49 | .filter(c -> c.getPostId().equals(k)).toList()) 50 | ); 51 | log.info("mapped comments: {}", mappedComments); 52 | return mappedComments; 53 | } 54 | ) 55 | .toCompletionStage(); 56 | } 57 | }; 58 | return DataLoaderFactory.newMappedDataLoader(batchLoader); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/repository/AuthorRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.model.AuthorEntity; 4 | import io.vertx.core.Future; 5 | import io.vertx.sqlclient.*; 6 | import lombok.RequiredArgsConstructor; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.UUID; 11 | import java.util.function.Function; 12 | import java.util.stream.StreamSupport; 13 | 14 | @RequiredArgsConstructor 15 | public class AuthorRepository { 16 | private static Function MAPPER = (row) -> new AuthorEntity( 17 | row.getUUID("id"), 18 | row.getString("name"), 19 | row.getString("email"), 20 | row.getLocalDateTime("created_at") 21 | ); 22 | 23 | private final Pool client; 24 | 25 | public Future> findAll() { 26 | return client.query("SELECT * FROM users ORDER BY created_at DESC ") 27 | .execute() 28 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 29 | .map(MAPPER) 30 | .toList() 31 | ); 32 | } 33 | 34 | public Future deleteAll() { 35 | return client.query("DELETE FROM users").execute() 36 | .map(SqlResult::rowCount); 37 | } 38 | 39 | 40 | public Future findById(UUID id) { 41 | Objects.requireNonNull(id, "id can not be null"); 42 | return client.preparedQuery("SELECT * FROM users WHERE id=$1").execute(Tuple.of(id)) 43 | .map(RowSet::iterator) 44 | .map(iterator -> { 45 | if (iterator.hasNext()) return MAPPER.apply(iterator.next()); 46 | throw new AuthorNotFoundException(id); 47 | }); 48 | } 49 | 50 | 51 | public Future> findByIdIn(List uuids) { 52 | return client.preparedQuery("SELECT * FROM users WHERE id = any($1)").execute(Tuple.of(uuids.toArray(new UUID[0]))) 53 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 54 | .map(MAPPER) 55 | .toList() 56 | ); 57 | } 58 | 59 | public Future create(String name, String email) { 60 | return client.preparedQuery("INSERT INTO users(name, email) VALUES ($1, $2) RETURNING (id)") 61 | .execute(Tuple.of(name, email)) 62 | .map(rs -> rs.iterator().next().getUUID("id")); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/repository/CommentRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.model.CommentEntity; 4 | import io.vertx.core.Future; 5 | import io.vertx.sqlclient.*; 6 | import lombok.RequiredArgsConstructor; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.UUID; 11 | import java.util.function.Function; 12 | import java.util.stream.StreamSupport; 13 | 14 | @RequiredArgsConstructor 15 | public class CommentRepository { 16 | private static Function MAPPER = (row) -> new CommentEntity( 17 | row.getUUID("id"), 18 | row.getString("content"), 19 | row.getLocalDateTime("created_at"), 20 | row.getUUID("post_id") 21 | ); 22 | 23 | private final Pool client; 24 | 25 | public Future> findAll() { 26 | return client.query("SELECT * FROM comments ORDER BY created_at DESC ") 27 | .execute() 28 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 29 | .map(MAPPER) 30 | .toList() 31 | ); 32 | } 33 | 34 | public Future findById(UUID id) { 35 | Objects.requireNonNull(id, "id can not be null"); 36 | return client.preparedQuery("SELECT * FROM comments WHERE id=$1").execute(Tuple.of(id)) 37 | .map(RowSet::iterator) 38 | .map(iterator -> { 39 | if (iterator.hasNext()) return MAPPER.apply(iterator.next()); 40 | throw new CommentNotFoundException(id); 41 | }); 42 | } 43 | 44 | public Future deleteAll() { 45 | return client.query("DELETE FROM comments").execute() 46 | .map(SqlResult::rowCount); 47 | } 48 | 49 | 50 | public Future> findByPostIdIn(List uuids) { 51 | return client.preparedQuery("SELECT * FROM comments WHERE post_id = any($1)").execute(Tuple.of(uuids.toArray(new UUID[0]))) 52 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 53 | .map(MAPPER) 54 | .toList() 55 | ); 56 | } 57 | 58 | public Future> findByPostId(UUID id) { 59 | return client.preparedQuery("SELECT * FROM comments WHERE post_id=$1").execute(Tuple.of(id)) 60 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 61 | .map(MAPPER) 62 | .toList() 63 | ); 64 | } 65 | 66 | public Future create(String content, UUID postId) { 67 | return client.preparedQuery("INSERT INTO comments(content, post_id) VALUES ($1, $2) RETURNING (id)") 68 | .execute(Tuple.of(content, postId)) 69 | .map(rs -> rs.iterator().next().getUUID("id")); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/repository/CommentRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.model.CommentEntity; 4 | import io.vertx.core.Future; 5 | import io.vertx.sqlclient.*; 6 | import lombok.RequiredArgsConstructor; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.UUID; 11 | import java.util.function.Function; 12 | import java.util.stream.StreamSupport; 13 | 14 | @RequiredArgsConstructor 15 | public class CommentRepository { 16 | private static Function MAPPER = (row) -> new CommentEntity( 17 | row.getUUID("id"), 18 | row.getString("content"), 19 | row.getLocalDateTime("created_at"), 20 | row.getUUID("post_id") 21 | ); 22 | 23 | private final Pool client; 24 | 25 | public Future> findAll() { 26 | return client.query("SELECT * FROM comments ORDER BY created_at DESC ") 27 | .execute() 28 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 29 | .map(MAPPER) 30 | .toList() 31 | ); 32 | } 33 | 34 | public Future findById(UUID id) { 35 | Objects.requireNonNull(id, "id can not be null"); 36 | return client.preparedQuery("SELECT * FROM comments WHERE id=$1").execute(Tuple.of(id)) 37 | .map(RowSet::iterator) 38 | .map(iterator -> { 39 | if (iterator.hasNext()) return MAPPER.apply(iterator.next()); 40 | throw new CommentNotFoundException(id); 41 | }); 42 | } 43 | 44 | public Future deleteAll() { 45 | return client.query("DELETE FROM comments").execute() 46 | .map(SqlResult::rowCount); 47 | } 48 | 49 | 50 | public Future> findByPostIdIn(List uuids) { 51 | return client.preparedQuery("SELECT * FROM comments WHERE post_id = any($1)").execute(Tuple.of(uuids.toArray(new UUID[0]))) 52 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 53 | .map(MAPPER) 54 | .toList() 55 | ); 56 | } 57 | 58 | public Future> findByPostId(UUID id) { 59 | return client.preparedQuery("SELECT * FROM comments WHERE post_id=$1").execute(Tuple.of(id)) 60 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 61 | .map(MAPPER) 62 | .toList() 63 | ); 64 | } 65 | 66 | public Future create(String content, UUID postId) { 67 | return client.preparedQuery("INSERT INTO comments(content, post_id) VALUES ($1, $2) RETURNING (id)") 68 | .execute(Tuple.of(content, postId)) 69 | .map(rs -> rs.iterator().next().getUUID("id")); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/DataInitializer.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | 4 | import com.example.demo.gql.types.PostStatus; 5 | import com.example.demo.repository.AuthorRepository; 6 | import com.example.demo.repository.CommentRepository; 7 | import com.example.demo.repository.PostRepository; 8 | import io.vertx.core.Future; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.SneakyThrows; 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | import java.util.concurrent.CountDownLatch; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.stream.Stream; 16 | 17 | @Slf4j 18 | @RequiredArgsConstructor 19 | public class DataInitializer { 20 | final PostRepository posts; 21 | final CommentRepository comments; 22 | final AuthorRepository authors; 23 | 24 | @SneakyThrows 25 | public void run() { 26 | log.info("Data initialization is starting..."); 27 | 28 | CountDownLatch latch = new CountDownLatch(1); 29 | cleanData() 30 | .flatMap(it -> insertData()) 31 | .flatMap(it -> printData()) 32 | .onComplete(event -> { 33 | log.info("Data initialization is done."); 34 | latch.countDown(); 35 | }); 36 | var await = latch.await(5000, TimeUnit.MILLISECONDS); 37 | log.debug("awaited result: {}", await); 38 | } 39 | 40 | Future printData() { 41 | return Future.join( 42 | this.posts.findAll().onSuccess(p -> log.info("saved posts: {}", p)), 43 | this.comments.findAll().onSuccess(p -> log.info("saved comments: {}", p)), 44 | this.authors.findAll().onSuccess(p -> log.info("saved authors: {}", p)) 45 | ); 46 | } 47 | 48 | Future insertData() { 49 | return this.authors.create("user", "user@example.com") 50 | .flatMap( 51 | authorId -> { 52 | log.info("inserted user: {}", authorId); 53 | var insertPosts = Stream.of("Hello vertx", "Hello vertx again") 54 | .map(title -> this.posts.create(title, "test content of " + title, PostStatus.DRAFT.name(), authorId) 55 | .onSuccess(id -> log.debug("inserted post: {}", id)) 56 | ) 57 | .toList(); 58 | 59 | return Future.join(insertPosts); 60 | } 61 | ); 62 | } 63 | 64 | Future cleanData() { 65 | return Future.join( 66 | this.comments.deleteAll().onSuccess(event -> log.info("deleted comments: {}", event)), 67 | this.posts.deleteAll().onSuccess(event -> log.info("deleted posts: {}", event)), 68 | this.authors.deleteAll().onSuccess(event -> log.info("deleted users: {}", event)) 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /cdi/src/test/java/com/example/demo/TestMainVerticle.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.core.http.HttpClientOptions; 5 | import io.vertx.core.http.HttpClientResponse; 6 | import io.vertx.core.http.HttpMethod; 7 | import io.vertx.core.spi.VerticleFactory; 8 | import io.vertx.junit5.VertxExtension; 9 | import io.vertx.junit5.VertxTestContext; 10 | import jakarta.enterprise.inject.Instance; 11 | import jakarta.inject.Inject; 12 | import org.jboss.weld.junit5.ExplicitParamInjection; 13 | import org.jboss.weld.junit5.auto.AddPackages; 14 | import org.jboss.weld.junit5.auto.EnableAutoWeld; 15 | import org.junit.jupiter.api.BeforeAll; 16 | import org.junit.jupiter.api.Test; 17 | import org.junit.jupiter.api.TestInstance; 18 | import org.junit.jupiter.api.extension.ExtendWith; 19 | 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | import static org.assertj.core.api.Assertions.assertThat; 24 | 25 | @EnableAutoWeld 26 | @ExplicitParamInjection 27 | @AddPackages(DemoApplication.class) 28 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 29 | @ExtendWith(VertxExtension.class) 30 | public class TestMainVerticle { 31 | private static final Logger LOGGER = Logger.getLogger(TestMainVerticle.class.getName()); 32 | 33 | @Inject 34 | Instance context; 35 | 36 | Vertx vertx; 37 | 38 | @BeforeAll 39 | public void setupAll(VertxTestContext testContext) { 40 | vertx = context.select(Vertx.class).get(); 41 | var factory = context.select(VerticleFactory.class).get(); 42 | vertx.deployVerticle(factory.prefix() + ":" + MainVerticle.class.getName()) 43 | .onSuccess(id -> { 44 | LOGGER.info("deployed:" + id); 45 | testContext.completeNow(); 46 | }) 47 | .onFailure(testContext::failNow); 48 | } 49 | 50 | @Test 51 | public void testVertx(VertxTestContext testContext) { 52 | assertThat(vertx).isNotNull(); 53 | testContext.completeNow(); 54 | } 55 | 56 | 57 | @Test 58 | void testGetAll(VertxTestContext testContext) { 59 | LOGGER.log(Level.INFO, "running test: {0}", "testGetAll"); 60 | var options = new HttpClientOptions() 61 | .setDefaultPort(8888); 62 | var client = vertx.createHttpClient(options); 63 | 64 | client.request(HttpMethod.GET, "/posts") 65 | .flatMap(req -> req.send().flatMap(HttpClientResponse::body)) 66 | .onSuccess( 67 | buffer -> testContext.verify( 68 | () -> { 69 | LOGGER.log(Level.INFO, "response buffer: {0}", new Object[]{buffer.toString()}); 70 | assertThat(buffer.toJsonArray().size()).isGreaterThan(0); 71 | testContext.completeNow(); 72 | } 73 | ) 74 | ) 75 | .onFailure(e -> LOGGER.log(Level.ALL, "error: {0}", e.getMessage())); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /kotlin/src/main/kotlin/com/example/demo/PostRepository.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import io.vertx.core.Future 4 | import io.vertx.sqlclient.Pool 5 | import io.vertx.sqlclient.Row 6 | import io.vertx.sqlclient.RowSet 7 | import io.vertx.sqlclient.Tuple 8 | import java.util.* 9 | import java.util.logging.Logger 10 | import java.util.stream.StreamSupport 11 | 12 | class PostRepository(private val client: Pool) { 13 | 14 | fun findAll(): Future> { 15 | val sql = "SELECT * FROM posts ORDER BY id ASC" 16 | return client.query(sql) 17 | .execute() 18 | .map { rs: RowSet -> 19 | StreamSupport.stream(rs.spliterator(), false) 20 | .map { mapFun(it!!) } 21 | .toList() 22 | } 23 | } 24 | 25 | 26 | fun findById(id: UUID): Future { 27 | val sql = "SELECT * FROM posts WHERE id=$1" 28 | return client.preparedQuery(sql) 29 | .execute(Tuple.of(id)) 30 | .map { it.iterator() } 31 | .map { 32 | if (it.hasNext()) mapFun(it.next()); 33 | else throw PostNotFoundException(id) 34 | } 35 | } 36 | 37 | 38 | fun save(data: Post): Future { 39 | val sql = "INSERT INTO posts(title, content) VALUES ($1, $2) RETURNING (id)" 40 | return client.preparedQuery(sql) 41 | .execute(Tuple.of(data.title, data.content)) 42 | .map { it.iterator().next().getUUID("id") } 43 | } 44 | 45 | 46 | fun saveAll(data: List): Future { 47 | val tuples = data.map { Tuple.of(it.title, it.content) } 48 | 49 | val sql = "INSERT INTO posts (title, content) VALUES ($1, $2)" 50 | return client.preparedQuery(sql) 51 | .executeBatch(tuples) 52 | .map { it.rowCount() } 53 | } 54 | 55 | fun update(data: Post): Future { 56 | val sql = "UPDATE posts SET title=$1, content=$2 WHERE id=$3" 57 | return client.preparedQuery(sql) 58 | .execute(Tuple.of(data.title, data.content, data.id)) 59 | .map { it.rowCount() } 60 | } 61 | 62 | 63 | fun deleteAll(): Future { 64 | val sql = "DELETE FROM posts" 65 | return client.query(sql).execute() 66 | .map { it.rowCount() } 67 | } 68 | 69 | 70 | fun deleteById(id: UUID): Future { 71 | val sql = "DELETE FROM posts WHERE id=$1" 72 | return client.preparedQuery(sql).execute(Tuple.of(id)) 73 | .map { it.rowCount() } 74 | } 75 | 76 | companion object { 77 | private val LOGGER = Logger.getLogger(PostRepository::class.java.name) 78 | val mapFun: (Row) -> Post = { row: Row -> 79 | Post( 80 | row.getUUID("id"), 81 | row.getString("title"), 82 | row.getString("content"), 83 | row.getLocalDateTime("created_at") 84 | ) 85 | } 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /spring/src/test/java/com/example/demo/TestMainVerticle.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.core.http.HttpClientOptions; 5 | import io.vertx.core.http.HttpClientResponse; 6 | import io.vertx.core.http.HttpMethod; 7 | import io.vertx.core.spi.VerticleFactory; 8 | import io.vertx.junit5.VertxExtension; 9 | import io.vertx.junit5.VertxTestContext; 10 | import org.junit.jupiter.api.BeforeAll; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.TestInstance; 13 | import org.junit.jupiter.api.extension.ExtendWith; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.context.ApplicationContext; 16 | import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; 17 | 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import static org.assertj.core.api.Assertions.assertThat; 22 | 23 | @SpringJUnitConfig(classes = DemoApplication.class) 24 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 25 | @ExtendWith(VertxExtension.class) 26 | public class TestMainVerticle { 27 | private static final Logger LOGGER = Logger.getLogger(TestMainVerticle.class.getName()); 28 | 29 | @Autowired 30 | ApplicationContext context; 31 | 32 | Vertx vertx; 33 | 34 | @BeforeAll 35 | public void setupAll(VertxTestContext testContext) { 36 | vertx = context.getBean(Vertx.class); 37 | var factory = context.getBean(VerticleFactory.class); 38 | vertx.deployVerticle(factory.prefix() + ":" + MainVerticle.class.getName()) 39 | .onSuccess(id -> { 40 | LOGGER.info("deployed:" + id); 41 | testContext.completeNow(); 42 | }) 43 | .onFailure(testContext::failNow); 44 | } 45 | 46 | @Test 47 | public void testVertx(VertxTestContext testContext) { 48 | assertThat(vertx).isNotNull(); 49 | testContext.completeNow(); 50 | } 51 | 52 | 53 | @Test 54 | void testGetAll(VertxTestContext testContext) { 55 | LOGGER.log(Level.INFO, "running test: {0}", "testGetAll"); 56 | var options = new HttpClientOptions() 57 | .setDefaultPort(8888); 58 | var client = vertx.createHttpClient(options); 59 | 60 | client.request(HttpMethod.GET, "/posts") 61 | .flatMap(req -> req.send().flatMap(HttpClientResponse::body)) 62 | .onSuccess( 63 | buffer -> testContext.verify( 64 | () -> { 65 | LOGGER.log(Level.INFO, "response buffer: {0}", new Object[]{buffer.toString()}); 66 | assertThat(buffer.toJsonArray().size()).isGreaterThan(0); 67 | testContext.completeNow(); 68 | } 69 | ) 70 | ) 71 | .onFailure(e -> { 72 | LOGGER.log(Level.ALL, "error: {0}", e.getMessage()); 73 | testContext.failNow(e); 74 | }); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /kotlin/src/main/kotlin/com/example/demo/PostsHandler.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import io.vertx.core.json.Json 4 | import io.vertx.ext.web.RoutingContext 5 | import java.util.* 6 | import java.util.logging.Level 7 | import java.util.logging.Logger 8 | 9 | class PostsHandler(val posts: PostRepository) { 10 | fun all(rc: RoutingContext) { 11 | // var params = rc.queryParams(); 12 | // var q = params.get("q"); 13 | // var limit = params.get("limit") == null ? 10 : Integer.parseInt(params.get("q")); 14 | // var offset = params.get("offset") == null ? 0 : Integer.parseInt(params.get("offset")); 15 | // LOGGER.log(Level.INFO, " find by keyword: q={0}, limit={1}, offset={2}", new Object[]{q, limit, offset}); 16 | posts.findAll() 17 | .onSuccess { 18 | rc.response().end(Json.encode(it)) 19 | } 20 | 21 | } 22 | 23 | fun getById(rc: RoutingContext) { 24 | val params = rc.pathParams() 25 | val id = params["id"] 26 | posts.findById(UUID.fromString(id)) 27 | .onSuccess { rc.response().end(Json.encode(it)) } 28 | .onFailure { rc.fail(404, it) } 29 | } 30 | 31 | fun save(rc: RoutingContext) { 32 | //rc.getBodyAsJson().mapTo(PostForm.class) 33 | val body = rc.body().asJsonObject() 34 | LOGGER.log(Level.INFO, "request body: {0}", body) 35 | val (title, content) = body.mapTo(CreatePostCommand::class.java) 36 | posts.save(Post(title = title, content = content)) 37 | .onSuccess { savedId: UUID -> 38 | rc.response() 39 | .putHeader("Location", "/posts/$savedId") 40 | .setStatusCode(201) 41 | .end() 42 | } 43 | } 44 | 45 | fun update(rc: RoutingContext) { 46 | val params = rc.pathParams() 47 | val id = params["id"] 48 | val body = rc.body().asJsonObject() 49 | LOGGER.log(Level.INFO, "\npath param id: {0}\nrequest body: {1}", arrayOf(id, body)) 50 | val (title, content) = body.mapTo(CreatePostCommand::class.java) 51 | posts.findById(UUID.fromString(id)) 52 | .flatMap { post: Post -> 53 | post.apply { 54 | this.title = title 55 | this.content = content 56 | } 57 | posts.update(post) 58 | } 59 | .onSuccess { rc.response().setStatusCode(204).end() } 60 | .onFailure { rc.fail(it) } 61 | } 62 | 63 | fun delete(rc: RoutingContext) { 64 | val params = rc.pathParams() 65 | val id = params["id"] 66 | val uuid = UUID.fromString(id) 67 | posts.findById(uuid) 68 | .flatMap { posts.deleteById(uuid) } 69 | .onSuccess { rc.response().setStatusCode(204).end() } 70 | .onFailure { rc.fail(404, it) } 71 | } 72 | 73 | companion object { 74 | private val LOGGER = Logger.getLogger(PostsHandler::class.java.simpleName) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /kotlin-co/src/main/kotlin/com/example/demo/PostsHandler.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import io.vertx.core.json.Json 4 | import io.vertx.ext.web.RoutingContext 5 | import io.vertx.kotlin.coroutines.coAwait 6 | import java.util.* 7 | import java.util.logging.Level 8 | import java.util.logging.Logger 9 | 10 | class PostsHandler(private val posts: PostRepository) { 11 | companion object { 12 | private val LOGGER = Logger.getLogger(PostsHandler::class.java.name) 13 | } 14 | 15 | suspend fun all(rc: RoutingContext) { 16 | LOGGER.log(Level.ALL, "handling /posts endpoint") 17 | // var params = rc.queryParams(); 18 | // var q = params.get("q"); 19 | // var limit = params.get("limit") == null ? 10 : Integer.parseInt(params.get("q")); 20 | // var offset = params.get("offset") == null ? 0 : Integer.parseInt(params.get("offset")); 21 | // LOGGER.log(Level.INFO, " find by keyword: q={0}, limit={1}, offset={2}", new Object[]{q, limit, offset}); 22 | val data = posts.findAll() 23 | rc.response().end(Json.encode(data)).coAwait() 24 | } 25 | 26 | suspend fun getById(rc: RoutingContext) { 27 | val id = rc.pathParam("id") ?: throw IllegalArgumentException("Path param id is required") 28 | val uuid = UUID.fromString(id) 29 | val data = posts.findById(uuid) 30 | rc.response().end(Json.encode(data)).coAwait() 31 | } 32 | 33 | suspend fun save(rc: RoutingContext) { 34 | //rc.getBodyAsJson().mapTo(PostForm.class) 35 | val body = rc.body().asJsonObject() 36 | LOGGER.log(Level.INFO, "request body: {0}", body) 37 | val (title, content) = body.mapTo(CreatePostCommand::class.java) 38 | val savedId = posts.save(Post(title = title, content = content)) 39 | rc.response() 40 | .putHeader("Location", "/posts/$savedId") 41 | .setStatusCode(201) 42 | .end() 43 | .coAwait() 44 | } 45 | 46 | suspend fun update(rc: RoutingContext) { 47 | val id = rc.pathParam("id") ?: throw IllegalArgumentException("Path param id is required") 48 | val uuid = UUID.fromString(id) 49 | val body = rc.body().asJsonObject() 50 | LOGGER.log(Level.INFO, "\npath param id: {0}\nrequest body: {1}", arrayOf(id, body)) 51 | val (title, content) = body.mapTo(UpdatePostCommand::class.java) 52 | val existing: Post = posts.findById(uuid) 53 | val data: Post = existing.apply { 54 | this.title = title 55 | this.content = content 56 | } 57 | posts.update(data) 58 | rc.response().setStatusCode(204).end().coAwait() 59 | } 60 | 61 | suspend fun delete(rc: RoutingContext) { 62 | val id = rc.pathParam("id") ?: throw IllegalArgumentException("Path param id is required") 63 | val uuid = UUID.fromString(id) 64 | val existing = posts.deleteById(uuid) 65 | if (existing > 0) { 66 | rc.response().setStatusCode(204).end().coAwait() 67 | } else { 68 | rc.fail(404, PostNotFoundException(uuid)) 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /kotlin-co/src/main/kotlin/com/example/demo/PostRepository.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import io.vertx.kotlin.coroutines.coAwait 4 | import io.vertx.sqlclient.Pool 5 | import io.vertx.sqlclient.Row 6 | import io.vertx.sqlclient.RowSet 7 | import io.vertx.sqlclient.Tuple 8 | import java.util.* 9 | import java.util.logging.Logger 10 | import java.util.stream.StreamSupport 11 | 12 | class PostRepository(private val client: Pool) { 13 | 14 | suspend fun findAll(): List { 15 | val sql = "SELECT * FROM posts ORDER BY id ASC" 16 | return client.query(sql) 17 | .execute() 18 | .map { rs: RowSet -> 19 | StreamSupport.stream(rs.spliterator(), false) 20 | .map { MAPPER(it!!) } 21 | .toList() 22 | } 23 | .coAwait() 24 | } 25 | 26 | 27 | suspend fun findById(id: UUID): Post { 28 | val sql = "SELECT * FROM posts WHERE id=$1" 29 | return client.preparedQuery(sql) 30 | .execute(Tuple.of(id)) 31 | .map { it.iterator() } 32 | .map { if (it.hasNext()) MAPPER(it.next()) else throw PostNotFoundException(id) } 33 | .coAwait() 34 | } 35 | 36 | 37 | suspend fun save(data: Post): UUID? { 38 | val sql = "INSERT INTO posts(title, content) VALUES ($1, $2) RETURNING (id)" 39 | return client.preparedQuery(sql) 40 | .execute(Tuple.of(data.title, data.content)) 41 | .map { it.iterator().next().getUUID("id") } 42 | .coAwait() 43 | } 44 | 45 | 46 | suspend fun saveAll(data: List): Int? { 47 | val tuples = data.map { Tuple.of(it.title, it.content) } 48 | val sql = "INSERT INTO posts (title, content) VALUES ($1, $2)" 49 | return client.preparedQuery(sql) 50 | .executeBatch(tuples) 51 | .map { it.rowCount() } 52 | .coAwait() 53 | } 54 | 55 | suspend fun update(data: Post): Int? { 56 | val sql = "UPDATE posts SET title=$1, content=$2 WHERE id=$3" 57 | return client.preparedQuery(sql) 58 | .execute(Tuple.of(data.title, data.content, data.id)) 59 | .map { it.rowCount() } 60 | .coAwait() 61 | } 62 | 63 | 64 | suspend fun deleteAll(): Int? { 65 | val sql = "DELETE FROM posts" 66 | return client.query(sql).execute() 67 | .map { it.rowCount() } 68 | .coAwait() 69 | } 70 | 71 | 72 | suspend fun deleteById(id: UUID): Int { 73 | val sql = "DELETE FROM posts WHERE id=$1" 74 | return client.preparedQuery(sql).execute(Tuple.of(id)) 75 | .map { it.rowCount() } 76 | .coAwait() 77 | } 78 | 79 | companion object { 80 | private val LOGGER = Logger.getLogger(PostRepository::class.java.name) 81 | val MAPPER: (Row) -> Post = { row: Row -> 82 | Post( 83 | row.getUUID("id"), 84 | row.getString("title"), 85 | row.getString("content"), 86 | row.getLocalDateTime("created_at") 87 | ) 88 | } 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /mutiny-spring-hibernate/src/test/java/com/example/demo/TestMainVerticle.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.http.HttpClientOptions; 4 | import io.vertx.core.http.HttpMethod; 5 | import io.vertx.core.spi.VerticleFactory; 6 | import io.vertx.junit5.VertxExtension; 7 | import io.vertx.junit5.VertxTestContext; 8 | import io.vertx.mutiny.core.Vertx; 9 | import io.vertx.mutiny.core.http.HttpClientRequest; 10 | import io.vertx.mutiny.core.http.HttpClientResponse; 11 | import org.junit.jupiter.api.BeforeAll; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.TestInstance; 14 | import org.junit.jupiter.api.extension.ExtendWith; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.context.ApplicationContext; 17 | import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; 18 | 19 | import java.util.logging.Level; 20 | import java.util.logging.Logger; 21 | 22 | import static org.assertj.core.api.Assertions.assertThat; 23 | 24 | @SpringJUnitConfig(classes = DemoApplication.class) 25 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 26 | @ExtendWith(VertxExtension.class) 27 | public class TestMainVerticle { 28 | private static final Logger LOGGER = Logger.getLogger(TestMainVerticle.class.getName()); 29 | 30 | @Autowired 31 | ApplicationContext context; 32 | 33 | Vertx vertx; 34 | 35 | @BeforeAll 36 | public void setupAll(VertxTestContext testContext) { 37 | vertx = context.getBean(Vertx.class); 38 | var factory = context.getBean(VerticleFactory.class); 39 | vertx.deployVerticle(factory.prefix() + ":" + MainVerticle.class.getName()) 40 | .subscribe() 41 | .with(id -> { 42 | LOGGER.info("deployed:" + id); 43 | testContext.completeNow(); 44 | }, 45 | testContext::failNow 46 | ); 47 | } 48 | 49 | @Test 50 | public void testVertx(VertxTestContext testContext) { 51 | assertThat(vertx).isNotNull(); 52 | testContext.completeNow(); 53 | } 54 | 55 | 56 | @Test 57 | void testGetAll(VertxTestContext testContext) { 58 | LOGGER.log(Level.INFO, "running test: {0}", "testGetAll"); 59 | var options = new HttpClientOptions() 60 | .setDefaultPort(8888); 61 | var client = vertx.createHttpClient(options); 62 | 63 | client.request(HttpMethod.GET, "/posts") 64 | .flatMap(HttpClientRequest::send) 65 | .flatMap(HttpClientResponse::body) 66 | .subscribe() 67 | .with(buffer -> 68 | testContext.verify( 69 | () -> { 70 | LOGGER.log(Level.INFO, "response buffer: {0}", new Object[]{buffer.toString()}); 71 | assertThat(buffer.toJsonArray().size()).isGreaterThan(0); 72 | testContext.completeNow(); 73 | } 74 | ), 75 | e -> { 76 | LOGGER.log(Level.ALL, "error: {0}", e.getMessage()); 77 | testContext.failNow(e); 78 | } 79 | ); 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/PostsHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.json.Json; 4 | import io.vertx.ext.web.RoutingContext; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.UUID; 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | 11 | @Component 12 | class PostsHandler { 13 | private static final Logger LOGGER = Logger.getLogger(PostsHandler.class.getSimpleName()); 14 | 15 | private final PostRepository posts; 16 | 17 | PostsHandler(PostRepository posts) { 18 | this.posts = posts; 19 | } 20 | 21 | public void all(RoutingContext rc) { 22 | // var params = rc.queryParams(); 23 | // var q = params.get("q"); 24 | // var limit = params.get("limit") == null ? 10 : Integer.parseInt(params.get("q")); 25 | // var offset = params.get("offset") == null ? 0 : Integer.parseInt(params.get("offset")); 26 | // LOGGER.log(Level.INFO, " find by keyword: q={0}, limit={1}, offset={2}", new Object[]{q, limit, offset}); 27 | this.posts.findAll() 28 | .onSuccess(data -> rc.response().end(Json.encode(data))); 29 | } 30 | 31 | public void get(RoutingContext rc) { 32 | var params = rc.pathParams(); 33 | var id = params.get("id"); 34 | this.posts.findById(UUID.fromString(id)) 35 | .onSuccess(post -> rc.response().end(Json.encode(post))) 36 | .onFailure(throwable -> rc.fail(404, throwable)); 37 | } 38 | 39 | public void save(RoutingContext rc) { 40 | //rc.getBodyAsJson().mapTo(PostForm.class) 41 | var body = rc.body().asJsonObject(); 42 | LOGGER.log(Level.INFO, "request body: {0}", body); 43 | var form = body.mapTo(CreatePostCommand.class); 44 | this.posts 45 | .save(new Post(null, form.title(), form.content(), null)) 46 | .onSuccess( 47 | savedId -> rc.response() 48 | .putHeader("Location", "/posts/" + savedId) 49 | .setStatusCode(201) 50 | .end() 51 | ); 52 | } 53 | 54 | public void update(RoutingContext rc) { 55 | var params = rc.pathParams(); 56 | var id = params.get("id"); 57 | var body = rc.body().asJsonObject(); 58 | LOGGER.log(Level.INFO, "\npath param id: {0}\nrequest body: {1}", new Object[]{id, body}); 59 | var form = body.mapTo(CreatePostCommand.class); 60 | this.posts.findById(UUID.fromString(id)) 61 | .compose( 62 | post -> { 63 | var toUpdated = new Post(post.id(), form.title(), form.content(), null); 64 | return this.posts.update(toUpdated); 65 | } 66 | ) 67 | .onSuccess(data -> rc.response().setStatusCode(204).end()) 68 | .onFailure(throwable -> rc.fail(404, throwable)); 69 | } 70 | 71 | public void delete(RoutingContext rc) { 72 | var params = rc.pathParams(); 73 | var id = params.get("id"); 74 | 75 | var uuid = UUID.fromString(id); 76 | this.posts.findById(uuid) 77 | .compose(post -> this.posts.deleteById(uuid)) 78 | .onSuccess(data -> rc.response().setStatusCode(204).end()) 79 | .onFailure(throwable -> rc.fail(404, throwable)); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /rxjava3/src/main/java/com/example/demo/PostsHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.json.Json; 4 | import io.vertx.rxjava3.ext.web.RoutingContext; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.UUID; 9 | 10 | class PostsHandler { 11 | private static final Logger log = LoggerFactory.getLogger(PostsHandler.class); 12 | private final PostRepository posts; 13 | 14 | private PostsHandler(PostRepository postRepository) { 15 | this.posts = postRepository; 16 | } 17 | 18 | //factory method 19 | public static PostsHandler create(PostRepository posts) { 20 | return new PostsHandler(posts); 21 | } 22 | 23 | public void all(RoutingContext rc) { 24 | // var params = rc.queryParams(); 25 | // var q = params.get("q"); 26 | // var limit = params.get("limit") == null ? 10 : Integer.parseInt(params.get("q")); 27 | // var offset = params.get("offset") == null ? 0 : Integer.parseInt(params.get("offset")); 28 | // LOGGER.log(Level.INFO, " find by keyword: q={0}, limit={1}, offset={2}", new Object[]{q, limit, offset}); 29 | this.posts.findAll().takeLast(10).toList() 30 | .subscribe(data -> rc.response().rxSend(Json.encode(data))); 31 | } 32 | 33 | public void get(RoutingContext rc) throws PostNotFoundException { 34 | var params = rc.pathParams(); 35 | var id = params.get("id"); 36 | var uuid = UUID.fromString(id); 37 | this.posts.findById(uuid) 38 | .subscribe( 39 | post -> rc.response().rxSend(Json.encode(post)), 40 | error -> rc.fail(404, new PostNotFoundException(uuid)) 41 | ); 42 | } 43 | 44 | 45 | public void save(RoutingContext rc) { 46 | //rc.getBodyAsJson().mapTo(PostForm.class) 47 | var body = rc.body().asJsonObject(); 48 | log.info("request body: {0}", body); 49 | var form = body.mapTo(CreatePostCommand.class); 50 | this.posts 51 | .save(new Post(null, form.title(), form.content(), null)) 52 | .subscribe(savedId -> rc.response() 53 | .putHeader("Location", "/posts/" + savedId) 54 | .setStatusCode(201) 55 | .rxEnd() 56 | ); 57 | } 58 | 59 | public void update(RoutingContext rc) { 60 | var params = rc.pathParams(); 61 | var id = params.get("id"); 62 | var body = rc.body().asJsonObject(); 63 | log.info("\npath param id: {}\nrequest body: {}", id, body); 64 | var form = body.mapTo(CreatePostCommand.class); 65 | 66 | this.posts.findById(UUID.fromString(id)) 67 | .flatMap(post -> { 68 | var toUpdated = new Post(post.id(), form.title(), form.content(), null); 69 | return this.posts.update(toUpdated); 70 | } 71 | ) 72 | .subscribe(data -> rc.response().setStatusCode(204).rxEnd()); 73 | } 74 | 75 | public void delete(RoutingContext rc) { 76 | var params = rc.pathParams(); 77 | var id = params.get("id"); 78 | var uuid = UUID.fromString(id); 79 | this.posts.findById(uuid) 80 | .flatMap(post -> this.posts.deleteById(uuid)) 81 | .subscribe(data -> rc.response().setStatusCode(204).rxEnd(), 82 | error -> rc.fail(404, error) 83 | ); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/PostRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Future; 4 | import io.vertx.sqlclient.*; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.List; 8 | import java.util.Objects; 9 | import java.util.UUID; 10 | import java.util.function.Function; 11 | import java.util.logging.Logger; 12 | import java.util.stream.StreamSupport; 13 | 14 | @Component 15 | public class PostRepository { 16 | private static final Logger LOGGER = Logger.getLogger(PostRepository.class.getName()); 17 | 18 | private static Function MAPPER = (row) -> 19 | new Post( 20 | row.getUUID("id"), 21 | row.getString("title"), 22 | row.getString("content"), 23 | row.getLocalDateTime("created_at") 24 | ); 25 | 26 | 27 | private final Pool client; 28 | 29 | public PostRepository(Pool client) { 30 | this.client = client; 31 | } 32 | 33 | public Future> findAll() { 34 | String sql = "SELECT * FROM posts ORDER BY id ASC"; 35 | return client.query(sql) 36 | .execute() 37 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 38 | .map(MAPPER) 39 | .toList() 40 | ); 41 | } 42 | 43 | 44 | public Future findById(UUID id) { 45 | Objects.requireNonNull(id, "id can not be null"); 46 | String sql = "SELECT * FROM posts WHERE id=$1"; 47 | return client.preparedQuery(sql).execute(Tuple.of(id)) 48 | .map(RowSet::iterator) 49 | .map(iterator -> { 50 | if (iterator.hasNext()) { 51 | return MAPPER.apply(iterator.next()); 52 | } 53 | throw new PostNotFoundException(id); 54 | }); 55 | } 56 | 57 | public Future save(Post data) { 58 | String sql = "INSERT INTO posts(title, content) VALUES ($1, $2) RETURNING (id)"; 59 | return client.preparedQuery(sql) 60 | .execute(Tuple.of(data.title(), data.content())) 61 | .map(rs -> rs.iterator().next().getUUID("id")); 62 | } 63 | 64 | public Future saveAll(List data) { 65 | var tuples = data.stream() 66 | .map( 67 | d -> Tuple.of(d.title(), d.content()) 68 | ) 69 | .toList(); 70 | 71 | String sql = "INSERT INTO posts (title, content) VALUES ($1, $2)"; 72 | return client.preparedQuery(sql) 73 | .executeBatch(tuples) 74 | .map(SqlResult::rowCount); 75 | } 76 | 77 | public Future update(Post data) { 78 | String sql = "UPDATE posts SET title=$1, content=$2 WHERE id=$3"; 79 | return client.preparedQuery(sql) 80 | .execute(Tuple.of(data.title(), data.content(), data.id())) 81 | .map(SqlResult::rowCount); 82 | } 83 | 84 | public Future deleteAll() { 85 | String sql = "DELETE FROM posts"; 86 | return client.query(sql).execute() 87 | .map(SqlResult::rowCount); 88 | } 89 | 90 | public Future deleteById(UUID id) { 91 | Objects.requireNonNull(id, "id can not be null"); 92 | String sql = "DELETE FROM posts WHERE id=$1"; 93 | return client.preparedQuery(sql).execute(Tuple.of(id)) 94 | .map(SqlResult::rowCount); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/PostsHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.json.Json; 4 | import io.vertx.ext.web.RoutingContext; 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | import jakarta.inject.Inject; 7 | 8 | import java.util.UUID; 9 | import java.util.logging.Level; 10 | import java.util.logging.Logger; 11 | 12 | @ApplicationScoped 13 | class PostsHandler { 14 | private static final Logger LOGGER = Logger.getLogger(PostsHandler.class.getSimpleName()); 15 | 16 | private PostRepository posts; 17 | 18 | public PostsHandler() { 19 | } 20 | 21 | @Inject 22 | PostsHandler(PostRepository posts) { 23 | this.posts = posts; 24 | } 25 | 26 | public void all(RoutingContext rc) { 27 | // var params = rc.queryParams(); 28 | // var q = params.get("q"); 29 | // var limit = params.get("limit") == null ? 10 : Integer.parseInt(params.get("q")); 30 | // var offset = params.get("offset") == null ? 0 : Integer.parseInt(params.get("offset")); 31 | // LOGGER.log(Level.INFO, " find by keyword: q={0}, limit={1}, offset={2}", new Object[]{q, limit, offset}); 32 | this.posts.findAll() 33 | .onSuccess( 34 | data -> rc.response().end(Json.encode(data)) 35 | ); 36 | } 37 | 38 | public void get(RoutingContext rc) { 39 | var params = rc.pathParams(); 40 | var id = params.get("id"); 41 | this.posts.findById(UUID.fromString(id)) 42 | .onSuccess(post -> rc.response().end(Json.encode(post))) 43 | .onFailure(throwable -> rc.fail(404, throwable)); 44 | } 45 | 46 | public void save(RoutingContext rc) { 47 | //rc.getBodyAsJson().mapTo(PostForm.class) 48 | var body = rc.body().asJsonObject(); 49 | LOGGER.log(Level.INFO, "request body: {0}", body); 50 | var form = body.mapTo(CreatePostCommand.class); 51 | this.posts 52 | .save(new Post(null, form.title(), form.content(), null)) 53 | .onSuccess( 54 | savedId -> rc.response() 55 | .putHeader("Location", "/posts/" + savedId) 56 | .setStatusCode(201) 57 | .end() 58 | ); 59 | } 60 | 61 | public void update(RoutingContext rc) { 62 | var params = rc.pathParams(); 63 | var id = params.get("id"); 64 | var body = rc.body().asJsonObject(); 65 | LOGGER.log(Level.INFO, "\npath param id: {0}\nrequest body: {1}", new Object[]{id, body}); 66 | var form = body.mapTo(CreatePostCommand.class); 67 | 68 | this.posts.findById(UUID.fromString(id)) 69 | .compose( 70 | post -> { 71 | var toUpdated = new Post(post.id(), form.title(), form.content(), null); 72 | return this.posts.update(toUpdated); 73 | } 74 | ) 75 | .onSuccess(data -> rc.response().setStatusCode(204).end()) 76 | .onFailure(throwable -> rc.fail(404, throwable)); 77 | } 78 | 79 | public void delete(RoutingContext rc) { 80 | var params = rc.pathParams(); 81 | var id = params.get("id"); 82 | var uuid = UUID.fromString(id); 83 | 84 | this.posts.findById(uuid) 85 | .compose(post -> this.posts.deleteById(uuid)) 86 | .onSuccess(data -> rc.response().setStatusCode(204).end()) 87 | .onFailure(throwable -> rc.fail(404, throwable)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/demo/PostsHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.json.Json; 4 | import io.vertx.ext.web.RoutingContext; 5 | 6 | import java.util.UUID; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | class PostsHandler { 11 | private static final Logger LOGGER = Logger.getLogger(PostsHandler.class.getSimpleName()); 12 | private final PostRepository posts; 13 | 14 | private PostsHandler(PostRepository postsRepository) { 15 | this.posts = postsRepository; 16 | } 17 | 18 | //factory method 19 | public static PostsHandler create(PostRepository posts) { 20 | return new PostsHandler(posts); 21 | } 22 | 23 | public void all(RoutingContext rc) { 24 | // var params = rc.queryParams(); 25 | // var q = params.get("q"); 26 | // var limit = params.get("limit") == null ? 10 : Integer.parseInt(params.get("q")); 27 | // var offset = params.get("offset") == null ? 0 : Integer.parseInt(params.get("offset")); 28 | // LOGGER.log(Level.INFO, " find by keyword: q={0}, limit={1}, offset={2}", new Object[]{q, limit, offset}); 29 | this.posts.findAll() 30 | .onSuccess( 31 | data -> rc.response().end(Json.encode(data)) 32 | ); 33 | } 34 | 35 | public void get(RoutingContext rc) { 36 | var params = rc.pathParams(); 37 | var id = params.get("id"); 38 | this.posts.findById(UUID.fromString(id)) 39 | .onSuccess(post -> rc.response().end(Json.encode(post))) 40 | .onFailure(rc::fail); 41 | } 42 | 43 | 44 | public void save(RoutingContext rc) { 45 | //rc.getBodyAsJson().mapTo(PostForm.class) 46 | var body = rc.body().asJsonObject(); 47 | LOGGER.log(Level.INFO, "request body: {0}", body); 48 | var form = body.mapTo(CreatePostCommand.class); 49 | this.posts.save(Post.of(form.title(), form.content())) 50 | .onSuccess( 51 | savedId -> rc.response() 52 | .putHeader("Location", "/posts/" + savedId) 53 | .setStatusCode(201) 54 | .end() 55 | ); 56 | } 57 | 58 | public void update(RoutingContext rc) { 59 | var params = rc.pathParams(); 60 | var id = params.get("id"); 61 | var body = rc.body().asJsonObject(); 62 | LOGGER.log(Level.INFO, "\npath param id: {0}\nrequest body: {1}", new Object[]{id, body}); 63 | var form = body.mapTo(CreatePostCommand.class); 64 | UUID uuid = UUID.fromString(id); 65 | 66 | this.posts.findById(uuid) 67 | .compose( 68 | post -> { 69 | var toUpdated = new Post(post.id(), form.title(), form.content(), post.createdAt()); 70 | return this.posts.update(toUpdated); 71 | } 72 | ) 73 | .onSuccess(data -> rc.response().setStatusCode(204).end()) 74 | .onFailure(throwable -> rc.fail(404, throwable)); 75 | } 76 | 77 | public void delete(RoutingContext rc) { 78 | var params = rc.pathParams(); 79 | var id = params.get("id"); 80 | var uuid = UUID.fromString(id); 81 | 82 | this.posts.findById(uuid) 83 | .compose( 84 | post -> this.posts.deleteById(uuid) 85 | ) 86 | .onSuccess(data -> rc.response().setStatusCode(204).end()) 87 | .onFailure(throwable -> rc.fail(404, throwable)); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/repository/PostRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.model.PostEntity; 4 | import io.vertx.core.Future; 5 | import io.vertx.sqlclient.*; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.UUID; 12 | import java.util.function.Function; 13 | import java.util.stream.StreamSupport; 14 | 15 | @RequiredArgsConstructor 16 | @Slf4j 17 | public class PostRepository { 18 | private static final Function MAPPER = (row) -> 19 | new PostEntity( 20 | row.getUUID("id"), 21 | row.getString("title"), 22 | row.getString("content"), 23 | row.getString("status"), 24 | row.getLocalDateTime("created_at"), 25 | row.getUUID("author_id") 26 | ); 27 | 28 | 29 | private final Pool client; 30 | 31 | public Future> findAll() { 32 | return client.query("SELECT * FROM posts ORDER BY created_at DESC ") 33 | .execute() 34 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 35 | .map(MAPPER) 36 | .toList() 37 | ); 38 | } 39 | 40 | 41 | public Future findById(UUID id) { 42 | Objects.requireNonNull(id, "id can not be null"); 43 | return client.preparedQuery("SELECT * FROM posts WHERE id=$1").execute(Tuple.of(id)) 44 | .map(RowSet::iterator) 45 | .map(iterator -> { 46 | if (iterator.hasNext()) return MAPPER.apply(iterator.next()); 47 | throw new PostNotFoundException(id); 48 | }); 49 | } 50 | 51 | public Future> findByAuthorId(UUID id) { 52 | Objects.requireNonNull(id, "id can not be null"); 53 | return client.preparedQuery("SELECT * FROM posts WHERE author_id=$1").execute(Tuple.of(id)) 54 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 55 | .map(MAPPER) 56 | .toList() 57 | ); 58 | } 59 | 60 | public Future create(String title, String content, String status, UUID authorId) { 61 | return client.preparedQuery("INSERT INTO posts(title, content, status, author_id) VALUES ($1, $2, $3, $4) RETURNING (id)") 62 | .execute(Tuple.of(title, content, status, authorId)) 63 | .map(rs -> rs.iterator().next().getUUID("id")); 64 | } 65 | 66 | public Future saveAll(List data) { 67 | var tuples = data.stream() 68 | .map(d -> Tuple.of(d.title(), d.content())) 69 | .toList(); 70 | 71 | return client.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)") 72 | .executeBatch(tuples) 73 | .map(SqlResult::rowCount); 74 | } 75 | 76 | public Future update(PostEntity data) { 77 | return client.preparedQuery("UPDATE posts SET title=$1, content=$2 WHERE id=$3") 78 | .execute(Tuple.of(data.title(), data.content(), data.id())) 79 | .map(SqlResult::rowCount); 80 | } 81 | 82 | public Future deleteAll() { 83 | return client.query("DELETE FROM posts").execute() 84 | .map(SqlResult::rowCount); 85 | } 86 | 87 | public Future deleteById(UUID id) { 88 | Objects.requireNonNull(id, "id can not be null"); 89 | return client.preparedQuery("DELETE FROM posts WHERE id=$1").execute(Tuple.of(id)) 90 | .map(SqlResult::rowCount); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/PostRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Future; 4 | import io.vertx.sqlclient.*; 5 | import jakarta.enterprise.context.ApplicationScoped; 6 | import jakarta.inject.Inject; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | import java.util.UUID; 12 | import java.util.function.Function; 13 | import java.util.logging.Logger; 14 | import java.util.stream.StreamSupport; 15 | 16 | import static java.util.stream.Collectors.toList; 17 | 18 | @ApplicationScoped 19 | public class PostRepository { 20 | private static final Logger LOGGER = Logger.getLogger(PostRepository.class.getName()); 21 | 22 | private static final Function MAPPER = (Row row) -> 23 | new Post( 24 | row.getUUID("id"), 25 | row.getString("title"), 26 | row.getString("content"), 27 | row.getLocalDateTime("created_at") 28 | ); 29 | 30 | private Pool client; 31 | 32 | public PostRepository() { 33 | } 34 | 35 | @Inject 36 | public PostRepository(Pool client) { 37 | this.client = client; 38 | } 39 | 40 | public Future> findAll() { 41 | return client.query("SELECT * FROM posts ORDER BY id ASC") 42 | .execute() 43 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 44 | .map(MAPPER) 45 | .collect(toList()) 46 | ); 47 | } 48 | 49 | public Future findById(UUID id) { 50 | Objects.requireNonNull(id, "id can not be null"); 51 | String sql = "SELECT * FROM posts WHERE id=$1"; 52 | return client.preparedQuery(sql) 53 | .execute(Tuple.of(id)) 54 | .map(RowSet::iterator) 55 | .map(iterator -> iterator.hasNext() ? MAPPER.apply(iterator.next()) : null) 56 | .map(Optional::ofNullable) 57 | .map(p -> p.orElseThrow(() -> new PostNotFoundException(id))); 58 | } 59 | 60 | public Future save(Post data) { 61 | String sql = "INSERT INTO posts(title, content) VALUES ($1, $2) RETURNING (id)"; 62 | return client.preparedQuery(sql) 63 | .execute(Tuple.of(data.title(), data.content())) 64 | .map(rs -> rs.iterator().next().getUUID("id")); 65 | } 66 | 67 | public Future saveAll(List data) { 68 | var tuples = data.stream() 69 | .map(d -> Tuple.of(d.title(), d.content())) 70 | .toList(); 71 | 72 | String sql = "INSERT INTO posts (title, content) VALUES ($1, $2)"; 73 | return client.preparedQuery(sql) 74 | .executeBatch(tuples) 75 | .map(SqlResult::rowCount); 76 | } 77 | 78 | public Future update(Post data) { 79 | String sql = "UPDATE posts SET title=$1, content=$2 WHERE id=$3"; 80 | return client.preparedQuery(sql) 81 | .execute(Tuple.of(data.title(), data.content(), data.id())) 82 | .map(SqlResult::rowCount); 83 | } 84 | 85 | public Future deleteAll() { 86 | String sql = "DELETE FROM posts"; 87 | return client.query(sql) 88 | .execute() 89 | .map(SqlResult::rowCount); 90 | } 91 | 92 | public Future deleteById(UUID id) { 93 | Objects.requireNonNull(id, "id can not be null"); 94 | String sql = "DELETE FROM posts WHERE id=$1"; 95 | return client.preparedQuery(sql) 96 | .execute(Tuple.of(id)) 97 | .map(SqlResult::rowCount); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /kotlin/src/test/kotlin/com/example/demo/TestMainVerticle.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import io.vertx.core.Vertx 4 | import io.vertx.core.buffer.Buffer 5 | import io.vertx.core.http.HttpClient 6 | import io.vertx.core.http.HttpClientOptions 7 | import io.vertx.core.http.HttpClientResponse 8 | import io.vertx.core.http.HttpMethod 9 | import io.vertx.junit5.Timeout 10 | import io.vertx.junit5.VertxExtension 11 | import io.vertx.junit5.VertxTestContext 12 | import org.assertj.core.api.Assertions.assertThat 13 | import org.junit.jupiter.api.* 14 | import org.junit.jupiter.api.extension.ExtendWith 15 | import java.util.* 16 | import java.util.concurrent.TimeUnit 17 | import java.util.logging.Level 18 | import java.util.logging.Logger 19 | 20 | 21 | @ExtendWith(VertxExtension::class) 22 | class TestMainVerticle { 23 | companion object { 24 | private val LOGGER = Logger.getLogger(TestMainVerticle::class.java.name) 25 | } 26 | 27 | lateinit var client: HttpClient 28 | 29 | @BeforeEach 30 | fun setup(vertx: Vertx, testContext: VertxTestContext) { 31 | vertx.deployVerticle(MainVerticle()) 32 | .onComplete( 33 | testContext.succeeding { id: String? -> 34 | LOGGER.log(Level.INFO, "deployed:{0}", arrayOf(id)) 35 | val options = HttpClientOptions() 36 | .setDefaultPort(8888) 37 | this.client = vertx.createHttpClient(options) 38 | testContext.completeNow() 39 | } 40 | ) 41 | } 42 | 43 | @AfterEach 44 | @DisplayName("Check that the verticle is still there") 45 | fun lastChecks(vertx: Vertx) { 46 | assertThat(vertx.deploymentIDs()) 47 | .isNotEmpty() 48 | .hasSize(1) 49 | } 50 | 51 | // Repeat this test 3 times 52 | @RepeatedTest(3) 53 | @Timeout(value = 10, timeUnit = TimeUnit.SECONDS) 54 | @DisplayName("Check the HTTP response...") 55 | fun testHello(vertx: Vertx, testContext: VertxTestContext) { 56 | client.request(HttpMethod.GET, "/hello") 57 | .flatMap { it.send() } 58 | .flatMap { it.body() } 59 | .onComplete( 60 | testContext.succeeding { buffer: Buffer -> 61 | testContext.verify { 62 | assertThat(buffer.toString()).contains("Hello") 63 | testContext.completeNow() 64 | } 65 | } 66 | ) 67 | } 68 | 69 | @Test 70 | fun `get all posts`(vertx: Vertx, testContext: VertxTestContext) { 71 | client.request(HttpMethod.GET, "/posts") 72 | .flatMap { it.send() } 73 | .flatMap { it.body() } 74 | .onComplete( 75 | testContext.succeeding { buffer: Buffer -> 76 | testContext.verify { 77 | assertThat(buffer.toJsonArray().size()).isEqualTo(2) 78 | testContext.completeNow() 79 | } 80 | } 81 | ) 82 | } 83 | 84 | @Test 85 | fun `get post by non-existing id`(vertx: Vertx, testContext: VertxTestContext) { 86 | val postByIdUrl = "/posts/" + UUID.randomUUID() 87 | client.request(HttpMethod.GET, postByIdUrl) 88 | .flatMap { it.send() } 89 | .onComplete( 90 | testContext.succeeding { response: HttpClientResponse -> 91 | testContext.verify { 92 | assertThat(response.statusCode()).isEqualTo(404) 93 | testContext.completeNow() 94 | } 95 | } 96 | ) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/demo/PostRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.core.Future; 4 | import io.vertx.sqlclient.*; 5 | 6 | import java.util.List; 7 | import java.util.Objects; 8 | import java.util.UUID; 9 | import java.util.function.Function; 10 | import java.util.logging.Logger; 11 | import java.util.stream.StreamSupport; 12 | 13 | import static java.util.stream.Collectors.toList; 14 | 15 | public class PostRepository { 16 | private static final Logger LOGGER = Logger.getLogger(PostRepository.class.getName()); 17 | 18 | private static Function MAPPER = (Row row) -> 19 | new Post( 20 | row.getUUID("id"), 21 | row.getString("title"), 22 | row.getString("content"), 23 | row.getLocalDateTime("created_at") 24 | ); 25 | 26 | 27 | private final Pool client; 28 | 29 | private PostRepository(Pool sqlClient) { 30 | this.client = sqlClient; 31 | } 32 | 33 | //factory method 34 | public static PostRepository create(Pool client) { 35 | return new PostRepository(client); 36 | } 37 | 38 | public Future> findAll() { 39 | String sql = "SELECT * FROM posts ORDER BY id ASC"; 40 | return client.query(sql) 41 | .execute() 42 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 43 | .map(MAPPER) 44 | .toList() 45 | ); 46 | } 47 | 48 | 49 | public Future findById(UUID id) { 50 | Objects.requireNonNull(id, "id can not be null"); 51 | String sql = "SELECT * FROM posts WHERE id=$1"; 52 | return client.preparedQuery(sql).execute(Tuple.of(id)) 53 | .map(RowSet::iterator) 54 | .map(iterator -> { 55 | if (iterator.hasNext()) { 56 | return MAPPER.apply(iterator.next()); 57 | } 58 | throw new PostNotFoundException(id); 59 | } 60 | ); 61 | } 62 | 63 | public Future save(Post data) { 64 | String sql = "INSERT INTO posts(title, content) VALUES ($1, $2) RETURNING (id)"; 65 | return client.preparedQuery(sql) 66 | .execute(Tuple.of(data.title(), data.content())) 67 | .map(rs -> rs.iterator().next().getUUID("id")); 68 | } 69 | 70 | public Future saveAll(List data) { 71 | var tuples = data.stream() 72 | .map(d -> Tuple.of(d.title(), d.content())) 73 | .toList(); 74 | 75 | String sql = "INSERT INTO posts (title, content) VALUES ($1, $2)"; 76 | return client.preparedQuery(sql) 77 | .executeBatch(tuples) 78 | .map(SqlResult::rowCount); 79 | } 80 | 81 | public Future update(Post data) { 82 | String sql = "UPDATE posts SET title=$1, content=$2 WHERE id=$3"; 83 | return client.preparedQuery(sql) 84 | .execute(Tuple.of(data.title(), data.content(), data.id())) 85 | .map(SqlResult::rowCount); 86 | } 87 | 88 | public Future deleteAll() { 89 | String sql = "DELETE FROM posts"; 90 | return client.query(sql) 91 | .execute() 92 | .map(SqlResult::rowCount); 93 | } 94 | 95 | public Future deleteById(UUID id) { 96 | Objects.requireNonNull(id, "id can not be null"); 97 | String sql = "DELETE FROM posts WHERE id=$1"; 98 | return client.preparedQuery(sql) 99 | .execute(Tuple.of(id)) 100 | .map(SqlResult::rowCount); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /rxjava3/src/main/java/com/example/demo/PostRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.reactivex.rxjava3.core.Flowable; 4 | import io.reactivex.rxjava3.core.Single; 5 | import io.vertx.rxjava3.sqlclient.*; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.UUID; 12 | import java.util.function.Function; 13 | import java.util.stream.Collectors; 14 | import java.util.stream.StreamSupport; 15 | 16 | public class PostRepository { 17 | private static final Logger log = LoggerFactory.getLogger(PostRepository.class); 18 | 19 | private static final Function MAPPER = (Row row) -> 20 | new Post( 21 | row.getUUID("id"), 22 | row.getString("title"), 23 | row.getString("content"), 24 | row.getLocalDateTime("created_at") 25 | ); 26 | 27 | 28 | private final Pool client; 29 | 30 | private PostRepository(Pool pgClient) { 31 | this.client = pgClient; 32 | } 33 | 34 | //factory method 35 | public static PostRepository create(Pool client) { 36 | return new PostRepository(client); 37 | } 38 | 39 | public Flowable findAll() { 40 | return this.client 41 | .query("SELECT * FROM posts") 42 | .rxExecute() 43 | .flattenAsFlowable( 44 | rows -> StreamSupport.stream(rows.spliterator(), false) 45 | .map(MAPPER) 46 | .toList() 47 | ); 48 | } 49 | 50 | 51 | public Single findById(UUID id) { 52 | Objects.requireNonNull(id, "id can not be null"); 53 | return client.preparedQuery("SELECT * FROM posts WHERE id=$1") 54 | .rxExecute(Tuple.of(id)) 55 | .map(RowSet::iterator) 56 | .flatMap(iterator -> iterator.hasNext() ? 57 | Single.just(MAPPER.apply(iterator.next())) : 58 | Single.error(new PostNotFoundException(id)) 59 | ); 60 | } 61 | 62 | public Single save(Post data) { 63 | String sql = "INSERT INTO posts(title, content) VALUES ($1, $2) RETURNING (id)"; 64 | return client.preparedQuery(sql) 65 | .rxExecute(Tuple.of(data.title(), data.content())) 66 | .map(rs -> rs.iterator().next().getUUID("id")); 67 | } 68 | 69 | public Single saveAll(List data) { 70 | var tuples = data.stream() 71 | .map(d -> Tuple.of(d.title(), d.content())) 72 | .collect(Collectors.toList()); 73 | 74 | String sql = "INSERT INTO posts (title, content) VALUES ($1, $2)"; 75 | return client.preparedQuery(sql) 76 | .rxExecuteBatch(tuples) 77 | .map(SqlResult::rowCount); 78 | } 79 | 80 | public Single update(Post data) { 81 | String sql = "UPDATE posts SET title=$1, content=$2 WHERE id=$3"; 82 | return client.preparedQuery(sql) 83 | .rxExecute(Tuple.of(data.title(), data.content(), data.id())) 84 | .map(SqlResult::rowCount); 85 | } 86 | 87 | public Single deleteAll() { 88 | String sql = "DELETE FROM posts"; 89 | return client.query(sql).rxExecute() 90 | .map(SqlResult::rowCount); 91 | } 92 | 93 | public Single deleteById(UUID id) { 94 | Objects.requireNonNull(id, "id can not be null"); 95 | String sql = "DELETE FROM posts WHERE id=$1"; 96 | return client.preparedQuery(sql).rxExecute(Tuple.of(id)) 97 | .map(SqlResult::rowCount); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /cdi/src/main/java/com/example/demo/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature; 4 | import com.fasterxml.jackson.databind.SerializationFeature; 5 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.VerticleBase; 8 | import io.vertx.core.json.jackson.DatabindCodec; 9 | import io.vertx.ext.web.Router; 10 | import io.vertx.ext.web.handler.BodyHandler; 11 | import jakarta.enterprise.context.ApplicationScoped; 12 | import jakarta.enterprise.context.Dependent; 13 | import jakarta.inject.Inject; 14 | 15 | import java.util.logging.Level; 16 | import java.util.logging.Logger; 17 | 18 | @Dependent 19 | public class MainVerticle extends VerticleBase { 20 | private static final Logger LOGGER = Logger.getLogger(MainVerticle.class.getName()); 21 | 22 | static { 23 | LOGGER.info("Customizing the built-in jackson ObjectMapper..."); 24 | var objectMapper = DatabindCodec.mapper(); 25 | objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 26 | objectMapper.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS); 27 | objectMapper.disable(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS); 28 | 29 | JavaTimeModule module = new JavaTimeModule(); 30 | objectMapper.registerModule(module); 31 | } 32 | 33 | private PostsHandler postsHandler; 34 | 35 | public MainVerticle() { 36 | } 37 | 38 | @Inject 39 | public MainVerticle(PostsHandler postHandlers) { 40 | this.postsHandler = postHandlers; 41 | } 42 | 43 | @Override 44 | public Future start() throws Exception { 45 | LOGGER.log(Level.INFO, "Starting HTTP server..."); 46 | //setupLogging(); 47 | 48 | //Create a PgPool instance 49 | //var pgPool = pgPool(); 50 | 51 | //Creating PostRepository 52 | //var postRepository = PostRepository.create(pgPool); 53 | 54 | //Creating PostHandler 55 | //var postHandlers = PostsHandler.create(postRepository); 56 | 57 | // Initializing the sample data 58 | // var initializer = DataInitializer.create(pgPool); 59 | // initializer.run(); 60 | 61 | // Configure routes 62 | var router = routes(postsHandler); 63 | 64 | // Create the HTTP server 65 | return vertx.createHttpServer() 66 | // Handle every request using the router 67 | .requestHandler(router) 68 | // Start listening 69 | .listen(8888) 70 | // Print the port 71 | .onSuccess(server -> LOGGER.log(Level.INFO, "HTTP server started on port " + server.actualPort())) 72 | .onFailure(event -> LOGGER.log(Level.SEVERE, "Failed to start HTTP server:" + event.getMessage())); 73 | } 74 | 75 | @Override 76 | public Future stop() throws Exception { 77 | return super.stop(); 78 | } 79 | 80 | //create routes 81 | private Router routes(PostsHandler handlers) { 82 | 83 | // Create a Router 84 | Router router = Router.router(vertx); 85 | // register BodyHandler globally. 86 | //router.route().handler(BodyHandler.create()); 87 | router.get("/posts").produces("application/json").handler(handlers::all); 88 | router.post("/posts").consumes("application/json").handler(BodyHandler.create()).handler(handlers::save); 89 | router.get("/posts/:id").produces("application/json").handler(handlers::get).failureHandler(frc -> frc.response().setStatusCode(404).end()); 90 | router.put("/posts/:id").consumes("application/json").handler(BodyHandler.create()).handler(handlers::update); 91 | router.delete("/posts/:id").handler(handlers::delete); 92 | 93 | router.get("/hello").handler(rc -> rc.response().end("Hello from my route")); 94 | 95 | return router; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /spring/src/main/java/com/example/demo/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature; 4 | import com.fasterxml.jackson.databind.SerializationFeature; 5 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.VerticleBase; 8 | import io.vertx.core.json.jackson.DatabindCodec; 9 | import io.vertx.ext.web.Router; 10 | import io.vertx.ext.web.handler.BodyHandler; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | 16 | @Component 17 | public class MainVerticle extends VerticleBase { 18 | private static final Logger LOGGER = Logger.getLogger(MainVerticle.class.getName()); 19 | 20 | static { 21 | LOGGER.info("Customizing the built-in jackson ObjectMapper..."); 22 | var objectMapper = DatabindCodec.mapper(); 23 | objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 24 | objectMapper.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS); 25 | objectMapper.disable(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS); 26 | 27 | JavaTimeModule module = new JavaTimeModule(); 28 | objectMapper.registerModule(module); 29 | } 30 | 31 | private final PostsHandler postHandlers; 32 | 33 | public MainVerticle(PostsHandler postHandlers) { 34 | this.postHandlers = postHandlers; 35 | } 36 | 37 | @Override 38 | public Future start() throws Exception { 39 | LOGGER.log(Level.INFO, "Starting HTTP server..."); 40 | //setupLogging(); 41 | 42 | //Create a PgPool instance 43 | //var pgPool = pgPool(); 44 | 45 | //Creating PostRepository 46 | //var postRepository = PostRepository.create(pgPool); 47 | 48 | //Creating PostHandler 49 | //var postHandlers = PostsHandler.create(postRepository); 50 | 51 | // Initializing the sample data 52 | // var initializer = DataInitializer.create(pgPool); 53 | // initializer.run(); 54 | 55 | // Configure routes 56 | var router = routes(postHandlers); 57 | 58 | // Create the HTTP server 59 | return vertx.createHttpServer() 60 | // Handle every request using the router 61 | .requestHandler(router) 62 | // Start listening 63 | .listen(8888) 64 | // Print the port 65 | .onSuccess(server -> { 66 | LOGGER.log(Level.INFO, "HTTP server started on port " + server.actualPort()); 67 | }) 68 | .onFailure(event -> { 69 | LOGGER.log(Level.SEVERE, "Failed to start HTTP server:" + event.getMessage()); 70 | }) 71 | ; 72 | } 73 | 74 | @Override 75 | public Future stop() throws Exception { 76 | LOGGER.log(Level.INFO, "Stopping HTTP server..."); 77 | return super.stop(); 78 | } 79 | 80 | //create routes 81 | private Router routes(PostsHandler handlers) { 82 | 83 | // Create a Router 84 | Router router = Router.router(vertx); 85 | // register BodyHandler globally. 86 | //router.route().handler(BodyHandler.create()); 87 | router.get("/posts").produces("application/json").handler(handlers::all); 88 | router.post("/posts").consumes("application/json").handler(BodyHandler.create()).handler(handlers::save); 89 | router.get("/posts/:id").produces("application/json").handler(handlers::get).failureHandler(frc -> frc.response().setStatusCode(404).end()); 90 | router.put("/posts/:id").consumes("application/json").handler(BodyHandler.create()).handler(handlers::update); 91 | router.delete("/posts/:id").handler(handlers::delete); 92 | 93 | router.get("/hello").handler(rc -> rc.response().end("Hello from my route")); 94 | 95 | return router; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/repository/PostRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.model.PostEntity; 4 | import io.vertx.core.Future; 5 | import io.vertx.sqlclient.*; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.UUID; 12 | import java.util.function.Function; 13 | import java.util.stream.Collectors; 14 | import java.util.stream.StreamSupport; 15 | 16 | @RequiredArgsConstructor 17 | @Slf4j 18 | public class PostRepository { 19 | private static Function MAPPER = (row) -> 20 | new PostEntity( 21 | row.getUUID("id"), 22 | row.getString("title"), 23 | row.getString("content"), 24 | row.getString("status"), 25 | row.getLocalDateTime("created_at"), 26 | row.getUUID("author_id") 27 | ); 28 | 29 | 30 | private final Pool client; 31 | 32 | public Future> findAll() { 33 | return client.query("SELECT * FROM posts ORDER BY created_at DESC ") 34 | .execute() 35 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 36 | .map(MAPPER) 37 | .collect(Collectors.toList()) 38 | ); 39 | } 40 | 41 | 42 | public Future findById(UUID id) { 43 | Objects.requireNonNull(id, "id can not be null"); 44 | return client.preparedQuery("SELECT * FROM posts WHERE id=$1").execute(Tuple.of(id)) 45 | .map(RowSet::iterator) 46 | .map(iterator -> { 47 | if (iterator.hasNext()) return MAPPER.apply(iterator.next()); 48 | throw new PostNotFoundException(id); 49 | }); 50 | } 51 | 52 | public Future> findByAuthorId(UUID id) { 53 | Objects.requireNonNull(id, "id can not be null"); 54 | return client.preparedQuery("SELECT * FROM posts WHERE author_id=$1").execute(Tuple.of(id)) 55 | .map(rs -> StreamSupport.stream(rs.spliterator(), false) 56 | .map(MAPPER) 57 | .collect(Collectors.toList()) 58 | ); 59 | } 60 | 61 | public Future create(String title, String content, String status, UUID authorId) { 62 | return client.preparedQuery("INSERT INTO posts(title, content, status, author_id) VALUES ($1, $2, $3, $4) RETURNING (id)") 63 | .execute(Tuple.of(title, content, status, authorId)) 64 | .map(rs -> rs.iterator().next().getUUID("id")); 65 | } 66 | 67 | public Future saveAll(List data) { 68 | var tuples = data.stream() 69 | .map( 70 | d -> Tuple.of(d.title(), d.content()) 71 | ) 72 | .collect(Collectors.toList()); 73 | 74 | return client.preparedQuery("INSERT INTO posts (title, content) VALUES ($1, $2)") 75 | .executeBatch(tuples) 76 | .map(SqlResult::rowCount); 77 | } 78 | 79 | public Future update(PostEntity data) { 80 | return client.preparedQuery("UPDATE posts SET title=$1, content=$2 WHERE id=$3") 81 | .execute(Tuple.of(data.title(), data.content(), data.id())) 82 | .map(SqlResult::rowCount); 83 | } 84 | 85 | public Future deleteAll() { 86 | return client.query("DELETE FROM posts").execute() 87 | .map(SqlResult::rowCount); 88 | } 89 | 90 | public Future deleteById(UUID id) { 91 | Objects.requireNonNull(id, "id can not be null"); 92 | return client.preparedQuery("DELETE FROM posts WHERE id=$1").execute(Tuple.of(id)) 93 | .map(SqlResult::rowCount); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /rxjava3/src/test/java/com/example/demo/TestMainVerticle.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.vertx.ext.web.client.WebClientOptions; 4 | import io.vertx.junit5.VertxExtension; 5 | import io.vertx.junit5.VertxTestContext; 6 | import io.vertx.rxjava3.core.RxHelper; 7 | import io.vertx.rxjava3.core.Vertx; 8 | import io.vertx.rxjava3.ext.web.client.WebClient; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | 17 | // see https://github.com/vert-x3/vertx-rx/issues/265 18 | // `testContext.succeeding` will block application. 19 | @ExtendWith(VertxExtension.class) 20 | public class TestMainVerticle { 21 | private static final Logger log = LoggerFactory.getLogger(TestMainVerticle.class); 22 | WebClient client; 23 | 24 | @BeforeEach 25 | void setUp(Vertx vertx, VertxTestContext testContext) { 26 | 27 | // see: https://github.com/vert-x3/vertx-rx/blob/master/rx-junit5-providers/vertx-junit5-rx-java3/src/test/java/io/vertx/junit5/rxjava3/RxJava3Test.java 28 | RxHelper 29 | .deployVerticle(vertx, new MainVerticle()) 30 | .subscribe( 31 | message -> testContext.verify(() -> { 32 | log.info("deployed: {}", message); 33 | 34 | // build RxJava3 WebClient 35 | var options = new WebClientOptions() 36 | .setDefaultHost("localhost") 37 | .setDefaultPort(8888); 38 | this.client = WebClient.create(vertx, options); 39 | 40 | // clean test context 41 | testContext.completeNow(); 42 | }), 43 | testContext::failNow 44 | ); 45 | } 46 | 47 | @Test 48 | void testGetAll(Vertx vertx, VertxTestContext testContext) { 49 | client.get("/posts") 50 | .rxSend() 51 | .subscribe( 52 | response -> testContext.verify(() -> { 53 | assertThat(response.statusCode()).isEqualTo(200); 54 | assertThat(response.bodyAsJsonArray().size()).isEqualTo(2); 55 | 56 | testContext.completeNow(); 57 | }), 58 | testContext::failNow 59 | ); 60 | } 61 | 62 | @Test 63 | void testCreatPost(Vertx vertx, VertxTestContext testContext) { 64 | client.post("/posts") 65 | .rxSendJson( 66 | new CreatePostCommand("The quick brown fox jumps over the lazy dog", 67 | "body of `the quick brown fox jumps over the lazy dog`") 68 | ) 69 | .subscribe( 70 | response -> testContext.verify(() -> { 71 | var statusCode = response.statusCode(); 72 | var body = response.bodyAsString(); 73 | log.info("status code: {}, body: {}", statusCode, body); 74 | assertThat(statusCode).isEqualTo(201); 75 | assertThat(response.getHeader("Location")).isNotNull(); 76 | testContext.completeNow(); 77 | }), 78 | testContext::failNow 79 | ); 80 | } 81 | 82 | @Test 83 | void testHello(Vertx vertx, VertxTestContext testContext) { 84 | client.get("/hello") 85 | .rxSend() 86 | .subscribe(response -> testContext.verify(() -> { 87 | var helloResponse = response.body().toString(); 88 | log.info("Get response from /hello: {}", helloResponse); 89 | assertThat(helloResponse).contains("Hello"); 90 | testContext.completeNow(); 91 | }), 92 | testContext::failNow 93 | ); 94 | 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /graphql-transport-ws/src/main/java/com/example/demo/service/PostService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.gql.types.*; 4 | import com.example.demo.model.CommentEntity; 5 | import com.example.demo.model.PostEntity; 6 | import com.example.demo.repository.AuthorRepository; 7 | import com.example.demo.repository.CommentRepository; 8 | import com.example.demo.repository.PostRepository; 9 | import io.vertx.core.Future; 10 | import lombok.RequiredArgsConstructor; 11 | import org.apache.commons.lang3.Validate; 12 | 13 | import java.util.List; 14 | import java.util.Set; 15 | import java.util.UUID; 16 | import java.util.function.Function; 17 | 18 | @RequiredArgsConstructor 19 | public class PostService { 20 | 21 | private static final Function POST_MAPPER = p -> Post.builder() 22 | .id(p.id().toString()) 23 | .title(p.title()) 24 | .content(p.content()) 25 | .status(PostStatus.valueOf(p.status())) 26 | .createdAt(p.createdAt()) 27 | .authorId(p.authorId().toString()) 28 | .build(); 29 | public static final Function COMMENT_MAPPER = c -> Comment.builder() 30 | .id(c.id().toString()) 31 | .content(c.content()) 32 | .createdAt(c.createdAt()) 33 | .postId(c.postId().toString()) 34 | .build(); 35 | 36 | final PostRepository posts; 37 | final CommentRepository comments; 38 | final AuthorRepository authors; 39 | 40 | 41 | public Future> getAllPosts() { 42 | return this.posts.findAll() 43 | .map( 44 | posts -> posts.stream() 45 | .map(POST_MAPPER) 46 | .toList() 47 | ); 48 | } 49 | 50 | public Future getPostById(String id) { 51 | var postEntity = this.posts.findById(UUID.fromString(id)); 52 | return postEntity.map(POST_MAPPER); 53 | } 54 | 55 | Future> getPostsByAuthorId(String id) { 56 | return this.posts.findByAuthorId(UUID.fromString(id)) 57 | .map( 58 | posts -> posts.stream() 59 | .map(POST_MAPPER) 60 | .toList() 61 | ); 62 | } 63 | 64 | public Future createPost(CreatePostInput postInput) { 65 | Validate.notNull(postInput, "CreatePostInput can not be null"); 66 | Validate.notEmpty(postInput.getTitle(), "CreatePostInput.title can not be empty"); 67 | // Use a hard code user id here. 68 | // In a real world application, the author is the current user which can be fetched from Spring security context. 69 | return this.authors.findAll().flatMap( 70 | result -> { 71 | var authorId = result.get(0).id(); 72 | return this.posts.create(postInput.getTitle(), postInput.getContent(), "DRAFT", authorId); 73 | } 74 | ); 75 | 76 | } 77 | 78 | public Future addComment(CommentInput input) { 79 | return this.comments.create(input.getContent(), UUID.fromString(input.getPostId())); 80 | } 81 | 82 | public Future getCommentById(String id) { 83 | var commentById = this.comments.findById(UUID.fromString(id)); 84 | return commentById.map(COMMENT_MAPPER); 85 | } 86 | 87 | public Future> getCommentsByPostId(String id) { 88 | return this.comments.findByPostId(UUID.fromString(id)) 89 | .map(comments -> comments.stream() 90 | .map(COMMENT_MAPPER) 91 | .toList() 92 | ); 93 | } 94 | 95 | public Future> getCommentsByPostIdIn(Set ids) { 96 | var uuids = ids.stream().map(UUID::fromString).toList(); 97 | return this.comments.findByPostIdIn(uuids) 98 | .map(comments -> comments.stream() 99 | .map(COMMENT_MAPPER) 100 | .toList() 101 | ); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /graphql-http/src/main/java/com/example/demo/service/PostService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.gql.types.*; 4 | import com.example.demo.model.CommentEntity; 5 | import com.example.demo.model.PostEntity; 6 | import com.example.demo.repository.AuthorRepository; 7 | import com.example.demo.repository.CommentRepository; 8 | import com.example.demo.repository.PostRepository; 9 | import io.vertx.core.Future; 10 | import lombok.RequiredArgsConstructor; 11 | import org.apache.commons.lang3.Validate; 12 | 13 | import java.util.List; 14 | import java.util.Set; 15 | import java.util.UUID; 16 | import java.util.function.Function; 17 | 18 | @RequiredArgsConstructor 19 | public class PostService { 20 | 21 | private static final Function POST_MAPPER = p -> Post.builder() 22 | .id(p.id().toString()) 23 | .title(p.title()) 24 | .content(p.content()) 25 | .status(PostStatus.valueOf(p.status())) 26 | .createdAt(p.createdAt()) 27 | .authorId(p.authorId() != null ? p.authorId().toString() : null) 28 | .build(); 29 | public static final Function COMMENT_MAPPER = c -> Comment.builder() 30 | .id(c.id().toString()) 31 | .content(c.content()) 32 | .createdAt(c.createdAt()) 33 | .postId(c.postId().toString()) 34 | .build(); 35 | 36 | final PostRepository posts; 37 | final CommentRepository comments; 38 | final AuthorRepository authors; 39 | 40 | 41 | public Future> getAllPosts() { 42 | return this.posts.findAll() 43 | .map( 44 | posts -> posts.stream() 45 | .map(POST_MAPPER) 46 | .toList() 47 | ); 48 | } 49 | 50 | public Future getPostById(String id) { 51 | var postEntity = this.posts.findById(UUID.fromString(id)); 52 | return postEntity.map(POST_MAPPER); 53 | } 54 | 55 | Future> getPostsByAuthorId(String id) { 56 | return this.posts.findByAuthorId(UUID.fromString(id)) 57 | .map( 58 | posts -> posts.stream() 59 | .map(POST_MAPPER) 60 | .toList() 61 | ); 62 | } 63 | 64 | public Future createPost(CreatePostInput postInput) { 65 | Validate.notNull(postInput, "CreatePostInput can not be null"); 66 | Validate.notEmpty(postInput.getTitle(), "CreatePostInput.title can not be empty"); 67 | // Use a hard code user id here. 68 | // In a real world application, the author is the current user which can be fetched from Spring security context. 69 | return this.authors.findAll().flatMap( 70 | result -> { 71 | var authorId = result.get(0).id(); 72 | return this.posts.create(postInput.getTitle(), postInput.getContent(), "DRAFT", authorId); 73 | } 74 | ); 75 | 76 | } 77 | 78 | public Future addComment(CommentInput input) { 79 | return this.comments.create(input.getContent(), UUID.fromString(input.getPostId())); 80 | } 81 | 82 | public Future getCommentById(String id) { 83 | var commentById = this.comments.findById(UUID.fromString(id)); 84 | return commentById.map(COMMENT_MAPPER); 85 | } 86 | 87 | public Future> getCommentsByPostId(String id) { 88 | return this.comments.findByPostId(UUID.fromString(id)) 89 | .map(comments -> comments.stream() 90 | .map(COMMENT_MAPPER) 91 | .toList() 92 | ); 93 | } 94 | 95 | public Future> getCommentsByPostIdIn(Set ids) { 96 | var uuids = ids.stream().map(UUID::fromString).toList(); 97 | return this.comments.findByPostIdIn(uuids) 98 | .map(comments -> comments.stream() 99 | .map(COMMENT_MAPPER) 100 | .toList() 101 | ); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /cdi/.gitignore: -------------------------------------------------------------------------------- 1 | ### Vert.x ### 2 | .vertx/ 3 | 4 | ### Eclipse ### 5 | 6 | .metadata 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | .recommenders 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # PyDev specific (Python IDE for Eclipse) 25 | *.pydevproject 26 | 27 | # CDT-specific (C/C++ Development Tooling) 28 | .cproject 29 | 30 | # Java annotation processor (APT) 31 | .factorypath 32 | 33 | # PDT-specific (PHP Development Tools) 34 | .buildpath 35 | 36 | # sbteclipse plugin 37 | .target 38 | 39 | # Tern plugin 40 | .tern-project 41 | 42 | # TeXlipse plugin 43 | .texlipse 44 | 45 | # STS (Spring Tool Suite) 46 | .springBeans 47 | 48 | # Code Recommenders 49 | .recommenders/ 50 | 51 | # Scala IDE specific (Scala & Java development for Eclipse) 52 | .cache-main 53 | .scala_dependencies 54 | .worksheet 55 | 56 | ### Intellij+iml ### 57 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 58 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 59 | 60 | # User-specific stuff: 61 | .idea/**/workspace.xml 62 | .idea/**/tasks.xml 63 | .idea/dictionaries 64 | 65 | # Sensitive or high-churn files: 66 | .idea/**/dataSources/ 67 | .idea/**/dataSources.ids 68 | .idea/**/dataSources.xml 69 | .idea/**/dataSources.local.xml 70 | .idea/**/sqlDataSources.xml 71 | .idea/**/dynamic.xml 72 | .idea/**/uiDesigner.xml 73 | 74 | # Gradle: 75 | .idea/**/gradle.xml 76 | .idea/**/libraries 77 | 78 | # CMake 79 | cmake-buildTool-debug/ 80 | 81 | # Mongo Explorer plugin: 82 | .idea/**/mongoSettings.xml 83 | 84 | ## File-based project format: 85 | *.iws 86 | 87 | ## Plugin-specific files: 88 | 89 | # IntelliJ 90 | /out/ 91 | 92 | # mpeltonen/sbt-idea plugin 93 | .idea_modules/ 94 | 95 | # JIRA plugin 96 | atlassian-ide-plugin.xml 97 | 98 | # Cursive Clojure plugin 99 | .idea/replstate.xml 100 | 101 | # Crashlytics plugin (for Android Studio and IntelliJ) 102 | com_crashlytics_export_strings.xml 103 | crashlytics.properties 104 | crashlytics-buildTool.properties 105 | fabric.properties 106 | 107 | ### Intellij+iml Patch ### 108 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 109 | 110 | *.iml 111 | modules.xml 112 | .idea/misc.xml 113 | *.ipr 114 | 115 | ### macOS ### 116 | *.DS_Store 117 | .AppleDouble 118 | .LSOverride 119 | 120 | # Icon must end with two \r 121 | Icon 122 | 123 | # Thumbnails 124 | ._* 125 | 126 | # Files that might appear in the root of a volume 127 | .DocumentRevisions-V100 128 | .fseventsd 129 | .Spotlight-V100 130 | .TemporaryItems 131 | .Trashes 132 | .VolumeIcon.icns 133 | .com.apple.timemachine.donotpresent 134 | 135 | # Directories potentially created on remote AFP share 136 | .AppleDB 137 | .AppleDesktop 138 | Network Trash Folder 139 | Temporary Items 140 | .apdisk 141 | 142 | ### Maven ### 143 | target/ 144 | pom.xml.tag 145 | pom.xml.releaseBackup 146 | pom.xml.versionsBackup 147 | pom.xml.next 148 | release.properties 149 | dependency-reduced-pom.xml 150 | buildNumber.properties 151 | .mvn/timing.properties 152 | 153 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 154 | !/.mvn/wrapper/maven-wrapper.jar 155 | 156 | ### Gradle ### 157 | .gradle 158 | /buildTool/ 159 | 160 | # Ignore Gradle GUI config 161 | gradle-app.setting 162 | 163 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 164 | !gradle-wrapper.jar 165 | 166 | # Cache of project 167 | .gradletasknamecache 168 | 169 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 170 | # gradle/wrapper/gradle-wrapper.properties 171 | 172 | ### NetBeans ### 173 | nbproject/private/ 174 | buildTool/ 175 | nbbuild/ 176 | dist/ 177 | nbdist/ 178 | .nb-gradle/ 179 | 180 | ### VisualStudioCode ### 181 | .vscode/* 182 | !.vscode/settings.json 183 | !.vscode/tasks.json 184 | !.vscode/launch.json 185 | !.vscode/extensions.json 186 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | ### Vert.x ### 2 | .vertx/ 3 | 4 | ### Eclipse ### 5 | 6 | .metadata 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | .recommenders 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # PyDev specific (Python IDE for Eclipse) 25 | *.pydevproject 26 | 27 | # CDT-specific (C/C++ Development Tooling) 28 | .cproject 29 | 30 | # Java annotation processor (APT) 31 | .factorypath 32 | 33 | # PDT-specific (PHP Development Tools) 34 | .buildpath 35 | 36 | # sbteclipse plugin 37 | .target 38 | 39 | # Tern plugin 40 | .tern-project 41 | 42 | # TeXlipse plugin 43 | .texlipse 44 | 45 | # STS (Spring Tool Suite) 46 | .springBeans 47 | 48 | # Code Recommenders 49 | .recommenders/ 50 | 51 | # Scala IDE specific (Scala & Java development for Eclipse) 52 | .cache-main 53 | .scala_dependencies 54 | .worksheet 55 | 56 | ### Intellij+iml ### 57 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 58 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 59 | 60 | # User-specific stuff: 61 | .idea/**/workspace.xml 62 | .idea/**/tasks.xml 63 | .idea/dictionaries 64 | 65 | # Sensitive or high-churn files: 66 | .idea/**/dataSources/ 67 | .idea/**/dataSources.ids 68 | .idea/**/dataSources.xml 69 | .idea/**/dataSources.local.xml 70 | .idea/**/sqlDataSources.xml 71 | .idea/**/dynamic.xml 72 | .idea/**/uiDesigner.xml 73 | 74 | # Gradle: 75 | .idea/**/gradle.xml 76 | .idea/**/libraries 77 | 78 | # CMake 79 | cmake-buildTool-debug/ 80 | 81 | # Mongo Explorer plugin: 82 | .idea/**/mongoSettings.xml 83 | 84 | ## File-based project format: 85 | *.iws 86 | 87 | ## Plugin-specific files: 88 | 89 | # IntelliJ 90 | /out/ 91 | 92 | # mpeltonen/sbt-idea plugin 93 | .idea_modules/ 94 | 95 | # JIRA plugin 96 | atlassian-ide-plugin.xml 97 | 98 | # Cursive Clojure plugin 99 | .idea/replstate.xml 100 | 101 | # Crashlytics plugin (for Android Studio and IntelliJ) 102 | com_crashlytics_export_strings.xml 103 | crashlytics.properties 104 | crashlytics-buildTool.properties 105 | fabric.properties 106 | 107 | ### Intellij+iml Patch ### 108 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 109 | 110 | *.iml 111 | modules.xml 112 | .idea/misc.xml 113 | *.ipr 114 | 115 | ### macOS ### 116 | *.DS_Store 117 | .AppleDouble 118 | .LSOverride 119 | 120 | # Icon must end with two \r 121 | Icon 122 | 123 | # Thumbnails 124 | ._* 125 | 126 | # Files that might appear in the root of a volume 127 | .DocumentRevisions-V100 128 | .fseventsd 129 | .Spotlight-V100 130 | .TemporaryItems 131 | .Trashes 132 | .VolumeIcon.icns 133 | .com.apple.timemachine.donotpresent 134 | 135 | # Directories potentially created on remote AFP share 136 | .AppleDB 137 | .AppleDesktop 138 | Network Trash Folder 139 | Temporary Items 140 | .apdisk 141 | 142 | ### Maven ### 143 | target/ 144 | pom.xml.tag 145 | pom.xml.releaseBackup 146 | pom.xml.versionsBackup 147 | pom.xml.next 148 | release.properties 149 | dependency-reduced-pom.xml 150 | buildNumber.properties 151 | .mvn/timing.properties 152 | 153 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 154 | !/.mvn/wrapper/maven-wrapper.jar 155 | 156 | ### Gradle ### 157 | .gradle 158 | /buildTool/ 159 | 160 | # Ignore Gradle GUI config 161 | gradle-app.setting 162 | 163 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 164 | !gradle-wrapper.jar 165 | 166 | # Cache of project 167 | .gradletasknamecache 168 | 169 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 170 | # gradle/wrapper/gradle-wrapper.properties 171 | 172 | ### NetBeans ### 173 | nbproject/private/ 174 | buildTool/ 175 | nbbuild/ 176 | dist/ 177 | nbdist/ 178 | .nb-gradle/ 179 | 180 | ### VisualStudioCode ### 181 | .vscode/* 182 | !.vscode/settings.json 183 | !.vscode/tasks.json 184 | !.vscode/launch.json 185 | !.vscode/extensions.json 186 | -------------------------------------------------------------------------------- /kotlin/.gitignore: -------------------------------------------------------------------------------- 1 | ### Vert.x ### 2 | .vertx/ 3 | 4 | ### Eclipse ### 5 | 6 | .metadata 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | .recommenders 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # PyDev specific (Python IDE for Eclipse) 25 | *.pydevproject 26 | 27 | # CDT-specific (C/C++ Development Tooling) 28 | .cproject 29 | 30 | # Java annotation processor (APT) 31 | .factorypath 32 | 33 | # PDT-specific (PHP Development Tools) 34 | .buildpath 35 | 36 | # sbteclipse plugin 37 | .target 38 | 39 | # Tern plugin 40 | .tern-project 41 | 42 | # TeXlipse plugin 43 | .texlipse 44 | 45 | # STS (Spring Tool Suite) 46 | .springBeans 47 | 48 | # Code Recommenders 49 | .recommenders/ 50 | 51 | # Scala IDE specific (Scala & Java development for Eclipse) 52 | .cache-main 53 | .scala_dependencies 54 | .worksheet 55 | 56 | ### Intellij+iml ### 57 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 58 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 59 | 60 | # User-specific stuff: 61 | .idea/**/workspace.xml 62 | .idea/**/tasks.xml 63 | .idea/dictionaries 64 | 65 | # Sensitive or high-churn files: 66 | .idea/**/dataSources/ 67 | .idea/**/dataSources.ids 68 | .idea/**/dataSources.xml 69 | .idea/**/dataSources.local.xml 70 | .idea/**/sqlDataSources.xml 71 | .idea/**/dynamic.xml 72 | .idea/**/uiDesigner.xml 73 | 74 | # Gradle: 75 | .idea/**/gradle.xml 76 | .idea/**/libraries 77 | 78 | # CMake 79 | cmake-buildTool-debug/ 80 | 81 | # Mongo Explorer plugin: 82 | .idea/**/mongoSettings.xml 83 | 84 | ## File-based project format: 85 | *.iws 86 | 87 | ## Plugin-specific files: 88 | 89 | # IntelliJ 90 | /out/ 91 | 92 | # mpeltonen/sbt-idea plugin 93 | .idea_modules/ 94 | 95 | # JIRA plugin 96 | atlassian-ide-plugin.xml 97 | 98 | # Cursive Clojure plugin 99 | .idea/replstate.xml 100 | 101 | # Crashlytics plugin (for Android Studio and IntelliJ) 102 | com_crashlytics_export_strings.xml 103 | crashlytics.properties 104 | crashlytics-buildTool.properties 105 | fabric.properties 106 | 107 | ### Intellij+iml Patch ### 108 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 109 | 110 | *.iml 111 | modules.xml 112 | .idea/misc.xml 113 | *.ipr 114 | 115 | ### macOS ### 116 | *.DS_Store 117 | .AppleDouble 118 | .LSOverride 119 | 120 | # Icon must end with two \r 121 | Icon 122 | 123 | # Thumbnails 124 | ._* 125 | 126 | # Files that might appear in the root of a volume 127 | .DocumentRevisions-V100 128 | .fseventsd 129 | .Spotlight-V100 130 | .TemporaryItems 131 | .Trashes 132 | .VolumeIcon.icns 133 | .com.apple.timemachine.donotpresent 134 | 135 | # Directories potentially created on remote AFP share 136 | .AppleDB 137 | .AppleDesktop 138 | Network Trash Folder 139 | Temporary Items 140 | .apdisk 141 | 142 | ### Maven ### 143 | target/ 144 | pom.xml.tag 145 | pom.xml.releaseBackup 146 | pom.xml.versionsBackup 147 | pom.xml.next 148 | release.properties 149 | dependency-reduced-pom.xml 150 | buildNumber.properties 151 | .mvn/timing.properties 152 | 153 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 154 | !/.mvn/wrapper/maven-wrapper.jar 155 | 156 | ### Gradle ### 157 | .gradle 158 | /buildTool/ 159 | 160 | # Ignore Gradle GUI config 161 | gradle-app.setting 162 | 163 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 164 | !gradle-wrapper.jar 165 | 166 | # Cache of project 167 | .gradletasknamecache 168 | 169 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 170 | # gradle/wrapper/gradle-wrapper.properties 171 | 172 | ### NetBeans ### 173 | nbproject/private/ 174 | buildTool/ 175 | nbbuild/ 176 | dist/ 177 | nbdist/ 178 | .nb-gradle/ 179 | 180 | ### VisualStudioCode ### 181 | .vscode/* 182 | !.vscode/settings.json 183 | !.vscode/tasks.json 184 | !.vscode/launch.json 185 | !.vscode/extensions.json 186 | -------------------------------------------------------------------------------- /rxjava3/.gitignore: -------------------------------------------------------------------------------- 1 | ### Vert.x ### 2 | .vertx/ 3 | 4 | ### Eclipse ### 5 | 6 | .metadata 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | .recommenders 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # PyDev specific (Python IDE for Eclipse) 25 | *.pydevproject 26 | 27 | # CDT-specific (C/C++ Development Tooling) 28 | .cproject 29 | 30 | # Java annotation processor (APT) 31 | .factorypath 32 | 33 | # PDT-specific (PHP Development Tools) 34 | .buildpath 35 | 36 | # sbteclipse plugin 37 | .target 38 | 39 | # Tern plugin 40 | .tern-project 41 | 42 | # TeXlipse plugin 43 | .texlipse 44 | 45 | # STS (Spring Tool Suite) 46 | .springBeans 47 | 48 | # Code Recommenders 49 | .recommenders/ 50 | 51 | # Scala IDE specific (Scala & Java development for Eclipse) 52 | .cache-main 53 | .scala_dependencies 54 | .worksheet 55 | 56 | ### Intellij+iml ### 57 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 58 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 59 | 60 | # User-specific stuff: 61 | .idea/**/workspace.xml 62 | .idea/**/tasks.xml 63 | .idea/dictionaries 64 | 65 | # Sensitive or high-churn files: 66 | .idea/**/dataSources/ 67 | .idea/**/dataSources.ids 68 | .idea/**/dataSources.xml 69 | .idea/**/dataSources.local.xml 70 | .idea/**/sqlDataSources.xml 71 | .idea/**/dynamic.xml 72 | .idea/**/uiDesigner.xml 73 | 74 | # Gradle: 75 | .idea/**/gradle.xml 76 | .idea/**/libraries 77 | 78 | # CMake 79 | cmake-buildTool-debug/ 80 | 81 | # Mongo Explorer plugin: 82 | .idea/**/mongoSettings.xml 83 | 84 | ## File-based project format: 85 | *.iws 86 | 87 | ## Plugin-specific files: 88 | 89 | # IntelliJ 90 | /out/ 91 | 92 | # mpeltonen/sbt-idea plugin 93 | .idea_modules/ 94 | 95 | # JIRA plugin 96 | atlassian-ide-plugin.xml 97 | 98 | # Cursive Clojure plugin 99 | .idea/replstate.xml 100 | 101 | # Crashlytics plugin (for Android Studio and IntelliJ) 102 | com_crashlytics_export_strings.xml 103 | crashlytics.properties 104 | crashlytics-buildTool.properties 105 | fabric.properties 106 | 107 | ### Intellij+iml Patch ### 108 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 109 | 110 | *.iml 111 | modules.xml 112 | .idea/misc.xml 113 | *.ipr 114 | 115 | ### macOS ### 116 | *.DS_Store 117 | .AppleDouble 118 | .LSOverride 119 | 120 | # Icon must end with two \r 121 | Icon 122 | 123 | # Thumbnails 124 | ._* 125 | 126 | # Files that might appear in the root of a volume 127 | .DocumentRevisions-V100 128 | .fseventsd 129 | .Spotlight-V100 130 | .TemporaryItems 131 | .Trashes 132 | .VolumeIcon.icns 133 | .com.apple.timemachine.donotpresent 134 | 135 | # Directories potentially created on remote AFP share 136 | .AppleDB 137 | .AppleDesktop 138 | Network Trash Folder 139 | Temporary Items 140 | .apdisk 141 | 142 | ### Maven ### 143 | target/ 144 | pom.xml.tag 145 | pom.xml.releaseBackup 146 | pom.xml.versionsBackup 147 | pom.xml.next 148 | release.properties 149 | dependency-reduced-pom.xml 150 | buildNumber.properties 151 | .mvn/timing.properties 152 | 153 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 154 | !/.mvn/wrapper/maven-wrapper.jar 155 | 156 | ### Gradle ### 157 | .gradle 158 | /buildTool/ 159 | 160 | # Ignore Gradle GUI config 161 | gradle-app.setting 162 | 163 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 164 | !gradle-wrapper.jar 165 | 166 | # Cache of project 167 | .gradletasknamecache 168 | 169 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 170 | # gradle/wrapper/gradle-wrapper.properties 171 | 172 | ### NetBeans ### 173 | nbproject/private/ 174 | buildTool/ 175 | nbbuild/ 176 | dist/ 177 | nbdist/ 178 | .nb-gradle/ 179 | 180 | ### VisualStudioCode ### 181 | .vscode/* 182 | !.vscode/settings.json 183 | !.vscode/tasks.json 184 | !.vscode/launch.json 185 | !.vscode/extensions.json 186 | --------------------------------------------------------------------------------