diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..dcd4165 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: CI + +on: + push: + branches: [master, main] + pull_request: + branches: [master, main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 25 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '25' + cache: maven + + - name: Build and test + run: mvn -B -ntp verify diff --git a/.gitignore b/.gitignore index 57f1cb2..4a9ac2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,18 @@ -/.idea/ \ No newline at end of file +target/ +build/ +out/ + +.idea/ +*.iml +*.ipr +*.iws +.vscode/ +.project +.classpath +.settings/ + +.DS_Store +Thumbs.db + +*.log +*.class diff --git a/.gitignore.txt b/.gitignore.txt deleted file mode 100644 index 57f1cb2..0000000 --- a/.gitignore.txt +++ /dev/null @@ -1 +0,0 @@ -/.idea/ \ No newline at end of file diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index a156ef4..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -gs-spring-boot \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index daa2f90..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index ba88c4b..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml b/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml deleted file mode 100644 index 6fec8f4..0000000 --- a/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml b/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml deleted file mode 100644 index 9eb8596..0000000 --- a/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_classmate_1_3_4.xml b/.idea/libraries/Maven__com_fasterxml_classmate_1_3_4.xml deleted file mode 100644 index 33c30b4..0000000 --- a/.idea/libraries/Maven__com_fasterxml_classmate_1_3_4.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_9_0.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_9_0.xml deleted file mode 100644 index 06441f4..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_9_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_9_5.xml deleted file mode 100644 index 1205e0d..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_9_5.xml deleted file mode 100644 index 467b779..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_9_5.xml deleted file mode 100644 index 65b251d..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_9_5.xml deleted file mode 100644 index c85f307..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_9_5.xml deleted file mode 100644 index 4ace22a..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_h2database_h2_1_4_197.xml b/.idea/libraries/Maven__com_h2database_h2_1_4_197.xml deleted file mode 100644 index 87c599a..0000000 --- a/.idea/libraries/Maven__com_h2database_h2_1_4_197.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_zaxxer_HikariCP_2_7_9.xml b/.idea/libraries/Maven__com_zaxxer_HikariCP_2_7_9.xml deleted file mode 100644 index 6d6865c..0000000 --- a/.idea/libraries/Maven__com_zaxxer_HikariCP_2_7_9.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml b/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml deleted file mode 100644 index e74f3ab..0000000 --- a/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__javax_validation_validation_api_2_0_1_Final.xml b/.idea/libraries/Maven__javax_validation_validation_api_2_0_1_Final.xml deleted file mode 100644 index 6978c0b..0000000 --- a/.idea/libraries/Maven__javax_validation_validation_api_2_0_1_Final.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_10_0.xml b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_10_0.xml deleted file mode 100644 index cbe5ca7..0000000 --- a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_10_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_10_0.xml b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_10_0.xml deleted file mode 100644 index 1407c58..0000000 --- a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_10_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_31.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_31.xml deleted file mode 100644 index a6693a2..0000000 --- a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_31.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_31.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_31.xml deleted file mode 100644 index bc00163..0000000 --- a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_31.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_31.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_31.xml deleted file mode 100644 index a47a3be..0000000 --- a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_31.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_9_Final.xml b/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_9_Final.xml deleted file mode 100644 index 5a26bec..0000000 --- a/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_9_Final.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_2_Final.xml b/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_2_Final.xml deleted file mode 100644 index 5f7dd01..0000000 --- a/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_2_Final.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml b/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml deleted file mode 100644 index 6073e53..0000000 --- a/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_25.xml b/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_25.xml deleted file mode 100644 index 20e8163..0000000 --- a/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_25.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_0_2_RELEASE.xml deleted file mode 100644 index 216fa5d..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_0_2_RELEASE.xml deleted file mode 100644 index 416393d..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_0_2_RELEASE.xml deleted file mode 100644 index f4f17f8..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_jdbc_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_jdbc_2_0_2_RELEASE.xml deleted file mode 100644 index 1fe0fd1..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_jdbc_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_0_2_RELEASE.xml deleted file mode 100644 index 7f64d70..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_0_2_RELEASE.xml deleted file mode 100644 index 73c5114..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_0_2_RELEASE.xml deleted file mode 100644 index 15cdbc9..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_0_2_RELEASE.xml deleted file mode 100644 index ab4ca86..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_aop_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_aop_5_0_6_RELEASE.xml deleted file mode 100644 index 45ed002..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_aop_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_beans_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_beans_5_0_6_RELEASE.xml deleted file mode 100644 index c046b8d..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_beans_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_context_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_context_5_0_6_RELEASE.xml deleted file mode 100644 index 9b830cd..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_context_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_core_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_core_5_0_6_RELEASE.xml deleted file mode 100644 index 597e34e..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_core_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_expression_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_expression_5_0_6_RELEASE.xml deleted file mode 100644 index ffca824..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_expression_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_jcl_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_jcl_5_0_6_RELEASE.xml deleted file mode 100644 index c0a9cc7..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_jcl_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_jdbc_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_jdbc_5_0_6_RELEASE.xml deleted file mode 100644 index 671875f..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_jdbc_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_tx_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_tx_5_0_6_RELEASE.xml deleted file mode 100644 index 6e29e18..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_tx_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_web_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_web_5_0_6_RELEASE.xml deleted file mode 100644 index 521bb85..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_web_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_webmvc_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_webmvc_5_0_6_RELEASE.xml deleted file mode 100644 index e4279b7..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_webmvc_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_yaml_snakeyaml_1_19.xml b/.idea/libraries/Maven__org_yaml_snakeyaml_1_19.xml deleted file mode 100644 index 33ccf19..0000000 --- a/.idea/libraries/Maven__org_yaml_snakeyaml_1_19.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 01b5b5c..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 751276b..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index e90adcd..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,943 +0,0 @@ - - - - - - - - - - - - hello.controller.* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HelloController - aslist - compata - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1526804939552 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - file://$PROJECT_DIR$/src/main/java/hello/controller/GreetingController.java - 15 - - - - file://$PROJECT_DIR$/src/main/java/hello/controller/HelloController.java - 55 - - - - - - - - - ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)) - JAVA - CODE_FRAGMENT - - - ZonedDateTime.of(getLocalDateTime(), getZoneId("UTC-04:00")) - JAVA - CODE_FRAGMENT - - - - - getZoneId(zoneString) - JAVA - EXPRESSION - - - topics.stream().filter(topic -> topic.getId().equals(id)).findFirst().get() - JAVA - EXPRESSION - - - topics.stream().filter(topic -> topic.getId().equals(id)) - JAVA - EXPRESSION - - - topics.stream().filter(topicId -> topicId.equals(id)) - JAVA - EXPRESSION - - - topics.stream().filter(topicId -> topicId.equals(id)).findFirst().get() - JAVA - EXPRESSION - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No facets are configured - - - - - - - - - - - - - - - 1.8 - - - - - - - - gs-spring-boot - - - - - - - - Maven: ch.qos.logback:logback-classic:1.2.3 - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 2b09400..da59331 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,51 @@ -# springboot-java8 -The project is made on spring boot. The project summarize the new features present in Java 8. -It contain list of harcoded topics list. You can call the apis's with POSTMAN to add,delete,update Topic list -In addition, it uses -1) Java 8 NIO methods +# springboot-java-modern (formerly springboot-java8) +Spring Boot REST service showcasing modern Java APIs. Originally a Java 8 demo, +upgraded to **Java 25 (LTS)** and **Spring Boot 3.4** with a batch of quality +improvements. + +The service exposes a CRUD API over an in-memory list of topics plus endpoints +that demonstrate stream, file, string, and date-time APIs. Call the endpoints +with `curl`, Postman, or the bundled Swagger UI. + +Language/library features demonstrated: + +1) NIO (`java.nio.file`) streams 2) String operations -3) Stream operations -4) IntStream functions -5) Functional interface -6) Lambda functions -7) Optional datatype -8) Foreach loops -9) Default and Static methods in interface -10) Java 8 LocalDateTime API -11) Pattern +3) `Stream` operations +4) `IntStream` +5) Functional interfaces +6) Lambdas +7) `Optional` +8) `forEach` +9) Default & static methods on interfaces +10) `java.time` (LocalDateTime, ZonedDateTime) +11) `Pattern` +12) Records (Java 16+) +13) Text blocks (Java 15+) +14) `String.formatted` (Java 15+) +15) `Stream#toList` (Java 16+) +16) `Pattern#asMatchPredicate` (Java 11+) ## Getting Started -1) Download or clone the project with link -(https://github.com/RehmanMuradAli/springboot-java8/) -## Available API's +```bash +# build + test +./mvnw verify + +# run +./mvnw spring-boot:run +``` + +Then visit: +- `http://localhost:8080/` — Greeting endpoint +- `http://localhost:8080/swagger-ui.html` — OpenAPI UI +- `http://localhost:8080/actuator/health` — Health check + +## Available APIs -Greetings +Greeting ``` GET / ``` @@ -129,6 +152,6 @@ https://dzone.com/articles/java-8-friday-goodies-new-new ## Authors -* **Rehman Murad Ali** +* **Rehman Murad Ali** diff --git a/application.properties b/application.properties deleted file mode 100644 index d3baf26..0000000 --- a/application.properties +++ /dev/null @@ -1 +0,0 @@ -#server.port = 8081 \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 09f1083..0000000 --- a/build.gradle +++ /dev/null @@ -1,32 +0,0 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.2.RELEASE") - } -} - -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -bootJar { - baseName = 'gs-spring-boot' - version = '0.1.0' -} - -repositories { - mavenCentral() -} - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -dependencies { - compile("org.springframework.boot:spring-boot-starter-web") - testCompile("junit:junit") -} - diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index ca78035..0000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a2ff3cc..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Thu Mar 01 09:01:15 CST 2018 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip diff --git a/gradlew b/gradlew deleted file mode 100644 index 27309d9..0000000 --- a/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 832fdb6..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/gs-spring-boot.iml b/gs-spring-boot.iml deleted file mode 100644 index ad195a8..0000000 --- a/gs-spring-boot.iml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 63f5cbd..178a3d3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,43 +1,61 @@ - + 4.0.0 - org.springframework - gs-spring-boot - pom - 0.1.0 + hello + springboot-java-modern + 1.0.0 + jar + + springboot-java-modern + Spring Boot REST service showcasing modern Java APIs (upgraded from Java 8) org.springframework.boot spring-boot-starter-parent - 2.0.2.RELEASE + 3.5.0 + + + 25 + 25 + UTF-8 + 2.7.0 + + org.springframework.boot - spring-boot-properties-migrator - runtime + spring-boot-starter-web org.springframework.boot - spring-boot-starter-web + spring-boot-starter-jdbc org.springframework.boot - spring-boot-starter-jdbc + spring-boot-starter-actuator com.h2database h2 + runtime + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc-openapi.version} - - - - 1.8 - + + org.springframework.boot + spring-boot-starter-test + test + + diff --git a/src/main/java/hello/Application.java b/src/main/java/hello/Application.java index 7cf8faf..44090f5 100644 --- a/src/main/java/hello/Application.java +++ b/src/main/java/hello/Application.java @@ -1,88 +1,51 @@ package hello; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - import hello.model.Customer; -import hello.model.Quote; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.ApplicationContext; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.web.client.RestTemplate; + +import java.util.List; @SpringBootApplication -public class Application implements CommandLineRunner { +public class Application { private static final Logger log = LoggerFactory.getLogger(Application.class); public static void main(String[] args) { - - ApplicationContext ctx = SpringApplication.run(Application.class, args); - - System.out.println("Let's inspect the beans provided by Spring Boot:"); - - String[] beanNames = ctx.getBeanDefinitionNames(); - Arrays.sort(beanNames); - for (String beanName : beanNames) { - System.out.println(beanName); - } - - RestTemplate restTemplate = new RestTemplate(); - Quote quote = restTemplate.getForObject("http://gturnquist-quoters.cfapps.io/api/random", Quote.class); - log.info(quote.toString()); + SpringApplication.run(Application.class, args); } - @Bean - public RestTemplate restTemplate(RestTemplateBuilder builder) { - return builder.build(); - } - - @Bean - public CommandLineRunner run(RestTemplate restTemplate) throws Exception { + @ConditionalOnBean(JdbcTemplate.class) + public CommandLineRunner seedCustomers(JdbcTemplate jdbcTemplate) { return args -> { - Quote quote = restTemplate.getForObject( - "http://gturnquist-quoters.cfapps.io/api/random", Quote.class); - log.info(quote.toString()); - }; - } - + log.info("Creating tables"); - @Autowired - JdbcTemplate jdbcTemplate; + jdbcTemplate.execute("DROP TABLE customers IF EXISTS"); + jdbcTemplate.execute("CREATE TABLE customers(id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))"); - @Override - public void run(String... args) throws Exception { - log.info("Creating tables"); + List splitUpNames = List.of("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long").stream() + .map(name -> name.split(" ")) + .map(parts -> new Object[] { parts[0], parts[1] }) + .toList(); - jdbcTemplate.execute("DROP TABLE customers IF EXISTS"); - jdbcTemplate.execute("CREATE TABLE customers(id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))"); + splitUpNames.forEach(name -> + log.info("Inserting customer record for {} {}", name[0], name[1])); - // Split up the array of whole names into an array of first/last names - List splitUpNames = Arrays.asList("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long") - .stream() - .map(name -> name.split(" ")) - .collect(Collectors.toList()); - - // Use a Java 8 stream to print out each tuple of the list - splitUpNames.forEach(name -> log.info(String.format("Inserting customer record for %s %s", name[0], name[1]))); - - // Uses JdbcTemplate's batchUpdate operation to bulk load data - jdbcTemplate.batchUpdate("INSERT INTO customers(first_name, last_name) VALUES (?,?)", splitUpNames); - - log.info("Querying for customer records where first_name = 'Josh':"); - jdbcTemplate.query( - "SELECT id, first_name, last_name FROM customers WHERE first_name = ?", new Object[]{"Josh"}, - (rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name")) - ).forEach(customer -> log.info(customer.toString())); + jdbcTemplate.batchUpdate("INSERT INTO customers(first_name, last_name) VALUES (?,?)", splitUpNames); + log.info("Querying for customer records where first_name = 'Josh':"); + jdbcTemplate.query( + "SELECT id, first_name, last_name FROM customers WHERE first_name = ?", + (rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name")), + "Josh") + .forEach(customer -> log.info(customer.toString())); + }; } } diff --git a/src/main/java/hello/controller/GreetingController.java b/src/main/java/hello/controller/GreetingController.java index cf52f8d..d59c0af 100644 --- a/src/main/java/hello/controller/GreetingController.java +++ b/src/main/java/hello/controller/GreetingController.java @@ -1,7 +1,7 @@ package hello.controller; import hello.model.Greeting; -import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -9,12 +9,11 @@ @RestController public class GreetingController { - private static final String template = "Hello, %s!"; + private static final String TEMPLATE = "Hello, %s!"; private final AtomicLong counter = new AtomicLong(); - @RequestMapping("/") - public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) { - return new Greeting(counter.incrementAndGet(), - String.format(template, name)); + @GetMapping("/") + public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) { + return new Greeting(counter.incrementAndGet(), TEMPLATE.formatted(name)); } } diff --git a/src/main/java/hello/controller/HelloController.java b/src/main/java/hello/controller/HelloController.java index f3602fa..5ab17f8 100644 --- a/src/main/java/hello/controller/HelloController.java +++ b/src/main/java/hello/controller/HelloController.java @@ -2,100 +2,71 @@ import hello.declaration.TimeClient; import hello.model.SimpleTimeClient; -import hello.model.Topic; import hello.service.TopicService; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.bind.annotation.RequestMapping; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.ZoneId; -import java.time.chrono.ChronoPeriod; import java.time.temporal.ChronoUnit; -import java.util.List; -import java.util.regex.Pattern; -import java.util.stream.Collector; -import java.util.stream.Collectors; @RestController public class HelloController { + private static final String JOIN_TEMPLATE = "Joining All String ID's with JOIN method: "; + private static final String DISTINCT_SORTED_TEMPLATE = "-------------Get all ID characters, select distict and sort with ID= "; + private static final String SPLIT_JAVA_KEYWORD_TEMPLATE = "-------------Split All Id With Colon,Select ID With \"Java\" Keyword, Then Sort Then Join "; + private static final String FIND_ID_HAVING_CHARACTER_TEMPLATE = "-------------Return All ID having character 'g' in it: "; + private static final String FIND_ALL_FILES_TEMPLATE = "---------Find all files in path and sort: "; + private static final String FIND_PARTICULAR_FILE_TEMPLATE = "----------Find File in present directory which starts with \"pom\", provided maximum depth=25 and sort : "; + private static final String FIND_PARTICULAR_FILE_WALK_TEMPLATE = "----------Find File in present directory which starts with \"pom\", provided maximum depth=25 and sort : with walk function "; + private static final String READ_FILE_TEMPLATE = "---------Read \"README.md\" file with stream functions, having \"spring\" within it: "; - String joinTemplate = "Joining All String ID's with JOIN method: "; - String makeDistinctAndSortCharactersTemplate = "-------------Get all ID characters, select distict and sort with ID= "; - String splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinTemplate = "-------------Split All Id With Colon," + - "Select ID With \"Java\" Keyword," + - " Then Sort Then Join "; - String findIdHavingCharacterTemplate = "-------------Return All ID having character \'g\' in it: "; - String findAllFilesInPathAndSortTemplate = "---------Find all files in path and sort: "; - String findParticularFileInPathAndSortTemplate = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : "; - String findParticularFileInPathAndSortWithWalkFunctionTemplate = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : with walk function"; - String readFileWithStreamFunctionTemplate = "---------Read \"temp.txt\" file with stream functions, having \"print\" witin it: "; + private final TopicService topicService; + public HelloController(TopicService topicService) { + this.topicService = topicService; + } - @Autowired - private TopicService topicService; - - /** - * Java 8 Date Time example - * - * @return - */ - @RequestMapping("/datetime") - public String index() { + @GetMapping("/datetime") + public String datetime() { TimeClient myTimeClient = new SimpleTimeClient(); - LocalDateTime localDateTime = LocalDateTime.now(); - return "Greetings from Spring Boot! ----------------------" + - "Datetime now is " + String.valueOf(myTimeClient.toString()) + "----------------------" + - "Datetime tomorrow will be " + String.valueOf(myTimeClient.getLocalDateTime().plusDays(1)) + "----------------------" + - "Datetime of previous month was " + String.valueOf(myTimeClient.getLocalDateTime().minus(1, ChronoUnit.MONTHS)) + "----------------------" + - "Is this a leap year ? " + String.valueOf(LocalDate.now().isLeapYear()) + "----------------------" + - "Default system zone id " + String.valueOf(ZoneId.systemDefault()) + "-------------------" + - "Time in California: " + myTimeClient.getZonedDateTime("Canada/Central").toString(); - + LocalDateTime now = myTimeClient.getLocalDateTime(); + return """ + Greetings from Spring Boot! ----------------------\ + Datetime now is %s----------------------\ + Datetime tomorrow will be %s----------------------\ + Datetime of previous month was %s----------------------\ + Is this a leap year ? %s----------------------\ + Default system zone id %s-------------------\ + Time in Canada/Central: %s""".formatted( + myTimeClient, + now.plusDays(1), + now.minus(1, ChronoUnit.MONTHS), + LocalDate.now().isLeapYear(), + ZoneId.systemDefault(), + myTimeClient.getZonedDateTime("Canada/Central")); } - - /** - * String Operations in Java 8 - * - * @return - */ - @RequestMapping("/topic/string/operation") + @GetMapping("/topic/string/operation") public String showStringOperation() { - String join = topicService.returnAllTopicIDWithStringSlicing(); - String makeDistinctAndSortCharacters = topicService.makeDistinctAndSortCharacters(join); - String splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin = topicService - .splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin(join); - String findIdHavingCharacter = topicService.findIdHavingCharacter(); - - return joinTemplate + join - + makeDistinctAndSortCharactersTemplate + makeDistinctAndSortCharacters - + splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinTemplate + splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin - + findIdHavingCharacterTemplate + findIdHavingCharacter; - + String distinct = topicService.makeDistinctAndSortCharacters(join); + String split = topicService.splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin(join); + String findG = topicService.findIdHavingCharacter(); + return JOIN_TEMPLATE + join + + DISTINCT_SORTED_TEMPLATE + distinct + + SPLIT_JAVA_KEYWORD_TEMPLATE + split + + FIND_ID_HAVING_CHARACTER_TEMPLATE + findG; } - - /** - * File Operation in Java 8 - * @return - */ - @RequestMapping("/topic/file/operation") + @GetMapping("/topic/file/operation") public String showFileOperation() { - String findAllFilesInPathAndSort = topicService.findAllFilesInPathAndSort(); - String findParticularFileInPathAndSort = topicService.findParticularFileInPathAndSort(); - String findParticularFileInPathAndSortWithWalkFunction = topicService.findParticularFileInPathAndSortWithWalkFunction(); - String readFileWithStreamFunction = topicService.readFileWithStreamFunction(); - return findAllFilesInPathAndSortTemplate + findAllFilesInPathAndSort - + findParticularFileInPathAndSortTemplate + findParticularFileInPathAndSort - + findParticularFileInPathAndSortWithWalkFunctionTemplate + findParticularFileInPathAndSortWithWalkFunction - + readFileWithStreamFunctionTemplate + readFileWithStreamFunction; + return FIND_ALL_FILES_TEMPLATE + topicService.findAllFilesInPathAndSort() + + FIND_PARTICULAR_FILE_TEMPLATE + topicService.findParticularFileInPathAndSort() + + FIND_PARTICULAR_FILE_WALK_TEMPLATE + topicService.findParticularFileInPathAndSortWithWalkFunction() + + READ_FILE_TEMPLATE + topicService.readFileWithStreamFunction(); } - - } diff --git a/src/main/java/hello/controller/TopicController.java b/src/main/java/hello/controller/TopicController.java index c2e8273..0f7666a 100644 --- a/src/main/java/hello/controller/TopicController.java +++ b/src/main/java/hello/controller/TopicController.java @@ -2,89 +2,66 @@ import hello.model.Topic; import hello.service.TopicService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import java.util.List; @RestController +@RequestMapping("/topic") public class TopicController { - @Autowired - private TopicService topicService; + private final TopicService topicService; + public TopicController(TopicService topicService) { + this.topicService = topicService; + } - /** - * Get all Topic - * @return - */ - @RequestMapping("/topic") + @GetMapping public List getAllTopics() { return topicService.getAllTopics(); } - /** - * get Topic with ID - * @param id - * @return - */ - @RequestMapping("/topic/{id}") + @GetMapping("/{id}") public Topic getTopicWithID(@PathVariable String id) { - return topicService.getTopicWithId(id); + return topicService.getTopicWithId(id) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Topic not found: " + id)); } - /** - * Add a new topic in list - * @param topic - */ - @RequestMapping(method = RequestMethod.POST, value = "/topic") + @PostMapping + @ResponseStatus(HttpStatus.CREATED) public void addTopic(@RequestBody Topic topic) { topicService.addTopic(topic); } - /** - * Update Topic in List with id - * @param id - * @param topic - */ - @RequestMapping(method = RequestMethod.PUT, value = "/topic/{id}") + @PutMapping("/{id}") public void updateTopic(@PathVariable String id, @RequestBody Topic topic) { topicService.updateTopic(id, topic); } - - /** - * Delete a topic with ID - * @param id - */ - @RequestMapping(method = RequestMethod.DELETE, value = "/topic/{id}") + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) public void deleteTopic(@PathVariable String id) { topicService.deleteTopic(id); } - /** - * Get all topics with Id length greater then minimum length - * @param minLength - * @return - */ - @RequestMapping(value = "/topic/minimum/length/{minLength}") + @GetMapping("/minimum/length/{minLength}") public List filterMinimumLengthForId(@PathVariable Integer minLength) { return topicService.filterMinimumLengthForId(minLength); } - - /** - * Sort with Id - * @return - */ - @RequestMapping("/topic/sort") + @GetMapping("/sort") public List sortTopicsWithID() { return topicService.sortTopicsWithID(); } - - - - - } diff --git a/src/main/java/hello/declaration/TimeClient.java b/src/main/java/hello/declaration/TimeClient.java index 80aa106..92e3c7b 100644 --- a/src/main/java/hello/declaration/TimeClient.java +++ b/src/main/java/hello/declaration/TimeClient.java @@ -4,35 +4,30 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - /** - * Implementing Defaults and Static Functions in Interface + * Demonstrates default and static methods on interfaces. */ - public interface TimeClient { void setTime(int hour, int minute, int second); + void setDate(int day, int month, int year); + void setDateAndTime(int day, int month, int year, int hour, int minute, int second); + LocalDateTime getLocalDateTime(); - static ZoneId getZoneId (String zoneString) { + static ZoneId getZoneId(String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { - System.err.println("Invalid time zone: " + zoneString + - "; using default time zone instead."); + System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } } - default ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); } - } diff --git a/src/main/java/hello/model/Customer.java b/src/main/java/hello/model/Customer.java index a6df80e..640db05 100644 --- a/src/main/java/hello/model/Customer.java +++ b/src/main/java/hello/model/Customer.java @@ -1,45 +1,4 @@ package hello.model; -public class Customer { - private long id; - private String firstName, lastName; - - @Override - public String toString() { - return "Customer{" + - "id=" + id + - ", firstName='" + firstName + '\'' + - ", lastName='" + lastName + '\'' + - '}'; - } - - public Customer(long id, String firstName, String lastName) { - this.id = id; - this.firstName = firstName; - this.lastName = lastName; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } +public record Customer(long id, String firstName, String lastName) { } diff --git a/src/main/java/hello/model/Greeting.java b/src/main/java/hello/model/Greeting.java index f2e7772..135b2fb 100644 --- a/src/main/java/hello/model/Greeting.java +++ b/src/main/java/hello/model/Greeting.java @@ -1,21 +1,4 @@ package hello.model; -public class Greeting { - private final long id; - private final String content; - - public Greeting(long id, String content) { - this.id = id; - this.content = content; - } - - - public long getId() { - - return id; - } - - public String getContent() { - return content; - } +public record Greeting(long id, String content) { } diff --git a/src/main/java/hello/model/Quote.java b/src/main/java/hello/model/Quote.java index 2178a6d..b548a67 100644 --- a/src/main/java/hello/model/Quote.java +++ b/src/main/java/hello/model/Quote.java @@ -1,34 +1,4 @@ package hello.model; -public class Quote { - private String type; - private Value value; - - @Override - public String toString() { - return "Quote{" + - "type='" + type + '\'' + - ", value=" + value + - '}'; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public Value getValue() { - return value; - } - - public void setValue(Value value) { - this.value = value; - } - - public Quote() { - - } +public record Quote(String type, Value value) { } diff --git a/src/main/java/hello/model/Topic.java b/src/main/java/hello/model/Topic.java index 483a4a7..59740dc 100644 --- a/src/main/java/hello/model/Topic.java +++ b/src/main/java/hello/model/Topic.java @@ -1,43 +1,4 @@ package hello.model; - -public class Topic { - private String id; - private String subjectName; - private String subjectDescription; - - public Topic() { - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getSubjectName() { - return subjectName; - } - - public void setSubjectName(String subjectName) { - this.subjectName = subjectName; - } - - public String getSubjectDescription() { - return subjectDescription; - } - - public void setSubjectDescription(String subjectDescription) { - this.subjectDescription = subjectDescription; - } - - public Topic(String id, String subjectName, String subjectDescription) { - super(); - this.id = id; - this.subjectName = subjectName; - this.subjectDescription = subjectDescription; - } - +public record Topic(String id, String subjectName, String subjectDescription) { } diff --git a/src/main/java/hello/model/Value.java b/src/main/java/hello/model/Value.java index 272be70..b795170 100644 --- a/src/main/java/hello/model/Value.java +++ b/src/main/java/hello/model/Value.java @@ -1,33 +1,4 @@ package hello.model; -public class Value { - private Long id; - private String quote; - - public Value() { - } - - @Override - public String toString() { - return "Value{" + - "id=" + id + - ", quote='" + quote + '\'' + - '}'; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getQuote() { - return quote; - } - - public void setQuote(String quote) { - this.quote = quote; - } +public record Value(Long id, String quote) { } diff --git a/src/main/java/hello/service/TopicService.java b/src/main/java/hello/service/TopicService.java index feffb92..a223d6a 100644 --- a/src/main/java/hello/service/TopicService.java +++ b/src/main/java/hello/service/TopicService.java @@ -9,229 +9,146 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @Service public class TopicService { - - private List topics = new ArrayList<>(Arrays.asList( + private final List topics = new CopyOnWriteArrayList<>(List.of( new Topic("spring", "Spring Framework", "Spring Framework Description"), new Topic("java", "Core Java", "Java Description"), new Topic("javascript", "javascript Framework", "javascript Framework Description") )); public List getAllTopics() { - return topics; + return List.copyOf(topics); } - /** - * Strean Example - * - * @param id - * @return - */ - public Topic getTopicWithId(String id) { - return topics.stream().filter(topic -> topic.getId().equals(id)).findFirst().get(); + public Optional getTopicWithId(String id) { + return topics.stream().filter(topic -> topic.id().equals(id)).findFirst(); } public void addTopic(Topic topic) { topics.add(topic); } - /** - * IntStream examples - * - * @param id - * @param topic - */ public void updateTopic(String id, Topic topic) { - OptionalInt indexOfElement = IntStream.range(0, topics.size()).filter(index -> id.equals(topics.get(index).getId())).findFirst(); - if (indexOfElement.isPresent()) topics.set(indexOfElement.getAsInt(), topic); + OptionalInt indexOfElement = IntStream.range(0, topics.size()) + .filter(index -> id.equals(topics.get(index).id())) + .findFirst(); + if (indexOfElement.isPresent()) { + topics.set(indexOfElement.getAsInt(), topic); + } } - /** - * Lamda Expressions - * - * @param id - */ public void deleteTopic(String id) { - topics.removeIf(topic -> topic.getId().equals(id)); + topics.removeIf(topic -> topic.id().equals(id)); } - /** - * Calling fucntional Interface - * - * @param minLength - * @return - */ public List filterMinimumLengthForId(Integer minLength) { - return printTopicsWithPredicate(topics, topic -> topic.getId().length() > minLength); + return filterTopicsWithPredicate(topics, topic -> topic.id().length() > minLength); } - - /** - * Functional Interface example With ForEach - * - * @param topicList - * @param tester - * @return - */ - private static List printTopicsWithPredicate(List topicList, CustomPredicate tester) { + private static List filterTopicsWithPredicate(List topicList, CustomPredicate tester) { List resultTopic = new ArrayList<>(); topicList.forEach(topic -> { - if (tester.test(topic)) resultTopic.add(topic); + if (tester.test(topic)) { + resultTopic.add(topic); + } }); return resultTopic; } - - /** - * Using Comparator to sort - * - * @return - */ public List sortTopicsWithID() { - topics.sort(Comparator.comparing(Topic::getId)); - return topics; + return topics.stream() + .sorted(Comparator.comparing(Topic::id)) + .toList(); } - - /** - * Join List of Strings - * - * @return - */ public String returnAllTopicIDWithStringSlicing() { - List topicIds = topics.stream().map(topic -> topic.getId()).collect(Collectors.toList()); - return String.join(":", topicIds); + return topics.stream() + .map(Topic::id) + .collect(java.util.stream.Collectors.joining(":")); } - - /** - * Use of MapToObject and distinct - * - * @param join - * @return - */ public String makeDistinctAndSortCharacters(String join) { return join.chars().distinct() .mapToObj(id -> String.valueOf((char) id)) .sorted() - .collect(Collectors.joining()); + .collect(java.util.stream.Collectors.joining()); } - - /** - * Use of Pattern Class with stream - * - * @param join - * @return - */ public String splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin(String join) { return Pattern.compile(":") .splitAsStream(join) .filter(s -> s.contains("java")) .sorted() - .collect(Collectors.joining(":")); + .collect(java.util.stream.Collectors.joining(":")); } - - /** - * Apply Regex as Predicate with Stream - * @return - */ public String findIdHavingCharacter() { Pattern pattern = Pattern.compile(".*g.*"); - Object[] topicIdObjectList = topics.stream().map(topic -> topic.getId()).collect(Collectors.toList()).toArray(); - - String[] topicIdList = Arrays.stream(topicIdObjectList).toArray(String[]::new); - - return Stream.of(topicIdList) - .filter(pattern.asPredicate()) - .collect(Collectors.toList()) + return topics.stream() + .map(Topic::id) + .filter(pattern.asMatchPredicate()) + .toList() .toString(); } - - /** - * NIO Java API - * Use Streams with files - * Try with resource, "Autoclose" - * - * @return - */ public String findAllFilesInPathAndSort() { try (Stream stream = Files.list(Paths.get(""))) { - String joined = stream + return stream .map(String::valueOf) .filter(path -> !path.startsWith(".")) .sorted() - .collect(Collectors.joining("; ")); - return joined; + .collect(java.util.stream.Collectors.joining("; ")); } catch (IOException e) { return " Error in IO"; } } - /** - * Using File.find function to find file - * @return - */ public String findParticularFileInPathAndSort() { Path start = Paths.get(""); int maxDepth = 25; try (Stream stream = Files.find(start, maxDepth, (path, attr) -> - String.valueOf(path).startsWith("grad"))) { - String joined = stream + String.valueOf(path).startsWith("pom"))) { + return stream .sorted() .map(String::valueOf) - .collect(Collectors.joining("; ")); - return joined; + .collect(java.util.stream.Collectors.joining("; ")); } catch (IOException e) { return " IO exception "; } } - - /** - * Using Files.Walk Function to find File - * @return - */ public String findParticularFileInPathAndSortWithWalkFunction() { Path start = Paths.get(""); int maxDepth = 5; try (Stream stream = Files.walk(start, maxDepth)) { - String joined = stream + return stream .map(String::valueOf) - .filter(path -> path.startsWith("grad")) + .filter(path -> path.startsWith("pom")) .sorted() - .collect(Collectors.joining("; ")); - return joined; + .collect(java.util.stream.Collectors.joining("; ")); } catch (IOException e) { return " IO exception "; } } - - /** - * Use BufferedReader with Stream functions - * @return - */ public String readFileWithStreamFunction() { - Path path = Paths.get("temp.txt"); - System.out.println(); + Path path = Paths.get("README.md"); try (BufferedReader reader = Files.newBufferedReader(path)) { - String lines = reader - .lines() - .filter(line->line.contains("print")) - .map(line->line.substring("print".length())) - .collect(Collectors.joining(",")); - return lines; + return reader.lines() + .filter(line -> line.contains("spring")) + .collect(java.util.stream.Collectors.joining(",")); } catch (IOException e) { return " IO exception "; } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..29d1979 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,6 @@ +spring.application.name=springboot-java-modern + +management.endpoints.web.exposure.include=health,info,metrics + +springdoc.api-docs.path=/v3/api-docs +springdoc.swagger-ui.path=/swagger-ui.html diff --git a/src/test/java/hello/ApplicationTests.java b/src/test/java/hello/ApplicationTests.java new file mode 100644 index 0000000..094b69e --- /dev/null +++ b/src/test/java/hello/ApplicationTests.java @@ -0,0 +1,12 @@ +package hello; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationTests { + + @Test + void contextLoads() { + } +} diff --git a/src/test/java/hello/controller/TopicControllerTest.java b/src/test/java/hello/controller/TopicControllerTest.java new file mode 100644 index 0000000..8782dd2 --- /dev/null +++ b/src/test/java/hello/controller/TopicControllerTest.java @@ -0,0 +1,84 @@ +package hello.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import hello.model.Topic; +import hello.service.TopicService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.List; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(TopicController.class) +class TopicControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + TopicService topicService; + + @Autowired + ObjectMapper objectMapper; + + @Test + void getAllTopics_returnsList() throws Exception { + given(topicService.getAllTopics()).willReturn(List.of( + new Topic("spring", "Spring Framework", "desc"))); + + mockMvc.perform(get("/topic")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value("spring")) + .andExpect(jsonPath("$[0].subjectName").value("Spring Framework")); + } + + @Test + void getTopicById_whenMissing_returns404() throws Exception { + given(topicService.getTopicWithId("missing")).willReturn(Optional.empty()); + + mockMvc.perform(get("/topic/missing")) + .andExpect(status().isNotFound()); + } + + @Test + void getTopicById_whenPresent_returnsTopic() throws Exception { + given(topicService.getTopicWithId("java")) + .willReturn(Optional.of(new Topic("java", "Core Java", "desc"))); + + mockMvc.perform(get("/topic/java")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value("java")); + } + + @Test + void addTopic_returns201() throws Exception { + Topic topic = new Topic("go", "Go", "desc"); + mockMvc.perform(post("/topic") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(topic))) + .andExpect(status().isCreated()); + + verify(topicService).addTopic(any(Topic.class)); + } + + @Test + void deleteTopic_returns204() throws Exception { + mockMvc.perform(delete("/topic/java")) + .andExpect(status().isNoContent()); + + verify(topicService).deleteTopic("java"); + } +} diff --git a/src/test/java/hello/service/TopicServiceTest.java b/src/test/java/hello/service/TopicServiceTest.java new file mode 100644 index 0000000..bcfb5dd --- /dev/null +++ b/src/test/java/hello/service/TopicServiceTest.java @@ -0,0 +1,97 @@ +package hello.service; + +import hello.model.Topic; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +class TopicServiceTest { + + TopicService topicService; + + @BeforeEach + void setUp() { + topicService = new TopicService(); + } + + @Test + void getAllTopics_containsSeedData() { + List all = topicService.getAllTopics(); + assertThat(all).hasSize(3); + assertThat(all).extracting(Topic::id).containsExactlyInAnyOrder("spring", "java", "javascript"); + } + + @Test + void getTopicWithId_returnsEmptyOptionalWhenMissing() { + assertThat(topicService.getTopicWithId("does-not-exist")).isEmpty(); + } + + @Test + void addAndDeleteTopic_roundTrip() { + Topic topic = new Topic("kotlin", "Kotlin", "desc"); + topicService.addTopic(topic); + assertThat(topicService.getTopicWithId("kotlin")).contains(topic); + + topicService.deleteTopic("kotlin"); + assertThat(topicService.getTopicWithId("kotlin")).isEmpty(); + } + + @Test + void updateTopic_replacesExistingEntry() { + Topic updated = new Topic("java", "Modern Java", "updated"); + topicService.updateTopic("java", updated); + assertThat(topicService.getTopicWithId("java")).contains(updated); + } + + @Test + void filterMinimumLengthForId_filtersByIdLength() { + assertThat(topicService.filterMinimumLengthForId(6)) + .extracting(Topic::id).containsExactlyInAnyOrder("javascript"); + assertThat(topicService.filterMinimumLengthForId(5)) + .extracting(Topic::id).containsExactlyInAnyOrder("spring", "javascript"); + } + + @Test + void sortTopicsWithID_sortsLexicographically() { + List sorted = topicService.sortTopicsWithID(); + assertThat(sorted).extracting(Topic::id).containsExactly("java", "javascript", "spring"); + } + + @Test + void returnAllTopicIDWithStringSlicing_joinsWithColon() { + assertThat(topicService.returnAllTopicIDWithStringSlicing()) + .contains("spring").contains("java").contains("javascript"); + } + + @Test + void findIdHavingCharacter_returnsIdsContainingG() { + String result = topicService.findIdHavingCharacter(); + assertThat(result).contains("spring"); + } + + @Test + void splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin_filtersJavaIds() { + String joined = topicService.returnAllTopicIDWithStringSlicing(); + String result = topicService.splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin(joined); + assertThat(result).contains("java"); + assertThat(result).doesNotContain("spring"); + } + + @Test + void makeDistinctAndSortCharacters_returnsDistinctSortedChars() { + String result = topicService.makeDistinctAndSortCharacters("ccbbaa"); + assertThat(result).isEqualTo("abc"); + } + + @Test + void getAllTopicsList_isImmutableCopy() { + List all = topicService.getAllTopics(); + Optional firstBefore = topicService.getTopicWithId("spring"); + assertThat(firstBefore).isPresent(); + assertThat(all).isUnmodifiable(); + } +} diff --git a/target/classes/hello/Application.class b/target/classes/hello/Application.class deleted file mode 100644 index 245a020..0000000 Binary files a/target/classes/hello/Application.class and /dev/null differ diff --git a/target/classes/hello/controller/GreetingController.class b/target/classes/hello/controller/GreetingController.class deleted file mode 100644 index 1149660..0000000 Binary files a/target/classes/hello/controller/GreetingController.class and /dev/null differ diff --git a/target/classes/hello/controller/HelloController.class b/target/classes/hello/controller/HelloController.class deleted file mode 100644 index 79b82ce..0000000 Binary files a/target/classes/hello/controller/HelloController.class and /dev/null differ diff --git a/target/classes/hello/controller/TopicController.class b/target/classes/hello/controller/TopicController.class deleted file mode 100644 index c32cad5..0000000 Binary files a/target/classes/hello/controller/TopicController.class and /dev/null differ diff --git a/target/classes/hello/declaration/CustomPredicate.class b/target/classes/hello/declaration/CustomPredicate.class deleted file mode 100644 index e35803f..0000000 Binary files a/target/classes/hello/declaration/CustomPredicate.class and /dev/null differ diff --git a/target/classes/hello/declaration/TimeClient.class b/target/classes/hello/declaration/TimeClient.class deleted file mode 100644 index a077c3b..0000000 Binary files a/target/classes/hello/declaration/TimeClient.class and /dev/null differ diff --git a/target/classes/hello/model/Customer.class b/target/classes/hello/model/Customer.class deleted file mode 100644 index 06e7307..0000000 Binary files a/target/classes/hello/model/Customer.class and /dev/null differ diff --git a/target/classes/hello/model/Greeting.class b/target/classes/hello/model/Greeting.class deleted file mode 100644 index f875277..0000000 Binary files a/target/classes/hello/model/Greeting.class and /dev/null differ diff --git a/target/classes/hello/model/Quote.class b/target/classes/hello/model/Quote.class deleted file mode 100644 index 3ec6c6c..0000000 Binary files a/target/classes/hello/model/Quote.class and /dev/null differ diff --git a/target/classes/hello/model/SimpleTimeClient.class b/target/classes/hello/model/SimpleTimeClient.class deleted file mode 100644 index f9bdddd..0000000 Binary files a/target/classes/hello/model/SimpleTimeClient.class and /dev/null differ diff --git a/target/classes/hello/model/Topic.class b/target/classes/hello/model/Topic.class deleted file mode 100644 index 3a53aa5..0000000 Binary files a/target/classes/hello/model/Topic.class and /dev/null differ diff --git a/target/classes/hello/model/Value.class b/target/classes/hello/model/Value.class deleted file mode 100644 index 862a68f..0000000 Binary files a/target/classes/hello/model/Value.class and /dev/null differ diff --git a/target/classes/hello/service/TopicService.class b/target/classes/hello/service/TopicService.class deleted file mode 100644 index b9f4992..0000000 Binary files a/target/classes/hello/service/TopicService.class and /dev/null differ diff --git a/target/classes/public/index.html b/target/classes/public/index.html deleted file mode 100644 index 566549b..0000000 --- a/target/classes/public/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Title - - - - - \ No newline at end of file diff --git a/temp.txt b/temp.txt deleted file mode 100644 index 8b07638..0000000 --- a/temp.txt +++ /dev/null @@ -1,9 +0,0 @@ -print Hello -print this -print is -temp -file -my -name -is -print Rehman