diff --git a/.editorconfig b/.editorconfig index 31325f8..83142a7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,6 +9,10 @@ indent_size = 4 indent_style = space insert_final_newline = true +[*.java] +ij_java_class_count_to_use_import_on_demand = 999 +ij_java_names_count_to_use_import_on_demand = 999 + [*.{bat,cmd}] end_of_line = crlf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 848cd16..fba6eca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ on: - '*' pull_request: branches: - - $default-branch + - '*' jobs: build: diff --git a/LICENSE_HEADER.txt b/LICENSE_HEADER.txt new file mode 100644 index 0000000..d95ab40 --- /dev/null +++ b/LICENSE_HEADER.txt @@ -0,0 +1,13 @@ +Copyright ${year} the original author or authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md index e31bc4c..6a83ab5 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ public class ExampleConfiguration { ### Build Requirements -* Java 17 or above to build. The release jars are compiled to Java 8 bytecode. Integration tests are compiled to Java 17 bytecode. +* Java 17 or above to build and use. To build: diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 2dec21b..b33d72c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,8 +1,14 @@ # Release Notes -## 0.7.0-SNAPSHOT +## 1.0.0-SNAPSHOT Released N/A +- Breaking change +- Updated to support Spring 6.x and Spring Boot 3.x. This brings with it a minimum Java version of 17. With the Spring + upgrade comes a switch to the Jakara EE Servlet API instead of Java EE. +- Update build to Gradle 8.9 +- Added support for ErrorProne and NullAway for compile time checks of nullability. + ## 0.6.0 Released 2023-12-01 diff --git a/build.gradle.kts b/build.gradle.kts index 7cfa1e7..761eb9e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,10 +6,8 @@ plugins { } allprojects { - apply(plugin = "com.mattbertolini.buildlogic.project-conventions") - group = "com.mattbertolini" - version = "0.7.0-SNAPSHOT" + version = "1.0.0-SNAPSHOT" } val rootJacocoDir = "reports/jacoco/testCodeCoverageReport" diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 876c922..cbccb00 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -3,5 +3,11 @@ plugins { } repositories { + gradlePluginPortal() mavenCentral() } + +dependencies { + implementation("net.ltgt.gradle:gradle-errorprone-plugin:4.0.1") + implementation("gradle.plugin.com.hierynomus.gradle.plugins:license-gradle-plugin:0.16.1") +} diff --git a/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/error-prone.gradle.kts b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/error-prone.gradle.kts new file mode 100644 index 0000000..debf80f --- /dev/null +++ b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/error-prone.gradle.kts @@ -0,0 +1,33 @@ +package com.mattbertolini.buildlogic + +import net.ltgt.gradle.errorprone.CheckSeverity +import net.ltgt.gradle.errorprone.errorprone + +plugins { + id("net.ltgt.errorprone") +} + +val libsCatalog = versionCatalogs.named("libs") +val errorProneCore = libsCatalog.findLibrary("errorProneCore").orElseThrow() +val errorProneAnnotations = libsCatalog.findLibrary("errorProneAnnotations").orElseThrow(); +val nullAway = libsCatalog.findLibrary("nullAway").orElseThrow() +val nullAwayAnnotations = libsCatalog.findLibrary("nullAwayAnnotations").orElseThrow() + +dependencies { + errorprone(errorProneCore) + errorprone(nullAway) +} + +project.extensions.getByType().configureEach { + dependencies.add(compileOnlyConfigurationName, errorProneAnnotations) + dependencies.add(compileOnlyConfigurationName, nullAwayAnnotations) +} + +tasks.withType().configureEach { + options.isFork = true + options.errorprone { + disableWarningsInGeneratedCode.set(true) + check("NullAway", CheckSeverity.ERROR) + option("NullAway:AnnotatedPackages", "com.mattbertolini") + } +} diff --git a/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/java-conventions.gradle.kts b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/java-conventions.gradle.kts index fbc4ecd..9724867 100644 --- a/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/java-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/java-conventions.gradle.kts @@ -3,6 +3,8 @@ package com.mattbertolini.buildlogic plugins { java jacoco + id("com.mattbertolini.buildlogic.project-conventions") + id("com.mattbertolini.buildlogic.error-prone") } val versionCatalog = versionCatalogs.named("libs") @@ -13,10 +15,6 @@ java { } } -tasks.named("compileJava").configure { - options.release.set(8) -} - testing { suites { named("test").configure { @@ -34,30 +32,25 @@ tasks.named("jar").configure { } } -val springVersion: String = versionCatalog.findVersion("spring").orElseThrow().toString() -val springBootVersion: String = versionCatalog.findVersion("springBoot").orElseThrow().toString() - val javadocLinks = arrayOf( - "https://docs.oracle.com/javase/8/docs/api/", - "https://docs.oracle.com/javaee/7/api/", - "https://docs.spring.io/spring-framework/docs/$springVersion/javadoc-api/", - "https://docs.spring.io/spring-boot/docs/$springBootVersion/api/" + "https://docs.oracle.com/en/java/javase/17/docs/api", + "https://jakarta.ee/specifications/platform/11/apidocs/", + "https://docs.spring.io/spring-framework/docs/current/javadoc-api/", + "https://docs.spring.io/spring-boot/api/java/" ) tasks.named("javadoc").configure { options { this as StandardJavadocDocletOptions - source = "8" + source = "17" links(*javadocLinks) addStringOption("Xdoclint:none", "-quiet") - if (java.toolchain.languageVersion.get().asInt() >= 9) { - addBooleanOption("html5", true) - } + addBooleanOption("html5", true) } } val jacocoVersion: String = versionCatalog.findVersion("jacoco").orElseThrow().toString() -configure { +jacoco { toolVersion = jacocoVersion } @@ -69,4 +62,6 @@ tasks.named("jacocoTestReport").configure { } } -tasks.test { finalizedBy(tasks.jacocoTestReport) } +tasks.named("test").configure { + finalizedBy(tasks.named("jacocoTestReport")) +} diff --git a/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/java-library.gradle.kts b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/java-library.gradle.kts index 96acfd0..271e920 100644 --- a/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/java-library.gradle.kts +++ b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/java-library.gradle.kts @@ -2,6 +2,5 @@ package com.mattbertolini.buildlogic plugins { `java-library` + id("com.mattbertolini.buildlogic.java-conventions") } - -apply(plugin = "com.mattbertolini.buildlogic.java-conventions") diff --git a/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/license-conventions.gradle.kts b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/license-conventions.gradle.kts new file mode 100644 index 0000000..6c33189 --- /dev/null +++ b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/license-conventions.gradle.kts @@ -0,0 +1,13 @@ +package com.mattbertolini.buildlogic + +import java.time.LocalDate + +plugins { + id("com.github.hierynomus.license") +} + +license { + mapping("java", "SLASHSTAR_STYLE") + header = isolated.rootProject.projectDirectory.file("LICENSE_HEADER.txt").asFile + ext.set("year", LocalDate.now().year) +} diff --git a/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/project-conventions.gradle.kts b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/project-conventions.gradle.kts index a7b73b0..f1cc10b 100644 --- a/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/project-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/com/mattbertolini/buildlogic/project-conventions.gradle.kts @@ -1,5 +1,9 @@ package com.mattbertolini.buildlogic +//plugins { +// id("com.mattbertolini.buildlogic.license-conventions") +//} + // Configuring archive tasks to have repeatable builds tasks.withType().configureEach { isReproducibleFileOrder = true diff --git a/docs/build.gradle.kts b/docs/build.gradle.kts index 82b5cb0..330fa0c 100644 --- a/docs/build.gradle.kts +++ b/docs/build.gradle.kts @@ -12,7 +12,8 @@ configurations { dependencies { implementation(project(":spring-webmvc-annotated-data-binder")) implementation(project(":spring-webflux-annotated-data-binder")) - implementation(libs.javaxServletApi) // Version defined in Spring BOM file + implementation(libs.jakartaServletApi) // Version defined in Spring BOM file + compileOnly(libs.findbugsJsr305) add("asciidoctorExt", libs.springAsciidoctorExtBlockSwitch) @@ -20,7 +21,10 @@ dependencies { testImplementation(libs.assertJCore) testImplementation(libs.mockitoCore) testImplementation(libs.springTest) + testImplementation(libs.jakartaWebsocketApi) + testImplementation(libs.jakartaWebsocketClientApi) testCompileOnly(libs.hamcrest) // Needed for Spring mock MVC matchers + testCompileOnly(libs.findbugsJsr305) } tasks.named("asciidoctor").configure { diff --git a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/CustomRequestBean.java b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/CustomRequestBean.java index 014bbd6..fbef8ec 100644 --- a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/CustomRequestBean.java +++ b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/CustomRequestBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.docs; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; @@ -25,6 +24,7 @@ import com.mattbertolini.spring.web.bind.annotation.RequestContext; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; +import org.springframework.lang.Nullable; import java.time.ZoneId; import java.util.Locale; @@ -37,6 +37,7 @@ public class CustomRequestBean { // end::class[] // Query parameters + @Nullable // tag::queryParam[] @RequestParameter("different_name") private String queryParam; @@ -44,6 +45,7 @@ public class CustomRequestBean { // end::queryParam[] // Form data + @Nullable // tag::formParam[] @FormParameter("form_data") private String formData; @@ -51,6 +53,7 @@ public class CustomRequestBean { // end::formParam[] // HTTP headers + @Nullable // tag::headerParam[] @HeaderParameter("X-Custom-Header") private String headerValues; @@ -58,6 +61,7 @@ public class CustomRequestBean { // end::headerParam[] // Spring MVC/WebFlux path variables + @Nullable // tag::pathParam[] @PathParameter("pathParam") private Integer pathParam; @@ -65,6 +69,7 @@ public class CustomRequestBean { // end::pathParam[] // HTTP cookie values + @Nullable // tag::cookieParam[] @CookieParameter("cookie_value") private String cookieValue; @@ -72,6 +77,7 @@ public class CustomRequestBean { // end::cookieParam[] // HTTP session attributes + @Nullable // tag::sessionParam[] @SessionParameter("sessionAttribute") private String sessionAttribute; @@ -79,16 +85,20 @@ public class CustomRequestBean { // end::sessionParam[] // Spring derived request scoped data like locale and time zone + @Nullable @RequestContext private Locale locale; + @Nullable @RequestContext private ZoneId timeZone; // A nested Java bean with additional annotated properties + @Nullable @BeanParameter private NestedBean nestedBean; + @Nullable // tag::queryParam[] public String getQueryParam() { return queryParam; @@ -99,6 +109,7 @@ public void setQueryParam(String queryParam) { } // end::queryParam[] + @Nullable // tag::formParam[] public String getFormData() { return formData; @@ -109,6 +120,7 @@ public void setFormData(String formData) { } // end::formParam[] + @Nullable // tag::headerParam[] public String getHeaderValues() { return headerValues; @@ -119,6 +131,7 @@ public void setHeaderValues(String headerValues) { } // end::headerParam[] + @Nullable // tag::pathParam[] public Integer getPathParam() { return pathParam; @@ -129,6 +142,7 @@ public void setPathParam(Integer pathParam) { } // end::pathParam[] + @Nullable // tag::cookieParam[] public String getCookieValue() { return cookieValue; @@ -139,6 +153,7 @@ public void setCookieValue(String cookieValue) { } // end::cookieParam[] + @Nullable // tag::sessionParam[] public String getSessionAttribute() { return sessionAttribute; @@ -149,6 +164,7 @@ public void setSessionAttribute(String sessionAttribute) { } // end::sessionParam[] + @Nullable public Locale getLocale() { return locale; } @@ -157,6 +173,7 @@ public void setLocale(Locale locale) { this.locale = locale; } + @Nullable public ZoneId getTimeZone() { return timeZone; } @@ -165,6 +182,7 @@ public void setTimeZone(ZoneId timeZone) { this.timeZone = timeZone; } + @Nullable public NestedBean getNestedBean() { return nestedBean; } diff --git a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/ExampleController.java b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/ExampleController.java index 16b679c..6e41cef 100644 --- a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/ExampleController.java +++ b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/ExampleController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.docs; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; diff --git a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/ExampleService.java b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/ExampleService.java index 6fecc4f..f8968f2 100644 --- a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/ExampleService.java +++ b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/ExampleService.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.docs; public class ExampleService { diff --git a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/NestedBean.java b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/NestedBean.java index f56d300..0c27da8 100644 --- a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/NestedBean.java +++ b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/NestedBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.docs; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; +import org.springframework.lang.Nullable; public class NestedBean { + @Nullable @RequestParameter("nested_request_param") private String nestedRequestParameter; + @Nullable public String getNestedRequestParameter() { return nestedRequestParameter; } diff --git a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/webflux/ExampleWebFluxContext.java b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/webflux/ExampleWebFluxContext.java index edcb4af..1082e89 100644 --- a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/webflux/ExampleWebFluxContext.java +++ b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/webflux/ExampleWebFluxContext.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.docs.webflux; import com.mattbertolini.spring.web.bind.docs.ExampleController; diff --git a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/webmvc/ExampleMvcContext.java b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/webmvc/ExampleMvcContext.java index 79edb17..08926fe 100644 --- a/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/webmvc/ExampleMvcContext.java +++ b/docs/src/main/java/com/mattbertolini/spring/web/bind/docs/webmvc/ExampleMvcContext.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.docs.webmvc; import com.mattbertolini.spring.web.bind.docs.ExampleController; diff --git a/docs/src/main/resources/com/mattbertolini/spring/web/bind/docs/webmvc/example-context.xml b/docs/src/main/resources/com/mattbertolini/spring/web/bind/docs/webmvc/example-context.xml index dd4b8e7..f504c59 100644 --- a/docs/src/main/resources/com/mattbertolini/spring/web/bind/docs/webmvc/example-context.xml +++ b/docs/src/main/resources/com/mattbertolini/spring/web/bind/docs/webmvc/example-context.xml @@ -1,4 +1,21 @@ + ("compileJava").configure { - options.release.set(17) + testCompileOnly(libs.findbugsJsr305) } tasks.named("jacocoTestReport").configure { diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/CookieParameterBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/CookieParameterBean.java index 34c9f4f..7d9ac43 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/CookieParameterBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/CookieParameterBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,29 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import com.mattbertolini.spring.web.bind.annotation.CookieParameter; - -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; +import org.springframework.lang.Nullable; public class CookieParameterBean { + @Nullable @CookieParameter("annotated_field") private String annotatedField; + @Nullable private String annotatedSetter; + @Nullable private String annotatedGetter; + @Nullable @NotEmpty @CookieParameter("validated") private String validated; + @Nullable @BeanParameter private NestedBean nestedBean; + @Nullable public String getAnnotatedField() { return annotatedField; } @@ -44,6 +49,7 @@ public void setAnnotatedField(String annotatedField) { this.annotatedField = annotatedField; } + @Nullable public String getAnnotatedSetter() { return annotatedSetter; } @@ -53,6 +59,7 @@ public void setAnnotatedSetter(String annotatedSetter) { this.annotatedSetter = annotatedSetter; } + @Nullable @CookieParameter("annotated_getter") public String getAnnotatedGetter() { return annotatedGetter; @@ -62,6 +69,7 @@ public void setAnnotatedGetter(String annotatedGetter) { this.annotatedGetter = annotatedGetter; } + @Nullable public String getValidated() { return validated; } @@ -70,6 +78,7 @@ public void setValidated(String validated) { this.validated = validated; } + @Nullable public NestedBean getNestedBean() { return nestedBean; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/CookieParameterController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/CookieParameterController.java index 572997f..886f78b 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/CookieParameterController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/CookieParameterController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,30 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.test.web.bind.records.CookieParameterRecord; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; +import jakarta.validation.Valid; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.validation.Valid; +import java.util.Objects; @RestController public class CookieParameterController { + @Nullable @GetMapping(value = "/annotatedField", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedField(@BeanParameter CookieParameterBean cookieParameterBean) { return cookieParameterBean.getAnnotatedField(); } + @Nullable @GetMapping(value = "/annotatedSetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedSetter(@BeanParameter CookieParameterBean cookieParameterBean) { return cookieParameterBean.getAnnotatedSetter(); } + @Nullable @GetMapping(value = "/annotatedGetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedGetter(@BeanParameter CookieParameterBean cookieParameterBean) { return cookieParameterBean.getAnnotatedGetter(); @@ -47,6 +51,7 @@ public String bindingResult(@BeanParameter CookieParameterBean cookieParameterBe return Integer.toString(bindingResult.getErrorCount()); } + @Nullable @GetMapping(value = "/validated", produces = MediaType.TEXT_PLAIN_VALUE) public String validated(@Valid @BeanParameter CookieParameterBean cookieParameterBean) { return cookieParameterBean.getValidated(); @@ -60,9 +65,10 @@ public String validatedWithBindingResult(@Valid @BeanParameter CookieParameterBe return "valid"; } + @Nullable @GetMapping(value = "/nested", produces = MediaType.TEXT_PLAIN_VALUE) public String nestedBean(@BeanParameter CookieParameterBean cookieParameterBean) { - return cookieParameterBean.getNestedBean().getCookieValue(); + return Objects.requireNonNull(cookieParameterBean.getNestedBean()).getCookieValue(); } @GetMapping(value = "/record", produces = MediaType.TEXT_PLAIN_VALUE) diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/DirectFieldAccessBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/DirectFieldAccessBean.java index 132f5a8..467ebfd 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/DirectFieldAccessBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/DirectFieldAccessBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.CookieParameter; @@ -23,55 +22,70 @@ import com.mattbertolini.spring.web.bind.annotation.RequestBody; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; +import org.springframework.lang.Nullable; @SuppressWarnings("unused") public class DirectFieldAccessBean { + @Nullable @CookieParameter("cookie_parameter") private String cookieParameter; + @Nullable @FormParameter("form_parameter") private String formParameter; - + + @Nullable @HeaderParameter("header_parameter") private String headerParameter; + @Nullable @PathParameter("path_parameter") private String pathParameter; - + + @Nullable @RequestParameter("request_parameter") private String requestParameter; + @Nullable @SessionParameter("session_parameter") private String sessionParameter; + @Nullable public String getCookieParameter() { return cookieParameter; } + @Nullable public String getFormParameter() { return formParameter; } + @Nullable public String getHeaderParameter() { return headerParameter; } + @Nullable public String getPathParameter() { return pathParameter; } + @Nullable public String getRequestParameter() { return requestParameter; } + @Nullable public String getSessionParameter() { return sessionParameter; } public static class RequestBodyBean { + @Nullable @RequestBody private JsonBody requestBody; + @Nullable public JsonBody getRequestBody() { return requestBody; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/DirectFieldAccessController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/DirectFieldAccessController.java index ac1b24e..688c425 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/DirectFieldAccessController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/DirectFieldAccessController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,50 +13,59 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Objects; + @RestController public class DirectFieldAccessController { + @Nullable @GetMapping(value = "/cookieParameter", produces = MediaType.TEXT_PLAIN_VALUE) public String cookieParameter(@BeanParameter DirectFieldAccessBean directFieldAccessBean) { return directFieldAccessBean.getCookieParameter(); } + @Nullable @PostMapping(value = "/formParameter", produces = MediaType.TEXT_PLAIN_VALUE) public String formParameter(@BeanParameter DirectFieldAccessBean directFieldAccessBean) { return directFieldAccessBean.getFormParameter(); } + @Nullable @GetMapping(value = "/headerParameter", produces = MediaType.TEXT_PLAIN_VALUE) public String headerParameter(@BeanParameter DirectFieldAccessBean directFieldAccessBean) { return directFieldAccessBean.getHeaderParameter(); } + @Nullable @SuppressWarnings("MVCPathVariableInspection") @GetMapping(value = "/pathParameter/{path_parameter}", produces = MediaType.TEXT_PLAIN_VALUE) public String pathParameter(@BeanParameter DirectFieldAccessBean directFieldAccessBean) { return directFieldAccessBean.getPathParameter(); } + @Nullable @GetMapping(value = "/requestParameter", produces = MediaType.TEXT_PLAIN_VALUE) public String requestParameter(@BeanParameter DirectFieldAccessBean directFieldAccessBean) { return directFieldAccessBean.getRequestParameter(); } + @Nullable @GetMapping(value = "/sessionParameter", produces = MediaType.TEXT_PLAIN_VALUE) public String sessionParameter(@BeanParameter DirectFieldAccessBean directFieldAccessBean) { return directFieldAccessBean.getSessionParameter(); } + @Nullable @PostMapping(value = "/requestBody", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.TEXT_PLAIN_VALUE) public String requestBody(@BeanParameter DirectFieldAccessBean.RequestBodyBean directFieldAccessBean) { - return directFieldAccessBean.getRequestBody().getProperty(); + return Objects.requireNonNull(directFieldAccessBean.getRequestBody()).getProperty(); } } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/FormParameterBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/FormParameterBean.java index 686f479..0e8ddc9 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/FormParameterBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/FormParameterBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,40 +13,48 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import com.mattbertolini.spring.web.bind.annotation.FormParameter; +import jakarta.servlet.http.Part; +import jakarta.validation.constraints.NotEmpty; import org.springframework.http.codec.multipart.FilePart; +import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.Part; -import javax.validation.constraints.NotEmpty; import java.util.Map; public class FormParameterBean { + @Nullable @FormParameter("annotated_field") private String annotatedField; + @Nullable private String annotatedSetter; + @Nullable private String annotatedGetter; + @Nullable @FormParameter private Map simpleMap; + @Nullable @FormParameter private MultiValueMap multiValueMap; + @Nullable @NotEmpty @FormParameter("validated") private String validated; + @Nullable @BeanParameter private NestedBean nestedBean; + @Nullable public String getAnnotatedField() { return annotatedField; } @@ -55,6 +63,7 @@ public void setAnnotatedField(String annotatedField) { this.annotatedField = annotatedField; } + @Nullable public String getAnnotatedSetter() { return annotatedSetter; } @@ -64,6 +73,7 @@ public void setAnnotatedSetter(String annotatedSetter) { this.annotatedSetter = annotatedSetter; } + @Nullable @FormParameter("annotated_getter") public String getAnnotatedGetter() { return annotatedGetter; @@ -73,6 +83,7 @@ public void setAnnotatedGetter(String annotatedGetter) { this.annotatedGetter = annotatedGetter; } + @Nullable public Map getSimpleMap() { return simpleMap; } @@ -81,6 +92,7 @@ public void setSimpleMap(Map simpleMap) { this.simpleMap = simpleMap; } + @Nullable public MultiValueMap getMultiValueMap() { return multiValueMap; } @@ -89,6 +101,7 @@ public void setMultiValueMap(MultiValueMap multiValueMap) { this.multiValueMap = multiValueMap; } + @Nullable public String getValidated() { return validated; } @@ -97,6 +110,7 @@ public void setValidated(String validated) { this.validated = validated; } + @Nullable public NestedBean getNestedBean() { return nestedBean; } @@ -109,24 +123,31 @@ public void setNestedBean(NestedBean nestedBean) { * Test bean for multipart binding in a Servlet/WebMVC application */ static class ServletMultipartBean { + @Nullable @FormParameter("file") private MultipartFile multipartFile; + @Nullable @FormParameter("part") private Part part; + @Nullable @FormParameter private Map multipartFileMap; + @Nullable @FormParameter private MultiValueMap multiValueMultipartMap; + @Nullable @FormParameter private Map partMap; + @Nullable @FormParameter private MultiValueMap multiValuePartMap; + @Nullable public MultipartFile getMultipartFile() { return multipartFile; } @@ -135,6 +156,7 @@ public void setMultipartFile(MultipartFile multipartFile) { this.multipartFile = multipartFile; } + @Nullable public Part getPart() { return part; } @@ -143,6 +165,7 @@ public void setPart(Part part) { this.part = part; } + @Nullable public Map getMultipartFileMap() { return multipartFileMap; } @@ -151,6 +174,7 @@ public void setMultipartFileMap(Map multipartFileMap) { this.multipartFileMap = multipartFileMap; } + @Nullable public MultiValueMap getMultiValueMultipartMap() { return multiValueMultipartMap; } @@ -159,6 +183,7 @@ public void setMultiValueMultipartMap(MultiValueMap multi this.multiValueMultipartMap = multiValueMultipartMap; } + @Nullable public Map getPartMap() { return partMap; } @@ -167,6 +192,7 @@ public void setPartMap(Map partMap) { this.partMap = partMap; } + @Nullable public MultiValueMap getMultiValuePartMap() { return multiValuePartMap; } @@ -180,9 +206,11 @@ public void setMultiValuePartMap(MultiValueMap multiValuePartMap) * Test bean for multipart binding in a WebFlux application */ static class WebfluxMultipartBean { + @Nullable @FormParameter("file") private FilePart filePart; + @Nullable public FilePart getFilePart() { return filePart; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/FormParameterController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/FormParameterController.java index da5d072..09eb3b2 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/FormParameterController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/FormParameterController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.test.web.bind.records.FormParameterRecord; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; +import jakarta.servlet.http.Part; +import jakarta.validation.Valid; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.MediaType; import org.springframework.http.codec.multipart.FilePart; +import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; import org.springframework.util.StreamUtils; import org.springframework.validation.BindingResult; @@ -30,42 +32,47 @@ import org.springframework.web.multipart.MultipartFile; import reactor.core.publisher.Flux; -import javax.servlet.http.Part; -import javax.validation.Valid; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; +@SuppressWarnings("NullAway") @RestController public class FormParameterController { + @Nullable @PostMapping(value = "/annotatedField", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedField(@BeanParameter FormParameterBean formParameterBean) { return formParameterBean.getAnnotatedField(); } + @Nullable @PostMapping(value = "/annotatedSetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedSetter(@BeanParameter FormParameterBean formParameterBean) { return formParameterBean.getAnnotatedSetter(); } + @Nullable @PostMapping(value = "/annotatedGetter", produces = MediaType.TEXT_PLAIN_VALUE) public String handleRequest(@BeanParameter FormParameterBean formParameterBean) { return formParameterBean.getAnnotatedGetter(); } + @Nullable @PostMapping(value = "/simpleMap", produces = MediaType.TEXT_PLAIN_VALUE) public String simpleMap(@BeanParameter FormParameterBean formParameterBean) { Map simpleMap = formParameterBean.getSimpleMap(); - return simpleMap.get("simple-map"); + return Objects.requireNonNull(simpleMap).get("simple-map"); } + @Nullable @PostMapping(value = "/multiValueMap", produces = MediaType.TEXT_PLAIN_VALUE) public String multiValueMap(@BeanParameter FormParameterBean formParameterBean) { MultiValueMap multiValueMap = formParameterBean.getMultiValueMap(); - return multiValueMap.getFirst("multi-value-map"); + return Objects.requireNonNull(multiValueMap).getFirst("multi-value-map"); } @SuppressWarnings("unused") @@ -74,6 +81,7 @@ public String bindingResult(@BeanParameter FormParameterBean formParameterBean, return Integer.toString(bindingResult.getErrorCount()); } + @Nullable @PostMapping(value = "/validated", produces = MediaType.TEXT_PLAIN_VALUE) public String validated(@Valid @BeanParameter FormParameterBean formParameterBean) { return formParameterBean.getValidated(); @@ -94,7 +102,7 @@ public String multipartFile(@BeanParameter FormParameterBean.ServletMultipartBea if (multipartFile == null || multipartFile.isEmpty()) { throw new RuntimeException("Multipart file is null or empty"); } - return new String(multipartFile.getBytes()); + return new String(multipartFile.getBytes(), StandardCharsets.UTF_8); } @PostMapping(value = "/part", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @@ -111,7 +119,7 @@ public String multipartFileMap(@BeanParameter FormParameterBean.ServletMultipart Map multipartFileMap = formParameterBean.getMultipartFileMap(); MultipartFile fileOne = multipartFileMap.get("fileOne"); MultipartFile fileTwo = multipartFileMap.get("fileTwo"); - return new String(fileOne.getBytes()) + ", " + new String(fileTwo.getBytes()); + return new String(fileOne.getBytes(), StandardCharsets.UTF_8) + ", " + new String(fileTwo.getBytes(), StandardCharsets.UTF_8); } @PostMapping(value = "/multiValueMultipartFileMap", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @@ -120,7 +128,7 @@ public String multiValueMultipartFileMap(@BeanParameter FormParameterBean.Servle List files = multiValueMultipartMap.get("file"); return files.stream().map(multipartFile -> { try { - return new String(multipartFile.getBytes()); + return new String(multipartFile.getBytes(), StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException(e); } @@ -161,9 +169,10 @@ public String webFluxFilePart(@BeanParameter FormParameterBean.WebfluxMultipartB return new String(data.toByteArray(), StandardCharsets.UTF_8); } + @Nullable @PostMapping(value = "/nested", produces = MediaType.TEXT_PLAIN_VALUE) public String nestedBeanParameter(@BeanParameter FormParameterBean formParameterBean) { - return formParameterBean.getNestedBean().getFormData(); + return Objects.requireNonNull(formParameterBean.getNestedBean()).getFormData(); } @PostMapping(value = "/record", produces = MediaType.TEXT_PLAIN_VALUE) diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/HeaderParameterBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/HeaderParameterBean.java index 30aa8e0..b039ab4 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/HeaderParameterBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/HeaderParameterBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,41 +13,50 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; +import jakarta.validation.constraints.NotEmpty; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; -import javax.validation.constraints.NotEmpty; import java.util.Map; public class HeaderParameterBean { + @Nullable @HeaderParameter("x-annotated-field") private String annotatedField; + @Nullable private String annotatedSetter; + @Nullable private String annotatedGetter; + @Nullable @HeaderParameter private Map simpleMap; + @Nullable @HeaderParameter private MultiValueMap multiValueMap; + @Nullable @HeaderParameter private HttpHeaders httpHeaders; + @Nullable @NotEmpty @HeaderParameter("validated") private String validated; + @Nullable @BeanParameter private NestedBean nestedBean; + @Nullable public String getAnnotatedField() { return annotatedField; } @@ -56,6 +65,7 @@ public void setAnnotatedField(String annotatedField) { this.annotatedField = annotatedField; } + @Nullable public String getAnnotatedSetter() { return annotatedSetter; } @@ -65,6 +75,7 @@ public void setAnnotatedSetter(String annotatedSetter) { this.annotatedSetter = annotatedSetter; } + @Nullable @HeaderParameter("x-annotated-getter") public String getAnnotatedGetter() { return annotatedGetter; @@ -74,6 +85,7 @@ public void setAnnotatedGetter(String annotatedGetter) { this.annotatedGetter = annotatedGetter; } + @Nullable public Map getSimpleMap() { return simpleMap; } @@ -82,6 +94,7 @@ public void setSimpleMap(Map simpleMap) { this.simpleMap = simpleMap; } + @Nullable public MultiValueMap getMultiValueMap() { return multiValueMap; } @@ -90,6 +103,7 @@ public void setMultiValueMap(MultiValueMap multiValueMap) { this.multiValueMap = multiValueMap; } + @Nullable public HttpHeaders getHttpHeaders() { return httpHeaders; } @@ -98,6 +112,7 @@ public void setHttpHeaders(HttpHeaders httpHeaders) { this.httpHeaders = httpHeaders; } + @Nullable public String getValidated() { return validated; } @@ -106,6 +121,7 @@ public void setValidated(String validated) { this.validated = validated; } + @Nullable public NestedBean getNestedBean() { return nestedBean; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/HeaderParameterController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/HeaderParameterController.java index 4ce66a5..1761736 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/HeaderParameterController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/HeaderParameterController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,54 +13,59 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.test.web.bind.records.HeaderParameterRecord; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; +import jakarta.validation.Valid; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.validation.Valid; import java.util.Map; +import java.util.Objects; @RestController public class HeaderParameterController { + @Nullable @GetMapping(value = "/annotatedField", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedField(@BeanParameter HeaderParameterBean headerParameterBean) { return headerParameterBean.getAnnotatedField(); } + @Nullable @GetMapping(value = "/annotatedSetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedSetter(@BeanParameter HeaderParameterBean headerParameterBean) { return headerParameterBean.getAnnotatedSetter(); } + @Nullable @GetMapping(value = "/annotatedGetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedGetter(@BeanParameter HeaderParameterBean headerParameterBean) { return headerParameterBean.getAnnotatedGetter(); } + @Nullable @GetMapping(value = "/simpleMap", produces = MediaType.TEXT_PLAIN_VALUE) public String simpleMap(@BeanParameter HeaderParameterBean headerParameterBean) { Map simpleMap = headerParameterBean.getSimpleMap(); - return simpleMap.get("x-simple-map"); + return Objects.requireNonNull(simpleMap).get("x-simple-map"); } @GetMapping(value = "/multiValueMap", produces = MediaType.TEXT_PLAIN_VALUE) public String multiValueMap(@BeanParameter HeaderParameterBean headerParameterBean) { MultiValueMap multiValueMap = headerParameterBean.getMultiValueMap(); - return multiValueMap.getFirst("x-multivalue-map"); + return Objects.requireNonNull(multiValueMap).getFirst("x-multivalue-map"); } @GetMapping(value = "/httpHeaders", produces = MediaType.TEXT_PLAIN_VALUE) public String httpHeaders(@BeanParameter HeaderParameterBean headerParameterBean) { HttpHeaders httpHeaders = headerParameterBean.getHttpHeaders(); - return httpHeaders.getFirst("x-http-headers"); + return Objects.requireNonNull(httpHeaders).getFirst("x-http-headers"); } @GetMapping(value = "/bindingResult", produces = MediaType.TEXT_PLAIN_VALUE) @@ -68,6 +73,7 @@ public String bindingResult(@BeanParameter HeaderParameterBean headerParameterBe return Integer.toString(bindingResult.getErrorCount()); } + @Nullable @GetMapping(value = "/validated", produces = MediaType.TEXT_PLAIN_VALUE) public String validated(@Valid @BeanParameter HeaderParameterBean headerParameterBean) { return headerParameterBean.getValidated(); @@ -81,9 +87,10 @@ public String validatedWithBindingResult(@Valid @BeanParameter HeaderParameterBe return "valid"; } + @Nullable @GetMapping(value = "/nested", produces = MediaType.TEXT_PLAIN_VALUE) public String nestedBean(@BeanParameter HeaderParameterBean headerParameterBean) { - return headerParameterBean.getNestedBean().getHeaderValue(); + return Objects.requireNonNull(headerParameterBean.getNestedBean()).getHeaderValue(); } @GetMapping(value = "/record", produces = MediaType.TEXT_PLAIN_VALUE) diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/JsonBody.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/JsonBody.java index 667ad64..78f57ff 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/JsonBody.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/JsonBody.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,19 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.lang.Nullable; @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) public class JsonBody { + @Nullable @JsonProperty("json_property") private String property; + @Nullable public String getProperty() { return property; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/NestedBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/NestedBean.java index 3132b99..c7dda8e 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/NestedBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/NestedBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.CookieParameter; @@ -23,27 +22,35 @@ import com.mattbertolini.spring.web.bind.annotation.RequestBody; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; +import org.springframework.lang.Nullable; @SuppressWarnings("unused") public class NestedBean { + @Nullable @RequestParameter("nested_query_param") private String queryParam; + @Nullable @FormParameter("nested_form_param") private String formData; + @Nullable @CookieParameter("nested_cookie_param") private String cookieValue; + @Nullable @HeaderParameter("nested_header_param") private String headerValue; + @Nullable @PathParameter("nested_path_param") private String pathVariable; + @Nullable @SessionParameter("nested_session_param") private String sessionAttribute; + @Nullable public String getQueryParam() { return queryParam; } @@ -52,6 +59,7 @@ public void setQueryParam(String queryParam) { this.queryParam = queryParam; } + @Nullable public String getFormData() { return formData; } @@ -60,6 +68,7 @@ public void setFormData(String formData) { this.formData = formData; } + @Nullable public String getCookieValue() { return cookieValue; } @@ -68,6 +77,7 @@ public void setCookieValue(String cookieValue) { this.cookieValue = cookieValue; } + @Nullable public String getHeaderValue() { return headerValue; } @@ -76,6 +86,7 @@ public void setHeaderValue(String headerValue) { this.headerValue = headerValue; } + @Nullable public String getPathVariable() { return pathVariable; } @@ -84,6 +95,7 @@ public void setPathVariable(String pathVariable) { this.pathVariable = pathVariable; } + @Nullable public String getSessionAttribute() { return sessionAttribute; } @@ -93,9 +105,11 @@ public void setSessionAttribute(String sessionAttribute) { } public static class RequestBodyBean { + @Nullable @RequestBody private JsonBody requestBody; + @Nullable public JsonBody getRequestBody() { return requestBody; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/PathParameterBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/PathParameterBean.java index 8c33df5..1d1b6f4 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/PathParameterBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/PathParameterBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,33 +13,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import com.mattbertolini.spring.web.bind.annotation.PathParameter; +import jakarta.validation.constraints.NotEmpty; +import org.springframework.lang.Nullable; -import javax.validation.constraints.NotEmpty; import java.util.Map; public class PathParameterBean { + @Nullable @PathParameter("annotated_field") private String annotatedField; + @Nullable private String annotatedSetter; + @Nullable private String annotatedGetter; + @Nullable @PathParameter private Map simpleMap; + @Nullable @NotEmpty @PathParameter("validated") private String validated; + @Nullable @BeanParameter private NestedBean nestedBean; + @Nullable public String getAnnotatedField() { return annotatedField; } @@ -48,6 +55,7 @@ public void setAnnotatedField(String annotatedField) { this.annotatedField = annotatedField; } + @Nullable public String getAnnotatedSetter() { return annotatedSetter; } @@ -57,6 +65,7 @@ public void setAnnotatedSetter(String annotatedSetter) { this.annotatedSetter = annotatedSetter; } + @Nullable @PathParameter("annotated_getter") public String getAnnotatedGetter() { return annotatedGetter; @@ -66,6 +75,7 @@ public void setAnnotatedGetter(String annotatedGetter) { this.annotatedGetter = annotatedGetter; } + @Nullable public Map getSimpleMap() { return simpleMap; } @@ -74,6 +84,7 @@ public void setSimpleMap(Map simpleMap) { this.simpleMap = simpleMap; } + @Nullable public String getValidated() { return validated; } @@ -82,6 +93,7 @@ public void setValidated(String validated) { this.validated = validated; } + @Nullable public NestedBean getNestedBean() { return nestedBean; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/PathParameterController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/PathParameterController.java index 473bde8..2c09869 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/PathParameterController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/PathParameterController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,41 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.test.web.bind.records.PathParameterRecord; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; +import jakarta.validation.Valid; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.validation.Valid; import java.util.Map; +import java.util.Objects; @SuppressWarnings("MVCPathVariableInspection") @RestController public class PathParameterController { + @Nullable @GetMapping(value = "/annotatedField/{annotated_field}", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedField(@BeanParameter PathParameterBean pathParameterBean) { return pathParameterBean.getAnnotatedField(); } + @Nullable @GetMapping(value = "/annotatedSetter/{annotated_setter}", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedSetter(@BeanParameter PathParameterBean pathParameterBean) { return pathParameterBean.getAnnotatedSetter(); } + @Nullable @GetMapping(value = "/annotatedGetter/{annotated_getter}", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedGetter(@BeanParameter PathParameterBean pathParameterBean) { return pathParameterBean.getAnnotatedGetter(); } + @Nullable @GetMapping(value = "/simpleMap/{simple_map}") public String simpleMap(@BeanParameter PathParameterBean pathParameterBean) { Map simpleMap = pathParameterBean.getSimpleMap(); - return simpleMap.get("simple_map"); + return Objects.requireNonNull(simpleMap).get("simple_map"); } @GetMapping(value = "/bindingResult/{validated}", produces = MediaType.TEXT_PLAIN_VALUE) @@ -55,6 +60,7 @@ public String bindingResult(@BeanParameter PathParameterBean pathParameterBean, return Integer.toString(bindingResult.getErrorCount()); } + @Nullable @GetMapping(value = {"/validated", "/validated/{validated}"}, produces = MediaType.TEXT_PLAIN_VALUE) public String validated(@Valid @BeanParameter PathParameterBean pathParameterBean) { return pathParameterBean.getValidated(); @@ -68,9 +74,10 @@ public String validatedWithBindingResult(@Valid @BeanParameter PathParameterBean return "valid"; } + @Nullable @GetMapping(value = "/nested/{nested_path_param}", produces = MediaType.TEXT_PLAIN_VALUE) public String nestedBean(@BeanParameter PathParameterBean pathParameterBean) { - return pathParameterBean.getNestedBean().getPathVariable(); + return Objects.requireNonNull(pathParameterBean.getNestedBean()).getPathVariable(); } @GetMapping(value = "/record/{annotated_field}", produces = MediaType.TEXT_PLAIN_VALUE) diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestBodyBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestBodyBean.java index 9d59242..4e18329 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestBodyBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestBodyBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,24 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import com.mattbertolini.spring.web.bind.annotation.RequestBody; +import jakarta.validation.constraints.NotNull; import org.springframework.http.codec.multipart.Part; +import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; import reactor.core.publisher.Flux; -import javax.validation.constraints.NotNull; - public class RequestBodyBean { @SuppressWarnings("unused") public static class AnnotatedField { + @Nullable @RequestBody private JsonBody jsonBody; + @Nullable public JsonBody getJsonBody() { return jsonBody; } @@ -42,8 +43,10 @@ public void setJsonBody(JsonBody jsonBody) { @SuppressWarnings("unused") public static class AnnotatedSetter { + @Nullable private JsonBody jsonBody; + @Nullable public JsonBody getJsonBody() { return jsonBody; } @@ -56,8 +59,10 @@ public void setJsonBody(JsonBody jsonBody) { @SuppressWarnings("unused") public static class AnnotatedGetter { + @Nullable private JsonBody jsonBody; + @Nullable @RequestBody public JsonBody getJsonBody() { return jsonBody; @@ -70,9 +75,11 @@ public void setJsonBody(JsonBody jsonBody) { @SuppressWarnings("unused") public static class BindingResult { + @Nullable @RequestBody private JsonBody jsonBody; + @Nullable public JsonBody getJsonBody() { return jsonBody; } @@ -84,10 +91,13 @@ public void setJsonBody(JsonBody jsonBody) { @SuppressWarnings("unused") public static class Validation { + @SuppressWarnings("MultipleNullnessAnnotations") + @Nullable @NotNull @RequestBody private JsonBody jsonBody; - + + @Nullable public JsonBody getJsonBody() { return jsonBody; } @@ -99,9 +109,11 @@ public void setJsonBody(JsonBody jsonBody) { @SuppressWarnings("unused") public static class Nested { + @Nullable @BeanParameter private NestedBean.RequestBodyBean nestedBean; + @Nullable public NestedBean.RequestBodyBean getNestedBean() { return nestedBean; } @@ -113,9 +125,11 @@ public void setNestedBean(NestedBean.RequestBodyBean nestedBean) { @SuppressWarnings("unused") public static class WebFluxMultipartMultiValueMap { + @Nullable @RequestBody private MultiValueMap parts; + @Nullable public MultiValueMap getParts() { return parts; } @@ -127,9 +141,11 @@ public void setParts(MultiValueMap parts) { @SuppressWarnings("unused") public static class WebFluxMultipartFlux { + @Nullable @RequestBody private Flux parts; + @Nullable public Flux getParts() { return parts; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestBodyController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestBodyController.java index 5b53c11..5305263 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestBodyController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestBodyController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.test.web.bind.records.RequestBodyRecord; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; +import jakarta.validation.Valid; import org.springframework.http.MediaType; import org.springframework.http.codec.multipart.Part; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.validation.BindingResult; @@ -27,27 +28,31 @@ import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; -import javax.validation.Valid; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; +@SuppressWarnings("NullAway") @RestController public class RequestBodyController { + @Nullable @PostMapping(value = "/annotatedField", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) public String annotatedField(@BeanParameter RequestBodyBean.AnnotatedField requestBodyBean) { JsonBody jsonBody = requestBodyBean.getJsonBody(); - return jsonBody.getProperty(); + return Objects.requireNonNull(jsonBody).getProperty(); } + @Nullable @PostMapping(value = "/annotatedSetter", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) public String annotatedSetter(@BeanParameter RequestBodyBean.AnnotatedSetter requestBodyBean) { JsonBody jsonBody = requestBodyBean.getJsonBody(); - return jsonBody.getProperty(); + return Objects.requireNonNull(jsonBody).getProperty(); } + @Nullable @PostMapping(value = "/annotatedGetter", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) public String annotatedGetter(@BeanParameter RequestBodyBean.AnnotatedGetter requestBodyBean) { JsonBody jsonBody = requestBodyBean.getJsonBody(); - return jsonBody.getProperty(); + return Objects.requireNonNull(jsonBody).getProperty(); } @SuppressWarnings("unused") @@ -56,9 +61,10 @@ public String bindingResult(@BeanParameter RequestBodyBean.BindingResult request return Integer.toString(bindingResult.getErrorCount()); } + @Nullable @PostMapping(value = "/validated", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) public String validated(@Valid @BeanParameter RequestBodyBean.Validation requestBodyBean) { - return requestBodyBean.getJsonBody().getProperty(); + return Objects.requireNonNull(requestBodyBean.getJsonBody()).getProperty(); } @SuppressWarnings("unused") @@ -70,9 +76,10 @@ public String validatedWithBindingResult(@Valid @BeanParameter RequestBodyBean.V return "valid"; } + @Nullable @PostMapping(value = "/nested", produces = MediaType.TEXT_PLAIN_VALUE) public String nestedBeanParameter(@BeanParameter RequestBodyBean.Nested requestBodyBean) { - return requestBodyBean.getNestedBean().getRequestBody().getProperty(); + return Objects.requireNonNull(Objects.requireNonNull(requestBodyBean.getNestedBean()).getRequestBody()).getProperty(); } @PostMapping(value = "/multipartMultiValueMap", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @@ -93,6 +100,7 @@ public String multipartFlux(@BeanParameter RequestBodyBean.WebFluxMultipartFlux return "multipartFlux " + count.get(); } + @Nullable @PostMapping(value = "/record", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) public String javaRecord(@BeanParameter RequestBodyRecord requestBodyRecord) { JsonBody jsonBody = requestBodyRecord.jsonBody(); diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestContextBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestContextBean.java index d23a638..22a2dce 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestContextBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestContextBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,54 +13,67 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.RequestContext; +import jakarta.servlet.http.HttpSession; import org.springframework.http.HttpMethod; +import org.springframework.lang.Nullable; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebSession; -import javax.servlet.http.HttpSession; import java.time.ZoneId; import java.util.Locale; import java.util.TimeZone; @SuppressWarnings("unused") public class RequestContextBean { + @Nullable @RequestContext private NativeWebRequest webRequestField; + @Nullable private NativeWebRequest webRequestSetter; + @Nullable private NativeWebRequest webRequestGetter; + @Nullable @RequestContext private ServerWebExchange exchangeField; + @Nullable private ServerWebExchange exchangeSetter; + @Nullable private ServerWebExchange exchangeGetter; + @Nullable @RequestContext private Locale locale; + @Nullable @RequestContext private TimeZone timeZone; + @Nullable @RequestContext private ZoneId zoneId; + @Nullable @RequestContext private HttpMethod method; + @Nullable @RequestContext private HttpSession httpSession; + @Nullable @RequestContext private WebSession webSession; + @Nullable public NativeWebRequest getWebRequestField() { return webRequestField; } @@ -69,6 +82,7 @@ public void setWebRequestField(NativeWebRequest webRequestField) { this.webRequestField = webRequestField; } + @Nullable public NativeWebRequest getWebRequestSetter() { return webRequestSetter; } @@ -78,6 +92,7 @@ public void setWebRequestSetter(NativeWebRequest webRequestSetter) { this.webRequestSetter = webRequestSetter; } + @Nullable @RequestContext public NativeWebRequest getWebRequestGetter() { return webRequestGetter; @@ -87,6 +102,7 @@ public void setWebRequestGetter(NativeWebRequest webRequestGetter) { this.webRequestGetter = webRequestGetter; } + @Nullable public ServerWebExchange getExchangeField() { return exchangeField; } @@ -95,6 +111,7 @@ public void setExchangeField(ServerWebExchange exchangeField) { this.exchangeField = exchangeField; } + @Nullable public ServerWebExchange getExchangeSetter() { return exchangeSetter; } @@ -104,6 +121,7 @@ public void setExchangeSetter(ServerWebExchange exchangeSetter) { this.exchangeSetter = exchangeSetter; } + @Nullable @RequestContext public ServerWebExchange getExchangeGetter() { return exchangeGetter; @@ -113,6 +131,7 @@ public void setExchangeGetter(ServerWebExchange exchangeGetter) { this.exchangeGetter = exchangeGetter; } + @Nullable public Locale getLocale() { return locale; } @@ -121,6 +140,7 @@ public void setLocale(Locale locale) { this.locale = locale; } + @Nullable public TimeZone getTimeZone() { return timeZone; } @@ -129,6 +149,7 @@ public void setTimeZone(TimeZone timeZone) { this.timeZone = timeZone; } + @Nullable public ZoneId getZoneId() { return zoneId; } @@ -137,6 +158,7 @@ public void setZoneId(ZoneId zoneId) { this.zoneId = zoneId; } + @Nullable public HttpMethod getMethod() { return method; } @@ -145,6 +167,7 @@ public void setMethod(HttpMethod method) { this.method = method; } + @Nullable public HttpSession getHttpSession() { return httpSession; } @@ -153,6 +176,7 @@ public void setHttpSession(HttpSession httpSession) { this.httpSession = httpSession; } + @Nullable public WebSession getWebSession() { return webSession; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestContextController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestContextController.java index 821209b..5503da4 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestContextController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestContextController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.test.web.bind.records.RequestContextRecord; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Objects; + import static org.assertj.core.api.Assertions.assertThat; @RestController @@ -65,14 +67,16 @@ public String exchangeGetter(@BeanParameter RequestContextBean requestContextBea } // Locale + @Nullable @GetMapping(value = "/locale", produces = MediaType.TEXT_PLAIN_VALUE) public String locale(@BeanParameter RequestContextBean requestContextBean) { - return requestContextBean.getLocale().toString(); + return Objects.requireNonNull(requestContextBean.getLocale()).toString(); } + @Nullable @GetMapping(value = "/timeZone", produces = MediaType.TEXT_PLAIN_VALUE) public String timeZone(@BeanParameter RequestContextBean requestContextBean) { - return requestContextBean.getTimeZone().toString(); + return Objects.requireNonNull(requestContextBean.getTimeZone()).toString(); } @GetMapping(value = "/timeZoneRecord", produces = MediaType.TEXT_PLAIN_VALUE) @@ -80,23 +84,27 @@ public String javaRecordTimeZone(@BeanParameter RequestContextRecord requestCont return requestContextRecord.timeZone().toString(); } + @Nullable @GetMapping(value = "/zoneId", produces = MediaType.TEXT_PLAIN_VALUE) public String zoneId(@BeanParameter RequestContextBean requestContextBean) { - return requestContextBean.getZoneId().toString(); + return Objects.requireNonNull(requestContextBean.getZoneId()).toString(); } + @Nullable @GetMapping(value = "/method", produces = MediaType.TEXT_PLAIN_VALUE) public String method(@BeanParameter RequestContextBean requestContextBean) { - return requestContextBean.getMethod().toString(); + return Objects.requireNonNull(requestContextBean.getMethod()).toString(); } + @Nullable @GetMapping(value = "/session", produces = MediaType.TEXT_PLAIN_VALUE) public String httpSession(@BeanParameter RequestContextBean requestContextBean) { - return (String) requestContextBean.getHttpSession().getAttribute("name"); + return (String) Objects.requireNonNull(requestContextBean.getHttpSession()).getAttribute("name"); } + @Nullable @GetMapping(value = "/webSession", produces = MediaType.TEXT_PLAIN_VALUE) public String webSession(@BeanParameter RequestContextBean requestContextBean) { - return requestContextBean.getWebSession().getAttribute("name"); + return Objects.requireNonNull(requestContextBean.getWebSession()).getAttribute("name"); } } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestParameterBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestParameterBean.java index 73f239e..2a38bd6 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestParameterBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestParameterBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,39 +13,47 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; +import jakarta.servlet.http.Part; +import jakarta.validation.constraints.NotEmpty; +import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.Part; -import javax.validation.constraints.NotEmpty; import java.util.Map; public class RequestParameterBean { + @Nullable @RequestParameter("annotated_field") private String annotatedField; + @Nullable private String annotatedSetter; + @Nullable private String annotatedGetter; + @Nullable @RequestParameter private Map simpleMap; + @Nullable @RequestParameter private MultiValueMap multiValueMap; + @Nullable @NotEmpty @RequestParameter("validated") private String validated; + @Nullable @BeanParameter private NestedBean nestedBean; + @Nullable public String getAnnotatedField() { return annotatedField; } @@ -54,6 +62,7 @@ public void setAnnotatedField(String annotatedField) { this.annotatedField = annotatedField; } + @Nullable public String getAnnotatedSetter() { return annotatedSetter; } @@ -63,6 +72,7 @@ public void setAnnotatedSetter(String annotatedSetter) { this.annotatedSetter = annotatedSetter; } + @Nullable @RequestParameter("annotated_getter") public String getAnnotatedGetter() { return annotatedGetter; @@ -72,6 +82,7 @@ public void setAnnotatedGetter(String annotatedGetter) { this.annotatedGetter = annotatedGetter; } + @Nullable public Map getSimpleMap() { return simpleMap; } @@ -80,6 +91,7 @@ public void setSimpleMap(Map simpleMap) { this.simpleMap = simpleMap; } + @Nullable public MultiValueMap getMultiValueMap() { return multiValueMap; } @@ -88,6 +100,7 @@ public void setMultiValueMap(MultiValueMap multiValueMap) { this.multiValueMap = multiValueMap; } + @Nullable public String getValidated() { return validated; } @@ -96,6 +109,7 @@ public void setValidated(String validated) { this.validated = validated; } + @Nullable public NestedBean getNestedBean() { return nestedBean; } @@ -107,25 +121,32 @@ public void setNestedBean(NestedBean nestedBean) { /** * Test bean for multipart binding in a Servlet/WebMVC application */ - static class ServletMultipartBean { + public static class ServletMultipartBean { + @Nullable @RequestParameter("file") private MultipartFile multipartFile; + @Nullable @RequestParameter("part") private Part part; + @Nullable @RequestParameter private Map multipartFileMap; + @Nullable @RequestParameter private MultiValueMap multiValueMultipartMap; + @Nullable @RequestParameter private Map partMap; + @Nullable @RequestParameter private MultiValueMap multiValuePartMap; + @Nullable public MultipartFile getMultipartFile() { return multipartFile; } @@ -134,6 +155,7 @@ public void setMultipartFile(MultipartFile multipartFile) { this.multipartFile = multipartFile; } + @Nullable public Part getPart() { return part; } @@ -142,6 +164,7 @@ public void setPart(Part part) { this.part = part; } + @Nullable public Map getMultipartFileMap() { return multipartFileMap; } @@ -150,6 +173,7 @@ public void setMultipartFileMap(Map multipartFileMap) { this.multipartFileMap = multipartFileMap; } + @Nullable public MultiValueMap getMultiValueMultipartMap() { return multiValueMultipartMap; } @@ -158,6 +182,7 @@ public void setMultiValueMultipartMap(MultiValueMap multi this.multiValueMultipartMap = multiValueMultipartMap; } + @Nullable public Map getPartMap() { return partMap; } @@ -166,6 +191,7 @@ public void setPartMap(Map partMap) { this.partMap = partMap; } + @Nullable public MultiValueMap getMultiValuePartMap() { return multiValuePartMap; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestParameterController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestParameterController.java index 7edb153..a7ef194 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestParameterController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/RequestParameterController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.test.web.bind.records.RequestParameterRecord; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; +import jakarta.servlet.http.Part; +import jakarta.validation.Valid; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; import org.springframework.util.StreamUtils; import org.springframework.validation.BindingResult; @@ -27,41 +29,46 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.Part; -import javax.validation.Valid; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; +@SuppressWarnings("NullAway") @RestController public class RequestParameterController { + @Nullable @GetMapping(value = "/annotatedField", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedField(@BeanParameter RequestParameterBean requestParameterBean) { return requestParameterBean.getAnnotatedField(); } + @Nullable @GetMapping(value = "/annotatedSetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedSetter(@BeanParameter RequestParameterBean requestParameterBean) { return requestParameterBean.getAnnotatedSetter(); } + @Nullable @GetMapping(value = "/annotatedGetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedGetter(@BeanParameter RequestParameterBean requestParameterBean) { return requestParameterBean.getAnnotatedGetter(); } + @Nullable @GetMapping(value = "/simpleMap", produces = MediaType.TEXT_PLAIN_VALUE) public String simpleMap(@BeanParameter RequestParameterBean requestParameterBean) { Map simpleMap = requestParameterBean.getSimpleMap(); - return simpleMap.get("simpleMap"); + return Objects.requireNonNull(simpleMap).get("simpleMap"); } + @Nullable @GetMapping(value = "/multiValueMap", produces = MediaType.TEXT_PLAIN_VALUE) public String multiValueMap(@BeanParameter RequestParameterBean requestParameterBean) { MultiValueMap multiValueMap = requestParameterBean.getMultiValueMap(); - return multiValueMap.getFirst("multiValueMap"); + return Objects.requireNonNull(multiValueMap).getFirst("multiValueMap"); } @GetMapping(value = "/bindingResult", produces = MediaType.TEXT_PLAIN_VALUE) @@ -69,6 +76,7 @@ public String bindingResult(@BeanParameter RequestParameterBean requestParameter return Integer.toString(bindingResult.getErrorCount()); } + @Nullable @GetMapping(value = "/validated", produces = MediaType.TEXT_PLAIN_VALUE) public String validated(@Valid @BeanParameter RequestParameterBean requestParameterBean) { return requestParameterBean.getValidated(); @@ -88,7 +96,7 @@ public String multipartFile(@BeanParameter RequestParameterBean.ServletMultipart if (multipartFile == null || multipartFile.isEmpty()) { throw new RuntimeException("Multipart file is null or empty"); } - return new String(multipartFile.getBytes()); + return new String(multipartFile.getBytes(), StandardCharsets.UTF_8); } @PostMapping(value = "/part", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @@ -103,9 +111,9 @@ public String part(@BeanParameter RequestParameterBean.ServletMultipartBean requ @PostMapping(value = "/multipartFileMap", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public String multipartFileMap(@BeanParameter RequestParameterBean.ServletMultipartBean requestParameterBean) throws Exception { Map multipartFileMap = requestParameterBean.getMultipartFileMap(); - MultipartFile fileOne = multipartFileMap.get("fileOne"); + MultipartFile fileOne = Objects.requireNonNull(multipartFileMap).get("fileOne"); MultipartFile fileTwo = multipartFileMap.get("fileTwo"); - return new String(fileOne.getBytes()) + ", " + new String(fileTwo.getBytes()); + return new String(fileOne.getBytes(), StandardCharsets.UTF_8) + ", " + new String(fileTwo.getBytes(), StandardCharsets.UTF_8); } @PostMapping(value = "/multiValueMultipartFileMap", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @@ -114,7 +122,7 @@ public String multiValueMultipartFileMap(@BeanParameter RequestParameterBean.Ser List files = multiValueMultipartMap.get("file"); return files.stream().map(multipartFile -> { try { - return new String(multipartFile.getBytes()); + return new String(multipartFile.getBytes(), StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException(e); } @@ -133,7 +141,7 @@ public String partMap(@BeanParameter RequestParameterBean.ServletMultipartBean r @PostMapping(value = "/multiValuePartMap", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public String multiValuePartMap(@BeanParameter RequestParameterBean.ServletMultipartBean requestParameterBean) { MultiValueMap multiValuePartMap = requestParameterBean.getMultiValuePartMap(); - List files = multiValuePartMap.get("file"); + List files = Objects.requireNonNull(multiValuePartMap).get("file"); return files.stream().map(part -> { try { return StreamUtils.copyToString(part.getInputStream(), StandardCharsets.UTF_8); @@ -143,9 +151,10 @@ public String multiValuePartMap(@BeanParameter RequestParameterBean.ServletMulti }).collect(Collectors.joining(", ")); } + @Nullable @GetMapping(value = "/nested", produces = MediaType.TEXT_PLAIN_VALUE) public String nestedBeanParameter(@BeanParameter RequestParameterBean requestParameterBean) { - return requestParameterBean.getNestedBean().getQueryParam(); + return Objects.requireNonNull(requestParameterBean.getNestedBean()).getQueryParam(); } @GetMapping(value = "/record", produces = MediaType.TEXT_PLAIN_VALUE) diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/SessionParameterBean.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/SessionParameterBean.java index 01b7f1b..429ff26 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/SessionParameterBean.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/SessionParameterBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,30 +13,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; - -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; +import org.springframework.lang.Nullable; public class SessionParameterBean { + @Nullable @SessionParameter("annotated_field") private String annotatedField; + @Nullable private String annotatedSetter; + @Nullable private String annotatedGetter; + @Nullable public String getAnnotatedField() { return annotatedField; } + @Nullable @NotEmpty @SessionParameter("validated") private String validated; + @Nullable @BeanParameter private NestedBean nestedBean; @@ -44,6 +49,7 @@ public void setAnnotatedField(String annotatedField) { this.annotatedField = annotatedField; } + @Nullable public String getAnnotatedSetter() { return annotatedSetter; } @@ -53,6 +59,7 @@ public void setAnnotatedSetter(String annotatedSetter) { this.annotatedSetter = annotatedSetter; } + @Nullable @SessionParameter("annotated_getter") public String getAnnotatedGetter() { return annotatedGetter; @@ -62,6 +69,7 @@ public void setAnnotatedGetter(String annotatedGetter) { this.annotatedGetter = annotatedGetter; } + @Nullable public String getValidated() { return validated; } @@ -70,6 +78,7 @@ public void setValidated(String validated) { this.validated = validated; } + @Nullable public NestedBean getNestedBean() { return nestedBean; } diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/SessionParameterController.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/SessionParameterController.java index 14d57ff..10e8b31 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/SessionParameterController.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/SessionParameterController.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,30 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind; import com.mattbertolini.spring.test.web.bind.records.SessionParameterRecord; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; +import jakarta.validation.Valid; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.validation.Valid; +import java.util.Objects; @RestController public class SessionParameterController { + @Nullable @GetMapping(value = "/annotatedField", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedField(@BeanParameter SessionParameterBean sessionParameterBean) { return sessionParameterBean.getAnnotatedField(); } + @Nullable @GetMapping(value = "/annotatedSetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedSetter(@BeanParameter SessionParameterBean sessionParameterBean) { return sessionParameterBean.getAnnotatedSetter(); } + @Nullable @GetMapping(value = "/annotatedGetter", produces = MediaType.TEXT_PLAIN_VALUE) public String annotatedGetter(@BeanParameter SessionParameterBean sessionParameterBean) { return sessionParameterBean.getAnnotatedGetter(); @@ -47,6 +51,7 @@ public String bindingResult(@BeanParameter SessionParameterBean sessionParameter return Integer.toString(bindingResult.getErrorCount()); } + @Nullable @GetMapping(value = "/validated", produces = MediaType.TEXT_PLAIN_VALUE) public String validated(@Valid @BeanParameter SessionParameterBean sessionParameterBean) { return sessionParameterBean.getValidated(); @@ -60,9 +65,10 @@ public String validatedWithBindingResult(@Valid @BeanParameter SessionParameterB return "valid"; } + @Nullable @GetMapping(value = "/nested", produces = MediaType.TEXT_PLAIN_VALUE) public String nestedBean(@BeanParameter SessionParameterBean sessionParameterBean) { - return sessionParameterBean.getNestedBean().getSessionAttribute(); + return Objects.requireNonNull(sessionParameterBean.getNestedBean()).getSessionAttribute(); } @GetMapping(value = "/record", produces = MediaType.TEXT_PLAIN_VALUE) diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/CookieParameterRecord.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/CookieParameterRecord.java index 3a12092..ce39aeb 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/CookieParameterRecord.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/CookieParameterRecord.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind.records; import com.mattbertolini.spring.web.bind.annotation.CookieParameter; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/FormParameterRecord.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/FormParameterRecord.java index f297dc6..f1fbcc3 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/FormParameterRecord.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/FormParameterRecord.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind.records; import com.mattbertolini.spring.web.bind.annotation.FormParameter; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/HeaderParameterRecord.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/HeaderParameterRecord.java index d81120f..dd9092c 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/HeaderParameterRecord.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/HeaderParameterRecord.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind.records; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/PathParameterRecord.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/PathParameterRecord.java index ae11bee..7f04362 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/PathParameterRecord.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/PathParameterRecord.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind.records; import com.mattbertolini.spring.web.bind.annotation.PathParameter; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestBodyRecord.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestBodyRecord.java index fe92418..d6dd140 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestBodyRecord.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestBodyRecord.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind.records; import com.mattbertolini.spring.test.web.bind.JsonBody; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestContextRecord.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestContextRecord.java index 69481fe..01ac3ed 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestContextRecord.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestContextRecord.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind.records; import com.mattbertolini.spring.web.bind.annotation.RequestContext; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestParameterRecord.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestParameterRecord.java index 4f06f2f..ea685dc 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestParameterRecord.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/RequestParameterRecord.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind.records; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/SessionParameterRecord.java b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/SessionParameterRecord.java index 10799cc..efd2669 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/SessionParameterRecord.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/test/web/bind/records/SessionParameterRecord.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.test.web.bind.records; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/CookieParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/CookieParameterIntegrationTest.java index 902b997..baf5900 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/CookieParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/CookieParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.CookieParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/DirectFieldAccessIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/DirectFieldAccessIntegrationTest.java index 02e6644..362b5e1 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/DirectFieldAccessIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/DirectFieldAccessIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.DirectFieldAccessController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/FormParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/FormParameterIntegrationTest.java index d1efd7b..0e4359a 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/FormParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/FormParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.FormParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/HeaderParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/HeaderParameterIntegrationTest.java index 624f085..fe88110 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/HeaderParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/HeaderParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.HeaderParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/PathParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/PathParameterIntegrationTest.java index 169ccd5..7ac9044 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/PathParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/PathParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.PathParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestBodyIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestBodyIntegrationTest.java index 9d2b6fd..4f9e342 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestBodyIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestBodyIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.RequestBodyController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestContextIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestContextIntegrationTest.java index 9c5be22..f6ced5a 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestContextIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestContextIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.RequestContextController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestParameterIntegrationTest.java index b1d2836..073daad 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/RequestParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.RequestParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionFilter.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionFilter.java index e2f261f..5424c7d 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionFilter.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionFilter.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import org.springframework.lang.NonNull; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionMutator.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionMutator.java index 11291cb..2bff9ae 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionMutator.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionMutator.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import org.springframework.http.client.reactive.ClientHttpConnector; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionParameterIntegrationTest.java index 0debef3..b730cad 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/reactive/test/SessionParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.test; import com.mattbertolini.spring.test.web.bind.SessionParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/CookieParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/CookieParameterIntegrationTest.java index 17aac83..89dcf5a 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/CookieParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/CookieParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.CookieParameterController; import com.mattbertolini.spring.web.servlet.mvc.bind.config.BinderConfiguration; +import jakarta.servlet.http.Cookie; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Bean; @@ -30,8 +30,6 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import javax.servlet.http.Cookie; - import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/DirectFieldAccessIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/DirectFieldAccessIntegrationTest.java index 2af7b3c..d4d62b3 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/DirectFieldAccessIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/DirectFieldAccessIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.DirectFieldAccessController; import com.mattbertolini.spring.web.servlet.mvc.bind.config.BinderConfiguration; +import jakarta.servlet.http.Cookie; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Bean; @@ -34,8 +34,6 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; -import javax.servlet.http.Cookie; - 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.content; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/FormParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/FormParameterIntegrationTest.java index b22ad14..43ea0b4 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/FormParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/FormParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.FormParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/HeaderParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/HeaderParameterIntegrationTest.java index 4c8fe99..d01e329 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/HeaderParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/HeaderParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.HeaderParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/PathParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/PathParameterIntegrationTest.java index b454443..05f546e 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/PathParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/PathParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.PathParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestBodyIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestBodyIntegrationTest.java index a406081..39647c3 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestBodyIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestBodyIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.RequestBodyController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestContextIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestContextIntegrationTest.java index 29d7743..278d818 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestContextIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestContextIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.RequestContextController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestParameterIntegrationTest.java index 29f51af..d4ea073 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/RequestParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.RequestParameterController; diff --git a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/SessionParameterIntegrationTest.java b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/SessionParameterIntegrationTest.java index 87d2983..1aceb35 100644 --- a/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/SessionParameterIntegrationTest.java +++ b/integration-tests/src/test/java/com/mattbertolini/spring/web/servlet/mvc/test/SessionParameterIntegrationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.test; import com.mattbertolini.spring.test.web.bind.SessionParameterController; diff --git a/libs.versions.toml b/libs.versions.toml index e91f1b7..f8047b9 100644 --- a/libs.versions.toml +++ b/libs.versions.toml @@ -1,12 +1,16 @@ [versions] -spring = "5.3.28" # Used in java-conventions.gradle.kts -springBoot = "2.7.13" # Used in java-conventions.gradle.kts +spring = "6.1.10" # Used in java-conventions.gradle.kts +springBoot = "3.3.1" # Used in java-conventions.gradle.kts junit = "5.9.3" # Used in java-conventions.gradle.kts jacoco = "0.8.10" # Used in java-conventions.gradle.kts +errorProne = "2.29.0" +nullAway = "0.11.0" [libraries] -javaxServletApi = { module = "javax.servlet:javax.servlet-api", version = "4.0.1" } -javaxValidationApi = { module = "javax.validation:validation-api", version = "2.0.1.Final" } +jakartaServletApi = { module = "jakarta.servlet:jakarta.servlet-api", version = "6.0.0" } +jakartaValidationApi = { module = "jakarta.validation:jakarta.validation-api", version = "3.1.0" } +jakartaWebsocketApi = { module = "jakarta.websocket:jakarta.websocket-api", version = "2.2.0" } +jakartaWebsocketClientApi = { module = "jakarta.websocket:jakarta.websocket-client-api", version = "2.2.0" } findbugsJsr305 = { module = "com.google.code.findbugs:jsr305", version = "3.0.2" } @@ -22,9 +26,9 @@ springBootTest = { module = "org.springframework.boot:spring-boot-test", version springAsciidoctorExtBlockSwitch = { module = "io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch", version = "0.6.1" } -glassfishJavaxEl = { module = "org.glassfish:javax.el", version = "3.0.1-b12" } # Needed by Hibernate Validator -hibernateValidator = { module = "org.hibernate.validator:hibernate-validator", version = "6.0.21.Final" } -jacksonDatabind = { module = "com.fasterxml.jackson.core:jackson-databind", version = "2.12.7.1" } +glassfishJakartaEl = { module = "org.glassfish:jakarta.el", version = "4.0.2" } # Needed by Hibernate Validator +hibernateValidator = { module = "org.hibernate.validator:hibernate-validator", version = "8.0.1.Final" } +jacksonDatabind = { module = "com.fasterxml.jackson.core:jackson-databind", version = "2.17.2" } junitJupiterApi = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } assertJCore = { module = "org.assertj:assertj-core", version = "3.24.2" } @@ -32,6 +36,11 @@ mockitoCore = { module = "org.mockito:mockito-core", version = "5.3.1" } equalsVerifier = { module = "nl.jqno.equalsverifier:equalsverifier", version = "3.14.2" } hamcrest = { module = "org.hamcrest:hamcrest", version = "2.2" } +errorProneCore = { module = "com.google.errorprone:error_prone_core", version.ref = "errorProne" } +errorProneAnnotations = { module = "com.google.errorprone:error_prone_annotations", version.ref = "errorProne"} +nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" } +nullAwayAnnotations = { module = "com.uber.nullaway:nullaway-annotations", version.ref = "nullAway" } + [plugins] asciidoctorConvert = { id = "org.asciidoctor.jvm.convert", version = "3.3.2" } sonarqube = { id = "org.sonarqube", version = "5.0.0.4638" } \ No newline at end of file diff --git a/publish.sh b/publish.sh old mode 100644 new mode 100755 index c116e88..dedec2d --- a/publish.sh +++ b/publish.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash # Disabling parallel builds as it doesn't work when publishing to Maven Central -./gradlew --no-parallel build publish \ No newline at end of file +./gradlew --no-parallel --no-configuration-cache build publish \ No newline at end of file diff --git a/spring-annotated-data-binder-core/build.gradle.kts b/spring-annotated-data-binder-core/build.gradle.kts index 8a644b6..df52b27 100644 --- a/spring-annotated-data-binder-core/build.gradle.kts +++ b/spring-annotated-data-binder-core/build.gradle.kts @@ -8,13 +8,14 @@ dependencies { api(libs.springBeans) api(libs.springWeb) compileOnly(libs.findbugsJsr305) // To Prevent warnings on missing enum constants - compileOnly(libs.javaxServletApi) // So Javadoc doesn't give warnings about missing links + compileOnly(libs.jakartaServletApi) // So Javadoc doesn't give warnings about missing links testImplementation(libs.junitJupiterApi) testImplementation(libs.assertJCore) testImplementation(libs.mockitoCore) testImplementation(libs.springTest) testImplementation(libs.equalsVerifier) + testCompileOnly(libs.findbugsJsr305) } tasks.named("jar").configure { diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/AbstractPropertyResolverRegistry.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/AbstractPropertyResolverRegistry.java index c466838..a6dd6d1 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/AbstractPropertyResolverRegistry.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/AbstractPropertyResolverRegistry.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import com.mattbertolini.spring.web.bind.resolver.RequestPropertyResolverBase; -import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import java.util.Collections; @@ -38,7 +36,7 @@ protected AbstractPropertyResolverRegistry() { } @Nullable - public T findResolverFor(@NonNull BindingProperty bindingProperty) { + public T findResolverFor(BindingProperty bindingProperty) { for (T resolver : propertyResolvers) { if (resolver.supports(bindingProperty)) { return resolver; @@ -77,7 +75,6 @@ public void addResolvers(AbstractPropertyResolverRegistry registry) { /** * Returns an unmodifiable collection of the resolvers. */ - @NonNull public Set getPropertyResolvers() { return Collections.unmodifiableSet(propertyResolvers); } diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/PropertyResolutionException.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/PropertyResolutionException.java index 614bfae..c658a6f 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/PropertyResolutionException.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/PropertyResolutionException.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind; /** diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/RequestPropertyBindingException.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/RequestPropertyBindingException.java index a5c553e..bfec84f 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/RequestPropertyBindingException.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/RequestPropertyBindingException.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind; public class RequestPropertyBindingException extends RuntimeException { diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/BeanParameter.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/BeanParameter.java index ea311a7..571e026 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/BeanParameter.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/BeanParameter.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.annotation; import java.lang.annotation.Documented; diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/CookieParameter.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/CookieParameter.java index f140ac1..afc9370 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/CookieParameter.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/CookieParameter.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.annotation; import java.lang.annotation.Documented; @@ -40,7 +39,7 @@ *

* *

If you need access to all attributes of a cookie (e.g. expiration date, domain, etc) you can bind to cookie - * objects. In Spring MVC you and bind directly to a {@link javax.servlet.http.Cookie}: + * objects. In Spring MVC you and bind directly to a {@link jakarta.servlet.http.Cookie}: *

{@code
  *     @CookieParameter("cookie_name")
  *     private Cookie cookie;
diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/FormParameter.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/FormParameter.java
index 430bb20..22de602 100644
--- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/FormParameter.java
+++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/FormParameter.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019-2022 the original author or authors.
+ * Copyright 2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.mattbertolini.spring.web.bind.annotation;
 
 import java.lang.annotation.Documented;
diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/HeaderParameter.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/HeaderParameter.java
index eb00ef4..36dbff1 100644
--- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/HeaderParameter.java
+++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/HeaderParameter.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019-2022 the original author or authors.
+ * Copyright 2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.mattbertolini.spring.web.bind.annotation;
 
 import java.lang.annotation.Documented;
diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/PathParameter.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/PathParameter.java
index 7658576..e5522b9 100644
--- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/PathParameter.java
+++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/PathParameter.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019-2022 the original author or authors.
+ * Copyright 2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.mattbertolini.spring.web.bind.annotation;
 
 import java.lang.annotation.Documented;
diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestBean.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestBean.java
index e13df18..57c5153 100644
--- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestBean.java
+++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestBean.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019-2022 the original author or authors.
+ * Copyright 2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.mattbertolini.spring.web.bind.annotation;
 
 import java.lang.annotation.Documented;
diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestBody.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestBody.java
index 367ef91..9acb239 100644
--- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestBody.java
+++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestBody.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019-2022 the original author or authors.
+ * Copyright 2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.mattbertolini.spring.web.bind.annotation;
 
 import java.lang.annotation.Documented;
diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestContext.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestContext.java
index c77a55e..eea5d95 100644
--- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestContext.java
+++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestContext.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019-2020 the original author or authors.
+ * Copyright 2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.mattbertolini.spring.web.bind.annotation;
 
 import java.lang.annotation.Documented;
@@ -33,8 +32,8 @@
  * In Spring MVC the following additional objects are available:
  * 
    *
  • {@link org.springframework.web.context.request.WebRequest} - The Spring WebRequest.
  • - *
  • {@link javax.servlet.http.HttpServletRequest} - The underlying Servlet request.
  • - *
  • {@link javax.servlet.http.HttpSession} - The Servlet session object.
  • + *
  • {@link jakarta.servlet.http.HttpServletRequest} - The underlying Servlet request.
  • + *
  • {@link jakarta.servlet.http.HttpSession} - The Servlet session object.
  • *
* In Spring WebFlux the following additional objects are available: *
    diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestParameter.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestParameter.java index d284a89..fe15359 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestParameter.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/RequestParameter.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.annotation; import java.lang.annotation.Documented; diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/SessionParameter.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/SessionParameter.java index 1d2b465..158229c 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/SessionParameter.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/SessionParameter.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.annotation; import java.lang.annotation.Documented; diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/package-info.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/package-info.java new file mode 100644 index 0000000..91f6d2c --- /dev/null +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/annotation/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.bind.annotation; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/AnnotatedRequestBeanIntrospector.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/AnnotatedRequestBeanIntrospector.java index 501ef87..df9b38f 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/AnnotatedRequestBeanIntrospector.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/AnnotatedRequestBeanIntrospector.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,11 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; -import org.springframework.lang.NonNull; - import java.util.Collection; import java.util.Collections; import java.util.Map; @@ -32,8 +29,7 @@ public interface AnnotatedRequestBeanIntrospector { * @return A map of resolved property data. This map is never null but may be empty. * @throws CircularReferenceException If a circular reference is found while traversing the object graph. */ - @NonNull - Map getResolverMapFor(@NonNull Class targetType); + Map getResolverMapFor(Class targetType); /** * Creates a list of resolved property data for the given target class. This method traverses the object graph for @@ -43,8 +39,7 @@ public interface AnnotatedRequestBeanIntrospector { * @return A list of resolved property data. This list is never null but may be empty. * @throws CircularReferenceException If a circular reference is found while traversing the object graph. */ - @NonNull - default Collection getResolversFor(@NonNull Class targetType) { + default Collection getResolversFor(Class targetType) { Map propertyData = getResolverMapFor(targetType); return Collections.unmodifiableCollection(propertyData.values()); } diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/BindingProperty.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/BindingProperty.java index 357e637..2efe4e6 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/BindingProperty.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/BindingProperty.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; import org.springframework.core.MethodParameter; import org.springframework.core.convert.Property; import org.springframework.core.convert.TypeDescriptor; -import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import java.beans.PropertyDescriptor; @@ -35,7 +33,7 @@ public final class BindingProperty { private final TypeDescriptor typeDescriptor; private final MethodParameter methodParameter; - private BindingProperty(@NonNull TypeDescriptor typeDescriptor, @NonNull MethodParameter methodParameter) { + private BindingProperty(TypeDescriptor typeDescriptor, MethodParameter methodParameter) { this.typeDescriptor = typeDescriptor; this.methodParameter = methodParameter; } @@ -45,7 +43,6 @@ public T getAnnotation(Class annotationType) { return typeDescriptor.getAnnotation(annotationType); } - @NonNull public MethodParameter getMethodParameter() { return methodParameter; } @@ -69,8 +66,7 @@ public boolean hasAnnotation(Class annotationType) { * @param propertyDescriptor The Java Beans PropertyDescriptor to create a BindingProperty for. * @return A new BindingProperty object. */ - @NonNull - public static BindingProperty forPropertyDescriptor(@NonNull PropertyDescriptor propertyDescriptor) { + public static BindingProperty forPropertyDescriptor(PropertyDescriptor propertyDescriptor) { Property property = new Property( propertyDescriptor.getPropertyType(), propertyDescriptor.getReadMethod(), @@ -86,8 +82,7 @@ public static BindingProperty forPropertyDescriptor(@NonNull PropertyDescriptor * This method is more or less the same as found in {@link Property} but those are not exposed publicly so I * needed to replicate it. */ - @NonNull - private static MethodParameter resolveMethodParameter(@NonNull Property property) { + private static MethodParameter resolveMethodParameter(Property property) { MethodParameter readMethodParameter = resolveReadMethodParameter(property); MethodParameter writeMethodParameter = resolveWriteMethodParameter(property); if (writeMethodParameter == null) { @@ -107,7 +102,7 @@ private static MethodParameter resolveMethodParameter(@NonNull Property property } @Nullable - private static MethodParameter resolveReadMethodParameter(@NonNull Property property) { + private static MethodParameter resolveReadMethodParameter(Property property) { if (property.getReadMethod() == null) { return null; } @@ -115,7 +110,7 @@ private static MethodParameter resolveReadMethodParameter(@NonNull Property prop } @Nullable - private static MethodParameter resolveWriteMethodParameter(@NonNull Property property) { + private static MethodParameter resolveWriteMethodParameter(Property property) { if (property.getWriteMethod() == null) { return null; } diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/CachedAnnotatedRequestBeanIntrospector.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/CachedAnnotatedRequestBeanIntrospector.java index 6ac201e..948e329 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/CachedAnnotatedRequestBeanIntrospector.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/CachedAnnotatedRequestBeanIntrospector.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,11 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; -import org.springframework.lang.NonNull; - import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -26,14 +23,13 @@ public class CachedAnnotatedRequestBeanIntrospector implements AnnotatedRequestB private final AnnotatedRequestBeanIntrospector delegate; private final ConcurrentMap, Map> cache; - public CachedAnnotatedRequestBeanIntrospector(@NonNull AnnotatedRequestBeanIntrospector delegate) { + public CachedAnnotatedRequestBeanIntrospector(AnnotatedRequestBeanIntrospector delegate) { this.delegate = delegate; cache = new ConcurrentHashMap<>(); } @Override - @NonNull - public Map getResolverMapFor(@NonNull Class targetType) { + public Map getResolverMapFor(Class targetType) { return cache.computeIfAbsent(targetType, delegate::getResolverMapFor); } } diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/CircularReferenceException.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/CircularReferenceException.java index d728f97..c48b717 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/CircularReferenceException.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/CircularReferenceException.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; /** diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/ClassPathScanningAnnotatedRequestBeanIntrospector.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/ClassPathScanningAnnotatedRequestBeanIntrospector.java index 2a64fb4..66225de 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/ClassPathScanningAnnotatedRequestBeanIntrospector.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/ClassPathScanningAnnotatedRequestBeanIntrospector.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; import com.mattbertolini.spring.web.bind.annotation.RequestBean; @@ -23,7 +22,6 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -39,7 +37,7 @@ public class ClassPathScanningAnnotatedRequestBeanIntrospector implements Annota private final CachedAnnotatedRequestBeanIntrospector introspectorCache; private final Set basePackages; - public ClassPathScanningAnnotatedRequestBeanIntrospector(@NonNull AnnotatedRequestBeanIntrospector delegate, @Nullable Set basePackages) { + public ClassPathScanningAnnotatedRequestBeanIntrospector(AnnotatedRequestBeanIntrospector delegate, @Nullable Set basePackages) { this.basePackages = new HashSet<>(); if (basePackages != null) { this.basePackages.addAll(basePackages); @@ -50,8 +48,7 @@ public ClassPathScanningAnnotatedRequestBeanIntrospector(@NonNull AnnotatedReque } @Override - @NonNull - public Map getResolverMapFor(@NonNull Class targetType) { + public Map getResolverMapFor(Class targetType) { return introspectorCache.getResolverMapFor(targetType); } @@ -62,7 +59,7 @@ public void afterPropertiesSet() { } } - private void scanAndLoadRequestBeans(@NonNull String basePackage) { + private void scanAndLoadRequestBeans(String basePackage) { ClassLoader classLoader = ClassPathScanningAnnotatedRequestBeanIntrospector.class.getClassLoader(); LOGGER.debug("Searching for @RequestBean annotated classes in package [" + basePackage + "]"); Set candidateComponents = scanner.findCandidateComponents(basePackage); diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/DefaultAnnotatedRequestBeanIntrospector.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/DefaultAnnotatedRequestBeanIntrospector.java index c7d04b9..ac8f23c 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/DefaultAnnotatedRequestBeanIntrospector.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/DefaultAnnotatedRequestBeanIntrospector.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; import com.mattbertolini.spring.web.bind.AbstractPropertyResolverRegistry; @@ -21,7 +20,6 @@ import com.mattbertolini.spring.web.bind.resolver.RequestPropertyResolverBase; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; -import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import java.beans.PropertyDescriptor; @@ -39,7 +37,7 @@ public class DefaultAnnotatedRequestBeanIntrospector implements AnnotatedRequest private final AbstractPropertyResolverRegistry registry; - public DefaultAnnotatedRequestBeanIntrospector(@NonNull AbstractPropertyResolverRegistry registry) { + public DefaultAnnotatedRequestBeanIntrospector(AbstractPropertyResolverRegistry registry) { this.registry = registry; } @@ -52,18 +50,17 @@ public DefaultAnnotatedRequestBeanIntrospector(@NonNull AbstractPropertyResolver * @throws CircularReferenceException If a circular reference is found while traversing the object graph. */ @Override - @NonNull - public Map getResolverMapFor(@NonNull Class targetType) { + public Map getResolverMapFor(Class targetType) { Set> cycleClasses = new LinkedHashSet<>(); Map propertyData = new HashMap<>(); recursiveGetResolverMapFor(targetType, null, propertyData, cycleClasses); return Collections.unmodifiableMap(propertyData); } - private void recursiveGetResolverMapFor(@NonNull final Class targetType, + private void recursiveGetResolverMapFor(final Class targetType, @Nullable final String prefix, - @NonNull Map propertyData, - @NonNull final Set> cycleClasses) { + Map propertyData, + final Set> cycleClasses) { PropertyDescriptor[] propertyDescriptors; try { propertyDescriptors = BeanUtils.getPropertyDescriptors(targetType); @@ -102,7 +99,7 @@ private void recursiveGetResolverMapFor(@NonNull final Class targetType, * @param propertyDescriptor The property descriptor to find a name for. Required. * @return The full property name path */ - private String getPropertyName(@Nullable String prefix, @NonNull PropertyDescriptor propertyDescriptor) { + private String getPropertyName(@Nullable String prefix, PropertyDescriptor propertyDescriptor) { if (prefix == null) { return propertyDescriptor.getName(); } diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/RequestBeanIntrospectionException.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/RequestBeanIntrospectionException.java index e18a058..a12d284 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/RequestBeanIntrospectionException.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/RequestBeanIntrospectionException.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; public class RequestBeanIntrospectionException extends RuntimeException { diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/ResolvedPropertyData.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/ResolvedPropertyData.java index d2e236c..d9b84cb 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/ResolvedPropertyData.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/ResolvedPropertyData.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,60 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; import com.mattbertolini.spring.web.bind.resolver.RequestPropertyResolverBase; -import org.springframework.lang.NonNull; - -import java.util.Objects; - -public final class ResolvedPropertyData { - private final String propertyName; - private final BindingProperty bindingProperty; - private final RequestPropertyResolverBase resolver; - - public ResolvedPropertyData( - @NonNull String propertyName, - @NonNull BindingProperty bindingProperty, - @NonNull RequestPropertyResolverBase resolver - ) { - this.propertyName = propertyName; - this.bindingProperty = bindingProperty; - this.resolver = resolver; - } - - @NonNull - public String getPropertyName() { - return propertyName; - } - - @NonNull - public BindingProperty getBindingProperty() { - return bindingProperty; - } - - @NonNull - public RequestPropertyResolverBase getResolver() { - return resolver; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof ResolvedPropertyData)) { - return false; - } - ResolvedPropertyData that = (ResolvedPropertyData) o; - return Objects.equals(propertyName, that.propertyName) && - Objects.equals(bindingProperty, that.bindingProperty) && - Objects.equals(resolver, that.resolver); - } - @Override - public int hashCode() { - return Objects.hash(propertyName, bindingProperty, resolver); - } -} +public record ResolvedPropertyData( + String propertyName, + BindingProperty bindingProperty, + RequestPropertyResolverBase resolver) {} diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/package-info.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/package-info.java new file mode 100644 index 0000000..7023dc6 --- /dev/null +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/introspect/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.bind.introspect; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/package-info.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/package-info.java new file mode 100644 index 0000000..a2a7d09 --- /dev/null +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.bind; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/AbstractNamedRequestPropertyResolver.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/AbstractNamedRequestPropertyResolver.java index f66d9cd..ef681b9 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/AbstractNamedRequestPropertyResolver.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/AbstractNamedRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,21 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.resolver; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; -import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; public abstract class AbstractNamedRequestPropertyResolver implements RequestPropertyResolverBase { - @NonNull - protected abstract String getName(@NonNull BindingProperty bindingProperty); + protected abstract String getName(BindingProperty bindingProperty); @Override - public final R resolve(@NonNull BindingProperty bindingProperty, @NonNull T request) { + @Nullable + public final R resolve(BindingProperty bindingProperty, T request) { String name = getName(bindingProperty); return resolveWithName(bindingProperty, name, request); } - protected abstract R resolveWithName(@NonNull BindingProperty bindingProperty, String name, @NonNull T request); + @Nullable + protected abstract R resolveWithName(BindingProperty bindingProperty, String name, T request); } diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/RequestPropertyResolverBase.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/RequestPropertyResolverBase.java index 2dc977b..eff6e55 100644 --- a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/RequestPropertyResolverBase.java +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/RequestPropertyResolverBase.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,11 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.resolver; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; -import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; /** @@ -28,8 +26,8 @@ * @param The response type to use. */ public interface RequestPropertyResolverBase { - boolean supports(@NonNull BindingProperty bindingProperty); + boolean supports(BindingProperty bindingProperty); @Nullable - R resolve(@NonNull BindingProperty bindingProperty, @NonNull T request); + R resolve(BindingProperty bindingProperty, T request); } diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/package-info.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/package-info.java new file mode 100644 index 0000000..2ba5338 --- /dev/null +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/resolver/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.bind.resolver; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/support/MapValueResolver.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/support/MapValueResolver.java new file mode 100644 index 0000000..5e0376c --- /dev/null +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/support/MapValueResolver.java @@ -0,0 +1,46 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mattbertolini.spring.web.bind.support; + +import org.springframework.lang.Nullable; +import org.springframework.validation.DataBinder; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + * Implementation of the {@link DataBinder.ValueResolver} to assist in mapping binding data for constructor binding. + * + * @param values The Map of values to pass to the binder + */ +public record MapValueResolver(Map values) implements DataBinder.ValueResolver { + @Override + @Nullable + public Object resolveValue(String name, Class type) { + return values.get(name); + } + + @Override + public Set getNames() { + return Set.copyOf(values.keySet()); + } + + @Override + public Map values() { + return Collections.unmodifiableMap(values); + } +} diff --git a/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/support/package-info.java b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/support/package-info.java new file mode 100644 index 0000000..12ee672 --- /dev/null +++ b/spring-annotated-data-binder-core/src/main/java/com/mattbertolini/spring/web/bind/support/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.bind.support; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/AbstractPropertyResolverRegistryTest.java b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/AbstractPropertyResolverRegistryTest.java index 494e68e..bba94e6 100644 --- a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/AbstractPropertyResolverRegistryTest.java +++ b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/AbstractPropertyResolverRegistryTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import com.mattbertolini.spring.web.bind.resolver.RequestPropertyResolverBase; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import java.beans.PropertyDescriptor; import java.util.Collections; @@ -100,8 +100,10 @@ private static class TestingRegistry extends AbstractPropertyResolverRegistry resolvers = introspector.getResolversFor(SimpleType.class); assertThat(resolvers).hasSize(1); ResolvedPropertyData data = resolvers.iterator().next(); - assertThat(data.getPropertyName()).isEqualTo("data"); + assertThat(data.propertyName()).isEqualTo("data"); } @Test @@ -63,7 +62,7 @@ void returnsResolversUsingNestedTypes() { Collection resolvers = introspector.getResolversFor(OuterBean.class); assertThat(resolvers).hasSize(1); ResolvedPropertyData data = resolvers.iterator().next(); - assertThat(data.getPropertyName()).isEqualTo("innerBean.inner"); + assertThat(data.propertyName()).isEqualTo("innerBean.inner"); } private static class FakeResolver implements RequestPropertyResolverBase { @@ -74,12 +73,13 @@ public FakeResolver(Class annotationType) { } @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { return bindingProperty.hasAnnotation(annotationType); } @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull Void request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, Void request) { // Don't need to worry about this method. No used in the introspector. return null; } @@ -93,9 +93,11 @@ public FakeRegistry() { @SuppressWarnings("unused") private static class SimpleType { + @Nullable @RequestParameter("data_param") private String data; + @Nullable public String getData() { return data; } @@ -107,9 +109,11 @@ public void setData(String data) { @SuppressWarnings("unused") private static class OuterBean { + @Nullable @BeanParameter private InnerBean innerBean; + @Nullable public InnerBean getInnerBean() { return innerBean; } @@ -121,9 +125,11 @@ public void setInnerBean(InnerBean innerBean) { @SuppressWarnings("unused") private static class InnerBean { + @Nullable @RequestParameter("inner_param") private String inner; + @Nullable public String getInner() { return inner; } @@ -135,9 +141,11 @@ public void setInner(String inner) { @SuppressWarnings("unused") private static class CircularReference { + @Nullable @BeanParameter private CircularReference circularReference; + @Nullable public CircularReference getCircularReference() { return circularReference; } diff --git a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/ResolvedPropertyDataTest.java b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/ResolvedPropertyDataTest.java index 78a7f32..f6737ea 100644 --- a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/ResolvedPropertyDataTest.java +++ b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/ResolvedPropertyDataTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect; import com.mattbertolini.spring.web.bind.resolver.RequestPropertyResolverBase; @@ -21,7 +20,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.core.convert.TypeDescriptor; -import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import java.beans.PropertyDescriptor; @@ -40,20 +39,20 @@ void setUp() throws Exception { @Test void returnsPropertyName() { - assertThat(propertyData.getPropertyName()).isEqualTo("name"); + assertThat(propertyData.propertyName()).isEqualTo("name"); } @Test void returnsBindingProperty() throws Exception { BindingProperty expected = BindingProperty.forPropertyDescriptor( new PropertyDescriptor("property", TestingClass.class)); - assertThat(propertyData.getBindingProperty()).isEqualTo(expected); + assertThat(propertyData.bindingProperty()).isEqualTo(expected); } @Test void returnsResolver() { - assertThat(propertyData.getResolver()).isNotNull(); - assertThat(propertyData.getResolver()).isInstanceOf(StubResolver.class); + assertThat(propertyData.resolver()).isNotNull(); + assertThat(propertyData.resolver()).isInstanceOf(StubResolver.class); } @Test @@ -69,22 +68,26 @@ void equalsContract() throws Exception { private static class StubResolver implements RequestPropertyResolverBase { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { return false; } @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull Object request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, Object request) { return null; } } @SuppressWarnings("unused") private static class TestingClass { + @Nullable private String property; + @Nullable private String another; + @Nullable public String getProperty() { return property; } @@ -93,6 +96,7 @@ public void setProperty(String property) { this.property = property; } + @Nullable public String getAnother() { return another; } diff --git a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/IgnoredBean.java b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/IgnoredBean.java index 13fc9d6..9218dad 100644 --- a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/IgnoredBean.java +++ b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/IgnoredBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect.scan; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; +import org.springframework.lang.Nullable; public class IgnoredBean { @RequestParameter("property") + @Nullable private String property; + @Nullable public String getProperty() { return property; } diff --git a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/ScannedBean.java b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/ScannedBean.java index e7092f2..cf0b629 100644 --- a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/ScannedBean.java +++ b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/ScannedBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect.scan; import com.mattbertolini.spring.web.bind.annotation.RequestBean; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; +import org.springframework.lang.Nullable; @RequestBean public class ScannedBean { @RequestParameter("property") + @Nullable private String property; + @Nullable public String getProperty() { return property; } diff --git a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/subbackage/SubpackageBean.java b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/subbackage/SubpackageBean.java index 5b958a7..923c95e 100644 --- a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/subbackage/SubpackageBean.java +++ b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/introspect/scan/subbackage/SubpackageBean.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.introspect.scan.subbackage; import com.mattbertolini.spring.web.bind.annotation.FormParameter; import com.mattbertolini.spring.web.bind.annotation.RequestBean; +import org.springframework.lang.Nullable; @RequestBean public class SubpackageBean { @FormParameter("subpackage_property") + @Nullable private String subpackageProperty; + @Nullable public String getSubpackageProperty() { return subpackageProperty; } diff --git a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/resolver/AbstractNamedRequestPropertyResolverTest.java b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/resolver/AbstractNamedRequestPropertyResolverTest.java index eef0b9a..69be429 100644 --- a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/resolver/AbstractNamedRequestPropertyResolverTest.java +++ b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/resolver/AbstractNamedRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.bind.resolver; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.Test; import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import java.beans.PropertyDescriptor; @@ -62,8 +62,10 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { @SuppressWarnings("unused") private static class TestingBean { + @Nullable private String property; + @Nullable public String getProperty() { return property; } diff --git a/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/support/MapValueResolverTest.java b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/support/MapValueResolverTest.java new file mode 100644 index 0000000..61811c1 --- /dev/null +++ b/spring-annotated-data-binder-core/src/test/java/com/mattbertolini/spring/web/bind/support/MapValueResolverTest.java @@ -0,0 +1,32 @@ +package com.mattbertolini.spring.web.bind.support; + +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class MapValueResolverTest { + @Test + void resolveValueReturnsMapValueFromKey() { + Map map = Map.of("key1", "value1", "key2", "value2"); + MapValueResolver valueResolver = new MapValueResolver(map); + assertThat(valueResolver.resolveValue("key1", String.class)).isEqualTo("value1"); + } + + @Test + void getNamesReturnsMapKeys() { + Map map = Map.of("key1", "value1", "key2", "value2"); + MapValueResolver valueResolver = new MapValueResolver(map); + assertThat(valueResolver.getNames()).contains("key1", "key2"); + } + + @Test + void valuesAccessorIsUnmodifiable() { + Map map = Map.of("key1", "value1", "key2", "value2"); + MapValueResolver valueResolver = new MapValueResolver(map); + assertThat(valueResolver.values()) + .isUnmodifiable() + .isEqualTo(map); + } +} diff --git a/spring-webflux-annotated-data-binder/build.gradle.kts b/spring-webflux-annotated-data-binder/build.gradle.kts index d8a8c28..8848608 100644 --- a/spring-webflux-annotated-data-binder/build.gradle.kts +++ b/spring-webflux-annotated-data-binder/build.gradle.kts @@ -12,7 +12,7 @@ dependencies { testImplementation(libs.assertJCore) testImplementation(libs.mockitoCore) testImplementation(libs.springTest) - testImplementation(libs.javaxValidationApi) // Used to test validation annotations + testImplementation(libs.jakartaValidationApi) // Used to test validation annotations testCompileOnly(libs.findbugsJsr305) // To Prevent warnings on missing enum constants } diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/BeanParameterMethodArgumentResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/BeanParameterMethodArgumentResolver.java index 9a7cbea..bdcc049 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/BeanParameterMethodArgumentResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/BeanParameterMethodArgumentResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind; import com.mattbertolini.spring.web.bind.RequestPropertyBindingException; @@ -21,17 +20,15 @@ import com.mattbertolini.spring.web.bind.introspect.AnnotatedRequestBeanIntrospector; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import com.mattbertolini.spring.web.bind.introspect.ResolvedPropertyData; +import com.mattbertolini.spring.web.bind.support.MapValueResolver; import com.mattbertolini.spring.web.reactive.bind.resolver.RequestPropertyResolver; import org.springframework.beans.BeanUtils; import org.springframework.beans.MutablePropertyValues; import org.springframework.core.MethodParameter; -import org.springframework.core.ReactiveAdapter; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ResolvableType; import org.springframework.lang.NonNull; -import org.springframework.util.Assert; import org.springframework.web.bind.support.WebExchangeDataBinder; -import org.springframework.web.reactive.BindingContext; import org.springframework.web.reactive.result.method.annotation.ModelAttributeMethodArgumentResolver; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; @@ -44,68 +41,46 @@ import java.util.Objects; public class BeanParameterMethodArgumentResolver extends ModelAttributeMethodArgumentResolver { - private static final String INTROSPECTOR_RESOLVABLE_TYPE = BeanParameterMethodArgumentResolver.class.getName() - + ".INTROSPECTOR_RESOLVABLE_TYPE"; - private final AnnotatedRequestBeanIntrospector introspector; public BeanParameterMethodArgumentResolver( - @NonNull ReactiveAdapterRegistry adapterRegistry, - @NonNull AnnotatedRequestBeanIntrospector introspector) { + ReactiveAdapterRegistry adapterRegistry, + AnnotatedRequestBeanIntrospector introspector) { super(adapterRegistry, false); this.introspector = introspector; } @Override - public boolean supportsParameter(@NonNull MethodParameter parameter) { + public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(BeanParameter.class) && !BeanUtils.isSimpleProperty(parameter.getParameterType()); } @Override - @NonNull - public Mono resolveArgument(@NonNull MethodParameter parameter, @NonNull BindingContext context, ServerWebExchange exchange) { - try { - ResolvableType type = ResolvableType.forMethodParameter(parameter); - Class resolvedType = type.resolve(); - ReactiveAdapter adapter = (resolvedType != null ? getAdapterRegistry().getAdapter(resolvedType) : null); - ResolvableType valueType = (adapter != null ? type.getGeneric() : type); - exchange.getAttributes().put(INTROSPECTOR_RESOLVABLE_TYPE, valueType); - return super.resolveArgument(parameter, context, exchange); - } finally { - exchange.getAttributes().remove(INTROSPECTOR_RESOLVABLE_TYPE); - } + protected Mono constructAttribute(WebExchangeDataBinder binder, ServerWebExchange exchange) { + ResolvableType targetType = Objects.requireNonNull(binder.getTargetType(), "WebExchangeDataBinder must have a target type"); + Collection propertyData = introspector.getResolversFor(Objects.requireNonNull(targetType.getRawClass())); + return getValuesToBind(propertyData, exchange) + .map(MapValueResolver::new) + .doOnNext(binder::construct) + .then(); } @Override @NonNull - protected Mono bindRequestParameters(@NonNull WebExchangeDataBinder binder, @NonNull ServerWebExchange exchange) { - Assert.state(binder.getTarget() != null, "WebExchangeDataBinder must have a target object"); - Collection propertyData = introspector.getResolversFor(binder.getTarget().getClass()); + protected Mono bindRequestParameters(WebExchangeDataBinder binder, ServerWebExchange exchange) { + Object target = Objects.requireNonNull(binder.getTarget(), "WebExchangeDataBinder must have a target object"); + Collection propertyData = introspector.getResolversFor(target.getClass()); return getValuesToBind(propertyData, exchange) .map(MutablePropertyValues::new) .doOnNext(binder::bind) .then(); } - @Override - @NonNull - public Mono> getValuesToBind(@NonNull WebExchangeDataBinder binder, ServerWebExchange exchange) { - ResolvableType resolvableType = exchange.getAttribute(INTROSPECTOR_RESOLVABLE_TYPE); - if (resolvableType == null) { - return super.getValuesToBind(binder, exchange); - } - Class type = resolvableType.resolve(); - Assert.notNull(type, "The resolved type must not be null"); - Collection propertyData = introspector.getResolversFor(type); - return getValuesToBind(propertyData, exchange); - } - - @NonNull - private Mono> getValuesToBind(@NonNull Collection propertyData, @NonNull ServerWebExchange exchange) { + private Mono> getValuesToBind(Collection propertyData, ServerWebExchange exchange) { return Flux.fromIterable(propertyData).flatMap(data -> { - BindingProperty bindingProperty = data.getBindingProperty(); - RequestPropertyResolver resolver = (RequestPropertyResolver) data.getResolver(); - return resolver.resolve(bindingProperty, exchange).map(resolvedValue -> Tuples.of(data.getPropertyName(), resolvedValue)); + BindingProperty bindingProperty = data.bindingProperty(); + RequestPropertyResolver resolver = (RequestPropertyResolver) data.resolver(); + return resolver.resolve(bindingProperty, exchange).map(resolvedValue -> Tuples.of(data.propertyName(), resolvedValue)); }).collectMap(Tuple2::getT1, Tuple2::getT2) .onErrorMap(e -> new RequestPropertyBindingException("Unable to resolve property. " + e.getMessage(), e)) .doOnSuccess(valuesMap -> valuesMap.values().removeIf(Objects::isNull)); diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/PropertyResolverRegistry.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/PropertyResolverRegistry.java index 2397d9f..ece6eeb 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/PropertyResolverRegistry.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/PropertyResolverRegistry.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind; import com.mattbertolini.spring.web.bind.AbstractPropertyResolverRegistry; diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/config/BinderConfiguration.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/config/BinderConfiguration.java index 95df482..6541780 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/config/BinderConfiguration.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/config/BinderConfiguration.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.config; import com.mattbertolini.spring.web.bind.introspect.AnnotatedRequestBeanIntrospector; @@ -37,12 +36,12 @@ import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.ReactiveAdapterRegistry; -import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; import java.util.Collections; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.Set; /** @@ -66,8 +65,8 @@ public BinderConfiguration() { * * @param propertyResolverRegistry The resolver registry to use. */ - public BinderConfiguration(@NonNull PropertyResolverRegistry propertyResolverRegistry) { - packagesToScan = new LinkedHashSet<>(); + public BinderConfiguration(PropertyResolverRegistry propertyResolverRegistry) { + packagesToScan = new HashSet<>(); this.propertyResolverRegistry = propertyResolverRegistry; } @@ -116,7 +115,7 @@ public BinderConfiguration addResolvers(Set resolvers) } /** - * Add all of the resolvers from the given registry into this registry. + * Add all the resolvers from the given registry into this registry. * * @param propertyResolverRegistry The registry to add resolvers from. Required. * @return This instance of the configuration. @@ -136,12 +135,12 @@ public Set getPackagesToScan() { } @Override - public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) { - if (!(bean instanceof RequestMappingHandlerAdapter)) { + @Nullable + public Object postProcessBeforeInitialization(Object bean, String beanName) { + if (!(bean instanceof RequestMappingHandlerAdapter adapter)) { return bean; } - RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean; ArgumentResolverConfigurer resolverConfigurer = adapter.getArgumentResolverConfigurer(); if (resolverConfigurer != null) { ReactiveAdapterRegistry reactiveAdapterRegistry = adapter.getReactiveAdapterRegistry(); @@ -157,7 +156,7 @@ public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull Str } return adapter; } - + private PropertyResolverRegistry createPropertyResolverRegistry(RequestMappingHandlerAdapter adapter, ReactiveAdapterRegistry reactiveAdapterRegistry) { PropertyResolverRegistry registry = new PropertyResolverRegistry(); diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/config/package-info.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/config/package-info.java new file mode 100644 index 0000000..f2c7acc --- /dev/null +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/config/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.reactive.bind.config; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/package-info.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/package-info.java new file mode 100644 index 0000000..5e8825f --- /dev/null +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.reactive.bind; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/CookieParameterRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/CookieParameterRequestPropertyResolver.java index dd2b40d..71f7cfc 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/CookieParameterRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/CookieParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,30 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.CookieParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.springframework.http.HttpCookie; import org.springframework.lang.NonNull; -import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import java.util.Objects; + public class CookieParameterRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { return bindingProperty.hasAnnotation(CookieParameter.class); } @NonNull @Override - public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange exchange) { + public Mono resolve(BindingProperty bindingProperty, ServerWebExchange exchange) { MultiValueMap cookies = exchange.getRequest().getCookies(); CookieParameter annotation = bindingProperty.getAnnotation(CookieParameter.class); - Assert.state(annotation != null, "No CookieParameter annotation found on type"); + Objects.requireNonNull(annotation, "No CookieParameter annotation found on type"); HttpCookie cookie = cookies.getFirst(annotation.value()); if (HttpCookie.class.isAssignableFrom(bindingProperty.getType())) { return Mono.justOrEmpty(cookie); diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterMapRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterMapRequestPropertyResolver.java index ac94982..b9b0e28 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterMapRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterMapRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.FormParameter; @@ -29,7 +28,7 @@ public class FormParameterMapRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { FormParameter annotation = bindingProperty.getAnnotation(FormParameter.class); return annotation != null && !StringUtils.hasText(annotation.value()) && Map.class.isAssignableFrom(bindingProperty.getType()); @@ -37,7 +36,7 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { @Override @NonNull - public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange exchange) { + public Mono resolve(BindingProperty bindingProperty, ServerWebExchange exchange) { if (MultiValueMap.class.isAssignableFrom(bindingProperty.getType())) { return exchange.getFormData().map(Function.identity()); } diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterRequestPropertyResolver.java index 749da08..ab011e2 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.FormParameter; @@ -21,26 +20,25 @@ import org.springframework.http.codec.multipart.FormFieldPart; import org.springframework.http.codec.multipart.Part; import org.springframework.lang.NonNull; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.util.List; -import java.util.stream.Collectors; +import java.util.Objects; public class FormParameterRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { FormParameter annotation = bindingProperty.getAnnotation(FormParameter.class); return annotation != null && StringUtils.hasText(annotation.value()); } @NonNull @Override - public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange exchange) { + public Mono resolve(BindingProperty bindingProperty, ServerWebExchange exchange) { FormParameter annotation = bindingProperty.getAnnotation(FormParameter.class); - Assert.state(annotation != null, "No FormParameter annotation found on type"); + Objects.requireNonNull(annotation, "No FormParameter annotation found on type"); return exchange.getMultipartData() .filter(multipartData -> multipartData.getFirst(annotation.value()) != null) .map(multipartData -> multipartData.get(annotation.value())) @@ -53,8 +51,8 @@ public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull S @NonNull private Object getPartValues(@NonNull List parts) { List values = parts.stream() - .map(value -> value instanceof FormFieldPart ? ((FormFieldPart) value).value() : value) - .collect(Collectors.toList()); + .map(value -> value instanceof FormFieldPart formFieldPart ? formFieldPart.value() : value) + .toList(); return values.size() == 1 ? values.get(0) : values; } } diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterMapRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterMapRequestPropertyResolver.java index 42f3c47..c88f8f2 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterMapRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterMapRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; @@ -28,7 +27,7 @@ public class HeaderParameterMapRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { HeaderParameter annotation = bindingProperty.getAnnotation(HeaderParameter.class); return annotation != null && !StringUtils.hasText(annotation.value()) && Map.class.isAssignableFrom(bindingProperty.getType()); @@ -36,7 +35,7 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { @Override @NonNull - public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange exchange) { + public Mono resolve(BindingProperty bindingProperty, ServerWebExchange exchange) { // HttpHeaders class extends from MultiValueMap if (MultiValueMap.class.isAssignableFrom(bindingProperty.getType())) { return Mono.just(exchange.getRequest().getHeaders()); diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterRequestPropertyResolver.java index 4d80411..4bc6e14 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.springframework.http.HttpHeaders; import org.springframework.lang.NonNull; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import java.util.Objects; + public class HeaderParameterRequestPropertyResolver implements RequestPropertyResolver { @Override public boolean supports(@NonNull BindingProperty bindingProperty) { @@ -34,10 +34,10 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { @Override @NonNull - public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange request) { + public Mono resolve(BindingProperty bindingProperty, ServerWebExchange request) { HttpHeaders headers = request.getRequest().getHeaders(); HeaderParameter annotation = bindingProperty.getAnnotation(HeaderParameter.class); - Assert.state(annotation != null, "No HeaderParameter annotation found on type"); + Objects.requireNonNull(annotation, "No HeaderParameter annotation found on type"); return Mono.justOrEmpty(headers.get(annotation.value())); } } diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterMapRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterMapRequestPropertyResolver.java index a9c8f0d..f7dddd9 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterMapRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterMapRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.PathParameter; diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterRequestPropertyResolver.java index fc8ff2e..a657da7 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.PathParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.springframework.lang.NonNull; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.server.ServerWebExchange; @@ -27,6 +25,7 @@ import java.util.Collections; import java.util.Map; +import java.util.Objects; public class PathParameterRequestPropertyResolver implements RequestPropertyResolver { @Override @@ -39,7 +38,7 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { @Override public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange exchange) { PathParameter annotation = bindingProperty.getAnnotation(PathParameter.class); - Assert.state(annotation != null, "No PathParameter annotation found on type"); + Objects.requireNonNull(annotation, "No PathParameter annotation found on type"); Map pathVariables = exchange.getAttributeOrDefault(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, Collections.emptyMap()); return Mono.justOrEmpty(pathVariables.get(annotation.value())); } diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestBodyRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestBodyRequestPropertyResolver.java index dbf7617..06d5c9c 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestBodyRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestBodyRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestBody; @@ -45,7 +44,6 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { return bindingProperty.hasAnnotation(RequestBody.class); } - @NonNull @Override public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange request) { diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestContextRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestContextRequestPropertyResolver.java index affd9a1..2397406 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestContextRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestContextRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestContext; @@ -80,8 +79,7 @@ public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull S @Nullable private TimeZone getTimeZone(@NonNull ServerWebExchange exchange) { LocaleContext localeContext = exchange.getLocaleContext(); - if (localeContext instanceof TimeZoneAwareLocaleContext) { - TimeZoneAwareLocaleContext timeZoneAwareLocaleContext = (TimeZoneAwareLocaleContext) localeContext; + if (localeContext instanceof TimeZoneAwareLocaleContext timeZoneAwareLocaleContext) { return timeZoneAwareLocaleContext.getTimeZone(); } return null; diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterMapRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterMapRequestPropertyResolver.java index c335158..ccfc0df 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterMapRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterMapRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterRequestPropertyResolver.java index d56bca2..4d340c5 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.springframework.lang.NonNull; -import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import java.util.Objects; + public class RequestParameterRequestPropertyResolver implements RequestPropertyResolver { @Override public boolean supports(@NonNull BindingProperty bindingProperty) { @@ -36,7 +36,7 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { @Override public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange serverWebExchange) { RequestParameter annotation = bindingProperty.getAnnotation(RequestParameter.class); - Assert.state(annotation != null, "No RequestParameter annotation found on type"); + Objects.requireNonNull(annotation, "No RequestParameter annotation found on type"); MultiValueMap queryParams = serverWebExchange.getRequest().getQueryParams(); return Mono.justOrEmpty(queryParams.get(annotation.value())); } diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestPropertyResolver.java index ad9e7a3..5d47ea0 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; @@ -27,6 +26,6 @@ */ public interface RequestPropertyResolver extends RequestPropertyResolverBase> { @Override - @NonNull - Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange request); + @NonNull // Explicitly setting NonNull as we are overriding a Nullable parent method + Mono resolve(BindingProperty bindingProperty, ServerWebExchange request); } diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/SessionParameterRequestPropertyResolver.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/SessionParameterRequestPropertyResolver.java index 0f97f5d..998826d 100644 --- a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/SessionParameterRequestPropertyResolver.java +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/SessionParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,30 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.springframework.lang.NonNull; -import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import java.util.Objects; + public class SessionParameterRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { return bindingProperty.hasAnnotation(SessionParameter.class); } @NonNull @Override - public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange exchange) { + public Mono resolve(BindingProperty bindingProperty, ServerWebExchange exchange) { SessionParameter annotation = bindingProperty.getAnnotation(SessionParameter.class); - Assert.state(annotation != null, "No SessionParameter annotation found on type"); - //noinspection ReactiveStreamsNullableInLambdaInTransform + Objects.requireNonNull(annotation, "No SessionParameter annotation found on type"); return exchange.getSession() .filter(session -> session.getAttribute(annotation.value()) != null) - .map(session -> session.getAttribute(annotation.value())); + .mapNotNull(session -> session.getAttribute(annotation.value())); } } diff --git a/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/package-info.java b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/package-info.java new file mode 100644 index 0000000..fecab4b --- /dev/null +++ b/spring-webflux-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/reactive/bind/resolver/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.reactive.bind.resolver; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/BeanParameterMethodArgumentResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/BeanParameterMethodArgumentResolverTest.java index 6753a09..02fdcde 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/BeanParameterMethodArgumentResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/BeanParameterMethodArgumentResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind; import com.mattbertolini.spring.web.bind.RequestPropertyBindingException; @@ -22,27 +21,23 @@ import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import com.mattbertolini.spring.web.bind.introspect.ResolvedPropertyData; import com.mattbertolini.spring.web.reactive.bind.resolver.RequestPropertyResolver; +import jakarta.validation.Valid; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.PropertyValue; import org.springframework.beans.PropertyValues; import org.springframework.core.MethodParameter; import org.springframework.core.ReactiveAdapterRegistry; -import org.springframework.format.support.FormattingConversionServiceFactoryBean; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; -import org.springframework.validation.support.BindingAwareConcurrentModel; import org.springframework.web.bind.support.WebExchangeBindException; -import org.springframework.web.bind.support.WebExchangeDataBinder; -import org.springframework.web.reactive.BindingContext; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; -import javax.validation.Valid; import java.beans.PropertyDescriptor; import java.util.Arrays; import java.util.List; @@ -51,9 +46,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.catchThrowableOfType; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -62,15 +54,14 @@ class BeanParameterMethodArgumentResolverTest { private ServerWebExchange exchange; private AnnotatedRequestBeanIntrospector introspector; - private BindingContext bindingContext; + private MockBindingContext bindingContext; @BeforeEach void setUp() { MockServerHttpRequest request = MockServerHttpRequest.get("/irrelevant").build(); exchange = MockServerWebExchange.from(request); introspector = mock(AnnotatedRequestBeanIntrospector.class); - bindingContext = mock(BindingContext.class); - when(bindingContext.getModel()).thenReturn(new BindingAwareConcurrentModel()); + bindingContext = new MockBindingContext(); ReactiveAdapterRegistry registry = new ReactiveAdapterRegistry(); resolver = new BeanParameterMethodArgumentResolver(registry, introspector); } @@ -105,14 +96,11 @@ void resolvesPropertyValues() throws Exception { MethodParameter methodParameter = createMethodParameter("anAnnotatedMethod", ABeanClass.class); - StubWebExchangeDataBinder dataBinder = new StubWebExchangeDataBinder(new ABeanClass()); - when(bindingContext.createDataBinder(eq(exchange), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - when(introspector.getResolversFor(ABeanClass.class)).thenReturn(propertyData); Mono objectMono = resolver.resolveArgument(methodParameter, bindingContext, exchange); objectMono.block(); - PropertyValues propertyValues = dataBinder.getPropertyValues(); + PropertyValues propertyValues = bindingContext.getDataBinder().getPropertyValues(); assertThat(propertyValues.contains("propertyOne")).isTrue(); assertThat(propertyValues.contains("propertyTwo")).isTrue(); @@ -133,14 +121,11 @@ void resolvesOnlyFoundPropertyValues() throws Exception { MethodParameter methodParameter = createMethodParameter("anAnnotatedMethod", ABeanClass.class); - StubWebExchangeDataBinder dataBinder = new StubWebExchangeDataBinder(new ABeanClass()); - when(bindingContext.createDataBinder(eq(exchange), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - when(introspector.getResolversFor(ABeanClass.class)).thenReturn(propertyData); Mono objectMono = resolver.resolveArgument(methodParameter, bindingContext, exchange); objectMono.block(); - PropertyValues propertyValues = dataBinder.getPropertyValues(); + PropertyValues propertyValues = bindingContext.getDataBinder().getPropertyValues(); assertThat(propertyValues.contains("propertyOne")).isFalse(); assertThat(propertyValues.contains("propertyTwo")).isTrue(); @@ -173,7 +158,6 @@ void throwsExceptionWhenResolverErrors() throws Exception { MethodParameter methodParameter = createMethodParameter("anAnnotatedMethod", ABeanClass.class); - when(bindingContext.createDataBinder(eq(exchange), any(ABeanClass.class), anyString())).thenReturn(new StubWebExchangeDataBinder(new ABeanClass())); when(introspector.getResolversFor(ABeanClass.class)).thenReturn(propertyData); Mono objectMono = resolver.resolveArgument(methodParameter, bindingContext, exchange); assertThatThrownBy(objectMono::block).isInstanceOf(RequestPropertyBindingException.class); @@ -183,38 +167,30 @@ void throwsExceptionWhenResolverErrors() throws Exception { void validatesWhenValidAnnotationPresent() throws Exception { MethodParameter methodParameter = createMethodParameter("aValidMethod", ABeanClass.class); - StubWebExchangeDataBinder dataBinder = new StubWebExchangeDataBinder(new ABeanClass()); - when(bindingContext.createDataBinder(eq(exchange), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - Mono objectMono = resolver.resolveArgument(methodParameter, bindingContext, exchange); objectMono.block(); - assertThat(dataBinder.isValidateInvoked()).isTrue(); + assertThat(bindingContext.getDataBinder().isValidateInvoked()).isTrue(); } @Test void validatesWhenValidatedAnnotationPresent() throws Exception { MethodParameter methodParameter = createMethodParameter("aValidatedMethod", ABeanClass.class); - StubWebExchangeDataBinder dataBinder = new StubWebExchangeDataBinder(new ABeanClass()); - when(bindingContext.createDataBinder(eq(exchange), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - Mono objectMono = resolver.resolveArgument(methodParameter, bindingContext, exchange); objectMono.block(); - assertThat(dataBinder.isValidateInvoked()).isTrue(); + assertThat(bindingContext.getDataBinder().isValidateInvoked()).isTrue(); } @Test void validatesWithGroups() throws Exception { MethodParameter methodParameter = createMethodParameter("validationGroups", ABeanClass.class); - StubWebExchangeDataBinder dataBinder = new StubWebExchangeDataBinder(new ABeanClass()); - when(bindingContext.createDataBinder(eq(exchange), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - Mono objectMono = resolver.resolveArgument(methodParameter, bindingContext, exchange); objectMono.block(); + MockWebExchangeDataBinder dataBinder = bindingContext.getDataBinder(); assertThat(dataBinder.isValidateInvoked()).isTrue(); assertThat(dataBinder.getValidationHints()).contains(ValidationGroupOne.class, ValidationGroupTwo.class); } @@ -226,9 +202,7 @@ void validationThrowsBindException() throws Exception { BindingResult bindingResult = mock(BindingResult.class); when(bindingResult.hasErrors()).thenReturn(true); - StubWebExchangeDataBinder dataBinder = new StubWebExchangeDataBinder(new ABeanClass()); - dataBinder.setBindingResult(bindingResult); - when(bindingContext.createDataBinder(eq(exchange), any(ABeanClass.class), anyString())).thenReturn(dataBinder); + bindingContext.setBindingResult(bindingResult); Mono objectMono = resolver.resolveArgument(methodParameter, bindingContext, exchange); WebExchangeBindException exception = catchThrowableOfType(objectMono::block, WebExchangeBindException.class); @@ -240,84 +214,27 @@ void validationHasErrorsWithBindingResultMethodParameter() throws Exception { MethodParameter methodParameter = createMethodParameter("withBindingResult", ABeanClass.class, BindingResult.class); BindingResult bindingResult = mock(BindingResult.class); - when(bindingResult.hasErrors()).thenReturn(true); + when(bindingResult.hasErrors()) + .thenReturn(false) + .thenReturn(false) + .thenReturn(true); - StubWebExchangeDataBinder dataBinder = new StubWebExchangeDataBinder(new ABeanClass()); - dataBinder.setBindingResult(bindingResult); - when(bindingContext.createDataBinder(eq(exchange), any(ABeanClass.class), anyString())).thenReturn(dataBinder); + bindingContext.setBindingResult(bindingResult); Mono objectMono = resolver.resolveArgument(methodParameter, bindingContext, exchange); objectMono.block(); - assertThat(dataBinder.getBindingResult()).isEqualTo(bindingResult); + assertThat(bindingContext.getDataBinder().getBindingResult()).isEqualTo(bindingResult); } private MethodParameter createMethodParameter(String anAnnotatedMethod, Class... parameterTypes) throws NoSuchMethodException { return new MethodParameter(FakeHandlerMethod.class.getMethod(anAnnotatedMethod, parameterTypes), 0); } - private static class StubWebExchangeDataBinder extends WebExchangeDataBinder { - private boolean bindInvoked = false; - private boolean validateInvoked = true; - private PropertyValues pvs; - private List validationHints; - private BindingResult bindingResult; - - public StubWebExchangeDataBinder(Object target) { - super(target); - FormattingConversionServiceFactoryBean conversionServiceFactoryBean = new FormattingConversionServiceFactoryBean(); - conversionServiceFactoryBean.afterPropertiesSet(); - setConversionService(conversionServiceFactoryBean.getObject()); - } - - @Override - public void bind(PropertyValues pvs) { - this.pvs = pvs; - bindInvoked = true; - } - - @Override - public void validate() { - validateInvoked = true; - } - - @Override - public void validate(Object... validationHints) { - this.validationHints = Arrays.asList(validationHints); - validateInvoked = true; - } - - @Override - public BindingResult getBindingResult() { - if (bindingResult == null) { - return super.getBindingResult(); - } - return bindingResult; - } - - public void setBindingResult(BindingResult bindingResult) { - this.bindingResult = bindingResult; - } - - public boolean isBindInvoked() { - return bindInvoked; - } - - public boolean isValidateInvoked() { - return validateInvoked; - } - - public List getValidationHints() { - return validationHints; - } - - public PropertyValues getPropertyValues() { - return pvs; - } - } - private static class MockRequestPropertyResolver implements RequestPropertyResolver { + @Nullable private final Object value; + @Nullable private final RuntimeException exception; private MockRequestPropertyResolver(@Nullable T value, @Nullable RuntimeException exception) { @@ -326,14 +243,14 @@ private MockRequestPropertyResolver(@Nullable T value, @Nullable RuntimeExce } @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { // Not used in this test return true; } @NonNull @Override - public Mono resolve(@NonNull BindingProperty bindingProperty, @NonNull ServerWebExchange exchange) { + public Mono resolve(BindingProperty bindingProperty, ServerWebExchange exchange) { if (exception != null) { throw exception; } @@ -389,11 +306,15 @@ public void withBindingResult(@BeanParameter @Validated ABeanClass aBeanClass, B } } + @SuppressWarnings("unused") private static class ABeanClass { + @Nullable private String propertyOne; + @Nullable private Integer propertyTwo; + @Nullable public String getPropertyOne() { return propertyOne; } @@ -402,6 +323,7 @@ public void setPropertyOne(String propertyOne) { this.propertyOne = propertyOne; } + @Nullable public Integer getPropertyTwo() { return propertyTwo; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/MockBindingContext.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/MockBindingContext.java new file mode 100644 index 0000000..45c9d1e --- /dev/null +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/MockBindingContext.java @@ -0,0 +1,83 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mattbertolini.spring.web.reactive.bind; + +import com.uber.nullaway.annotations.Initializer; +import org.springframework.core.ResolvableType; +import org.springframework.format.support.FormattingConversionServiceFactoryBean; +import org.springframework.lang.Nullable; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.validation.support.BindingAwareConcurrentModel; +import org.springframework.web.bind.support.WebExchangeDataBinder; +import org.springframework.web.reactive.BindingContext; +import org.springframework.web.server.ServerWebExchange; + +public class MockBindingContext extends BindingContext { + private final BindingAwareConcurrentModel model = new BindingAwareConcurrentModel(); + private MockWebExchangeDataBinder dataBinder; + @Nullable + private BindingResult bindingResult; + + @Override + @Initializer + public WebExchangeDataBinder createDataBinder(ServerWebExchange exchange, @Nullable Object target, String name) { + dataBinder = new MockWebExchangeDataBinder(target); + + if (bindingResult != null) { + dataBinder.setBindingResult(bindingResult); + } + + FormattingConversionServiceFactoryBean conversionServiceFactoryBean = new FormattingConversionServiceFactoryBean(); + conversionServiceFactoryBean.afterPropertiesSet(); + dataBinder.setConversionService(conversionServiceFactoryBean.getObject()); + + return dataBinder; + } + + @Override + @Initializer + public WebExchangeDataBinder createDataBinder(ServerWebExchange exchange, @Nullable Object target, String name, ResolvableType targetType) { + dataBinder = new MockWebExchangeDataBinder(target); + + if (target == null) { + dataBinder.setTargetType(targetType); + } + + if (bindingResult != null) { + dataBinder.setBindingResult(bindingResult); + } + + FormattingConversionServiceFactoryBean conversionServiceFactoryBean = new FormattingConversionServiceFactoryBean(); + conversionServiceFactoryBean.afterPropertiesSet(); + dataBinder.setConversionService(conversionServiceFactoryBean.getObject()); + + return dataBinder; + } + + @Override + public Model getModel() { + return model; + } + + public MockWebExchangeDataBinder getDataBinder() { + return dataBinder; + } + + public void setBindingResult(BindingResult bindingResult) { + this.bindingResult = bindingResult; + } +} diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/MockWebExchangeDataBinder.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/MockWebExchangeDataBinder.java new file mode 100644 index 0000000..e706ec2 --- /dev/null +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/MockWebExchangeDataBinder.java @@ -0,0 +1,86 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mattbertolini.spring.web.reactive.bind; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValues; +import org.springframework.lang.Nullable; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.support.WebExchangeDataBinder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MockWebExchangeDataBinder extends WebExchangeDataBinder { + private boolean bindInvoked = false; + private boolean validateInvoked = true; + private PropertyValues pvs; + private List validationHints; + @Nullable + private BindingResult bindingResult; + + public MockWebExchangeDataBinder(@Nullable Object target) { + super(target); + pvs = new MutablePropertyValues(); + validationHints = new ArrayList<>(); + } + + @Override + public void bind(PropertyValues pvs) { + this.pvs = pvs; + bindInvoked = true; + } + + @Override + public void validate() { + validateInvoked = true; + } + + @Override + public void validate(Object... validationHints) { + this.validationHints = Arrays.asList(validationHints); + validateInvoked = true; + } + + @Override + public BindingResult getBindingResult() { + if (bindingResult == null) { + return super.getBindingResult(); + } + return bindingResult; + } + + public void setBindingResult(BindingResult bindingResult) { + this.bindingResult = bindingResult; + } + + public boolean isBindInvoked() { + return bindInvoked; + } + + public boolean isValidateInvoked() { + return validateInvoked; + } + + public List getValidationHints() { + return validationHints; + } + + public PropertyValues getPropertyValues() { + return pvs; + } +} diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/PropertyResolverRegistryTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/PropertyResolverRegistryTest.java index fade2ff..6433b13 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/PropertyResolverRegistryTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/PropertyResolverRegistryTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.mattbertolini.spring.web.reactive.bind; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/config/BinderConfigurationTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/config/BinderConfigurationTest.java index 2a82545..ccd8b27 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/config/BinderConfigurationTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/config/BinderConfigurationTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.mattbertolini.spring.web.reactive.bind.config; import com.mattbertolini.spring.web.reactive.bind.BeanParameterMethodArgumentResolver; diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/CookieParameterRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/CookieParameterRequestPropertyResolverTest.java index 5e3a698..7c82b3a 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/CookieParameterRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/CookieParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.CookieParameter; @@ -21,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.HttpCookie; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import reactor.core.publisher.Mono; @@ -60,7 +60,7 @@ void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { .build(); MockServerWebExchange exchange = MockServerWebExchange.from(request); BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, exchange)); } @@ -105,14 +105,18 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @CookieParameter("the_cookie") private String annotated; + @Nullable private String notAnnotated; + @Nullable @CookieParameter("the_cookie") private HttpCookie cookieObject; + @Nullable public String getAnnotated() { return annotated; } @@ -121,6 +125,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -129,6 +134,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public HttpCookie getCookieObject() { return cookieObject; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterMapRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterMapRequestPropertyResolverTest.java index 79864f2..b0f50a4 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterMapRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterMapRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.FormParameter; @@ -21,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.util.MultiValueMap; @@ -104,20 +104,26 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @FormParameter private Map annotated; + @Nullable private Map notAnnotated; + @Nullable @FormParameter private MultiValueMap multivalue; + @Nullable @FormParameter("name") private String withName; + @Nullable @FormParameter private String notAMap; + @Nullable public Map getAnnotated() { return annotated; } @@ -126,6 +132,7 @@ public void setAnnotated(Map annotated) { this.annotated = annotated; } + @Nullable public Map getNotAnnotated() { return notAnnotated; } @@ -134,6 +141,7 @@ public void setNotAnnotated(Map notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public MultiValueMap getMultivalue() { return multivalue; } @@ -142,6 +150,7 @@ public void setMultivalue(MultiValueMap multivalue) { this.multivalue = multivalue; } + @Nullable public String getWithName() { return withName; } @@ -150,6 +159,7 @@ public void setWithName(String withName) { this.withName = withName; } + @Nullable public String getNotAMap() { return notAMap; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterRequestPropertyResolverTest.java index d028bf8..9e27c05 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/FormParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.FormParameter; @@ -31,6 +30,7 @@ import org.springframework.http.codec.multipart.FilePart; import org.springframework.http.codec.multipart.MultipartHttpMessageWriter; import org.springframework.http.codec.multipart.Part; +import org.springframework.lang.Nullable; import org.springframework.mock.http.client.reactive.MockClientHttpRequest; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; @@ -89,7 +89,7 @@ void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { .build(); MockServerWebExchange exchange = MockServerWebExchange.from(request); BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, exchange)); } @@ -215,20 +215,26 @@ private String partContentToString(Part part) { @SuppressWarnings("unused") private static class TestingBean { + @Nullable @FormParameter("testing") private String annotated; + @Nullable private String notAnnotated; + @Nullable @FormParameter("multiple_values") private List multipleValues; + @Nullable @FormParameter private String missingValue; + @Nullable @FormParameter("file") private Part multipartValue; + @Nullable public String getAnnotated() { return annotated; } @@ -237,6 +243,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -245,6 +252,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public List getMultipleValues() { return multipleValues; } @@ -253,6 +261,7 @@ public void setMultipleValues(List multipleValues) { this.multipleValues = multipleValues; } + @Nullable public String getMissingValue() { return missingValue; } @@ -261,6 +270,7 @@ public void setMissingValue(String missingValue) { this.missingValue = missingValue; } + @Nullable public Part getMultipartValue() { return multipartValue; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterMapRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterMapRequestPropertyResolverTest.java index cafd7c4..0ff2bca 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterMapRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterMapRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; @@ -21,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.util.MultiValueMap; @@ -121,23 +121,30 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @HeaderParameter private Map annotated; + @Nullable private Map notAnnotated; + @Nullable @HeaderParameter private MultiValueMap multivalue; + @Nullable @HeaderParameter private HttpHeaders httpHeaders; + @Nullable @HeaderParameter("irrelevant") private String withValue; + @Nullable @HeaderParameter private String notAMap; + @Nullable public Map getAnnotated() { return annotated; } @@ -146,6 +153,7 @@ public void setAnnotated(Map annotated) { this.annotated = annotated; } + @Nullable public Map getNotAnnotated() { return notAnnotated; } @@ -154,6 +162,7 @@ public void setNotAnnotated(Map notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public MultiValueMap getMultivalue() { return multivalue; } @@ -162,6 +171,7 @@ public void setMultivalue(MultiValueMap multivalue) { this.multivalue = multivalue; } + @Nullable public HttpHeaders getHttpHeaders() { return httpHeaders; } @@ -170,6 +180,7 @@ public void setHttpHeaders(HttpHeaders httpHeaders) { this.httpHeaders = httpHeaders; } + @Nullable public String getWithValue() { return withValue; } @@ -178,6 +189,7 @@ public void setWithValue(String withValue) { this.withValue = withValue; } + @Nullable public String getNotAMap() { return notAMap; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterRequestPropertyResolverTest.java index 062525a..cfcb73f 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/HeaderParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import reactor.core.publisher.Mono; @@ -67,7 +67,7 @@ void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { .build(); MockServerWebExchange exchange = MockServerWebExchange.from(request); BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, exchange)); } @@ -114,17 +114,22 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @HeaderParameter("X-HeaderName") private String annotated; + @Nullable private String notAnnotated; + @Nullable @HeaderParameter private String missingValue; + @Nullable @HeaderParameter("X-Multiple") private List multipleValues; + @Nullable public String getAnnotated() { return annotated; } @@ -133,6 +138,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -141,6 +147,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public String getMissingValue() { return missingValue; } @@ -149,6 +156,7 @@ public void setMissingValue(String missingValue) { this.missingValue = missingValue; } + @Nullable public List getMultipleValues() { return multipleValues; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterMapRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterMapRequestPropertyResolverTest.java index fcb14b1..42f0477 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterMapRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterMapRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.PathParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.web.reactive.HandlerMapping; @@ -103,17 +103,22 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @PathParameter private Map annotated; + @Nullable private Map notAnnotated; + @Nullable @PathParameter("irrelevant") private String withValue; + @Nullable @PathParameter private String notAMap; + @Nullable public Map getAnnotated() { return annotated; } @@ -122,6 +127,7 @@ public void setAnnotated(Map annotated) { this.annotated = annotated; } + @Nullable public Map getNotAnnotated() { return notAnnotated; } @@ -130,6 +136,7 @@ public void setNotAnnotated(Map notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public String getWithValue() { return withValue; } @@ -138,6 +145,7 @@ public void setWithValue(String withValue) { this.withValue = withValue; } + @Nullable public String getNotAMap() { return notAMap; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterRequestPropertyResolverTest.java index 52d293d..299f0b5 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/PathParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.PathParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.web.reactive.HandlerMapping; @@ -76,7 +76,7 @@ void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { .build(); MockServerWebExchange exchange = MockServerWebExchange.from(request); BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, exchange)); } @@ -119,14 +119,18 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @PathParameter("pathParamName") private String annotated; + @Nullable private String notAnnotated; + @Nullable @PathParameter private String missingValue; + @Nullable public String getAnnotated() { return annotated; } @@ -135,6 +139,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -143,6 +148,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public String getMissingValue() { return missingValue; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestBodyRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestBodyRequestPropertyResolverTest.java index 32aede7..1ac4392 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestBodyRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestBodyRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestBody; @@ -26,6 +25,7 @@ import org.springframework.http.MediaType; import org.springframework.http.codec.DecoderHttpMessageReader; import org.springframework.http.codec.HttpMessageReader; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import reactor.core.publisher.Mono; @@ -105,12 +105,14 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @RequestBody private String annotated; + @Nullable private String notAnnotated; - + @Nullable public String getAnnotated() { return annotated; } @@ -119,6 +121,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestContextRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestContextRequestPropertyResolverTest.java index 00b17f2..4d8c13c 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestContextRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestContextRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestContext; @@ -23,6 +22,7 @@ import org.springframework.context.i18n.TimeZoneAwareLocaleContext; import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.mock.web.server.MockWebSession; @@ -216,32 +216,42 @@ private static class NotKnown {} @SuppressWarnings("unused") private static class TestingBean { + @Nullable private ServerWebExchange notAnnotated; + @Nullable @RequestContext private NotKnown notKnown; + @Nullable @RequestContext private ServerWebExchange serverWebExchange; + @Nullable @RequestContext private ServerHttpRequest serverHttpRequest; + @Nullable @RequestContext private WebSession webSession; + @Nullable @RequestContext private HttpMethod httpMethod; + @Nullable @RequestContext private Locale locale; + @Nullable @RequestContext private TimeZone timeZone; + @Nullable @RequestContext private ZoneId zoneId; + @Nullable public ServerWebExchange getNotAnnotated() { return notAnnotated; } @@ -250,6 +260,7 @@ public void setNotAnnotated(ServerWebExchange notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public NotKnown getNotKnown() { return notKnown; } @@ -258,6 +269,7 @@ public void setNotKnown(NotKnown notKnown) { this.notKnown = notKnown; } + @Nullable public ServerWebExchange getServerWebExchange() { return serverWebExchange; } @@ -266,6 +278,7 @@ public void setServerWebExchange(ServerWebExchange serverWebExchange) { this.serverWebExchange = serverWebExchange; } + @Nullable public ServerHttpRequest getServerHttpRequest() { return serverHttpRequest; } @@ -274,6 +287,7 @@ public void setServerHttpRequest(ServerHttpRequest serverHttpRequest) { this.serverHttpRequest = serverHttpRequest; } + @Nullable public WebSession getWebSession() { return webSession; } @@ -282,6 +296,7 @@ public void setWebSession(WebSession webSession) { this.webSession = webSession; } + @Nullable public HttpMethod getHttpMethod() { return httpMethod; } @@ -290,6 +305,7 @@ public void setHttpMethod(HttpMethod httpMethod) { this.httpMethod = httpMethod; } + @Nullable public Locale getLocale() { return locale; } @@ -298,6 +314,7 @@ public void setLocale(Locale locale) { this.locale = locale; } + @Nullable public TimeZone getTimeZone() { return timeZone; } @@ -306,6 +323,7 @@ public void setTimeZone(TimeZone timeZone) { this.timeZone = timeZone; } + @Nullable public ZoneId getZoneId() { return zoneId; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterMapRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterMapRequestPropertyResolverTest.java index 450576c..36e6931 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterMapRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterMapRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.util.MultiValueMap; @@ -100,20 +100,26 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @RequestParameter private Map annotated; + @Nullable private Map notAnnotated; + @Nullable @RequestParameter private MultiValueMap multivalue; + @Nullable @RequestParameter private String notAMap; + @Nullable @RequestParameter("irrelevant") private Map valuePresent; + @Nullable public Map getAnnotated() { return annotated; } @@ -122,6 +128,7 @@ public void setAnnotated(Map annotated) { this.annotated = annotated; } + @Nullable public Map getNotAnnotated() { return notAnnotated; } @@ -130,6 +137,7 @@ public void setNotAnnotated(Map notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public MultiValueMap getMultivalue() { return multivalue; } @@ -138,6 +146,7 @@ public void setMultivalue(MultiValueMap multivalue) { this.multivalue = multivalue; } + @Nullable public String getNotAMap() { return notAMap; } @@ -146,6 +155,7 @@ public void setNotAMap(String notAMap) { this.notAMap = notAMap; } + @Nullable public Map getValuePresent() { return valuePresent; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterRequestPropertyResolverTest.java index 6335480..4c5b190 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/RequestParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import reactor.core.publisher.Mono; @@ -66,7 +66,7 @@ void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { .build(); MockServerWebExchange exchange = MockServerWebExchange.from(request); BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, exchange)); } @@ -112,17 +112,22 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @RequestParameter("testing") private String annotated; + @Nullable private String notAnnotated; + @Nullable @RequestParameter private String missingValue; + @Nullable @RequestParameter("multiple_values") private List multipleValues; + @Nullable public String getAnnotated() { return annotated; } @@ -131,6 +136,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -139,6 +145,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public String getMissingValue() { return missingValue; } @@ -147,6 +154,7 @@ public void setMissingValue(String missingValue) { this.missingValue = missingValue; } + @Nullable public List getMultipleValues() { return multipleValues; } diff --git a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/SessionParameterRequestPropertyResolverTest.java b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/SessionParameterRequestPropertyResolverTest.java index afcf83f..c064461 100644 --- a/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/SessionParameterRequestPropertyResolverTest.java +++ b/spring-webflux-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/reactive/bind/resolver/SessionParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.mock.web.server.MockWebSession; @@ -58,7 +58,7 @@ void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { .build(); MockServerWebExchange exchange = MockServerWebExchange.from(request); BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, exchange)); } @@ -102,11 +102,14 @@ private BindingProperty bindingProperty(String propertyName) throws Introspectio @SuppressWarnings("unused") private static class TestingBean { + @Nullable @SessionParameter("sessionKey") private String annotated; + @Nullable private String notAnnotated; + @Nullable public String getAnnotated() { return annotated; } @@ -115,6 +118,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } diff --git a/spring-webmvc-annotated-data-binder/build.gradle.kts b/spring-webmvc-annotated-data-binder/build.gradle.kts index b837cd8..b565033 100644 --- a/spring-webmvc-annotated-data-binder/build.gradle.kts +++ b/spring-webmvc-annotated-data-binder/build.gradle.kts @@ -6,14 +6,14 @@ plugins { dependencies { api(project(":spring-annotated-data-binder-core")) api(libs.springWebmvc) - implementation(libs.javaxServletApi) + implementation(libs.jakartaServletApi) compileOnly(libs.findbugsJsr305) // To Prevent warnings on missing enum constants testImplementation(libs.junitJupiterApi) testImplementation(libs.assertJCore) testImplementation(libs.mockitoCore) testImplementation(libs.springTest) - testImplementation(libs.javaxValidationApi) // Used to test validation annotations + testImplementation(libs.jakartaValidationApi) // Used to test validation annotations testCompileOnly(libs.findbugsJsr305) // To Prevent warnings on missing enum constants } diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/BeanParameterMethodArgumentResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/BeanParameterMethodArgumentResolver.java index 337c95d..024a212 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/BeanParameterMethodArgumentResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/BeanParameterMethodArgumentResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,99 +13,88 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind; import com.mattbertolini.spring.web.bind.RequestPropertyBindingException; import com.mattbertolini.spring.web.bind.annotation.BeanParameter; import com.mattbertolini.spring.web.bind.introspect.AnnotatedRequestBeanIntrospector; import com.mattbertolini.spring.web.bind.introspect.ResolvedPropertyData; +import com.mattbertolini.spring.web.bind.support.MapValueResolver; import com.mattbertolini.spring.web.servlet.mvc.bind.resolver.RequestPropertyResolver; import org.springframework.beans.BeanUtils; import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.PropertyValues; import org.springframework.core.MethodParameter; -import org.springframework.lang.NonNull; -import org.springframework.util.Assert; +import org.springframework.core.ResolvableType; import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.method.annotation.ModelAttributeMethodProcessor; import java.util.Collection; +import java.util.HashMap; import java.util.Map; +import java.util.Objects; public class BeanParameterMethodArgumentResolver extends ModelAttributeMethodProcessor { - private static final String INTROSPECTOR_TARGET_CLASS = BeanParameterMethodArgumentResolver.class + - ".INTROSPECTOR_TARGET_CLASS"; - + private static final String BIND_VALUES_ATTRIBUTE_KEY = BeanParameterMethodArgumentResolver.class.getName() + ".bindValues"; private final AnnotatedRequestBeanIntrospector introspector; - public BeanParameterMethodArgumentResolver(@NonNull AnnotatedRequestBeanIntrospector introspector) { + public BeanParameterMethodArgumentResolver(AnnotatedRequestBeanIntrospector introspector) { super(false); this.introspector = introspector; } @Override - public boolean supportsParameter(@NonNull MethodParameter parameter) { + public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(BeanParameter.class) && !BeanUtils.isSimpleProperty(parameter.getParameterType()); } @Override - public boolean supportsReturnType(@NonNull MethodParameter returnType) { + public boolean supportsReturnType(MethodParameter returnType) { return false; } @Override - protected void bindRequestParameters(@NonNull WebDataBinder binder, @NonNull NativeWebRequest request) { - Assert.state(binder.getTarget() != null, "WebDataBinder must have a target object"); - PropertyValues propertyValues = makePropertyValues(binder.getTarget().getClass(), request); - binder.bind(propertyValues); + protected void constructAttribute(WebDataBinder binder, NativeWebRequest request) { + ResolvableType targetType = Objects.requireNonNull(binder.getTargetType(), "WebDataBinder must have a target type"); + Map valuesToBind = memoizedGetValuesToBind(Objects.requireNonNull(targetType.getRawClass()), request); + binder.construct(new MapValueResolver(valuesToBind)); + } + + @Override + protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) { + Object target = Objects.requireNonNull(binder.getTarget(), "WebDataBinder must have a target object"); + Map valuesToBind = memoizedGetValuesToBind(target.getClass(), request); + binder.bind(new MutablePropertyValues(valuesToBind)); + request.removeAttribute(BIND_VALUES_ATTRIBUTE_KEY, RequestAttributes.SCOPE_REQUEST); } - @NonNull - private PropertyValues makePropertyValues(@NonNull Class targetType, @NonNull NativeWebRequest request) { - MutablePropertyValues propertyValues = new MutablePropertyValues(); + @SuppressWarnings("unchecked") + private Map memoizedGetValuesToBind(Class targetType, NativeWebRequest request) { + /* Nullable */ Map memoizedValues = (Map) request.getAttribute(BIND_VALUES_ATTRIBUTE_KEY, RequestAttributes.SCOPE_REQUEST); + if (memoizedValues != null) { + return memoizedValues; + } + Map valuesToBind = getValuesToBind(targetType, request); + request.setAttribute(BIND_VALUES_ATTRIBUTE_KEY, valuesToBind, RequestAttributes.SCOPE_REQUEST); + return valuesToBind; + } + + private Map getValuesToBind(Class targetType, NativeWebRequest request) { + Map values = new HashMap<>(); Collection propertyData = introspector.getResolversFor(targetType); for (ResolvedPropertyData data : propertyData) { - RequestPropertyResolver resolver = (RequestPropertyResolver) data.getResolver(); + RequestPropertyResolver resolver = (RequestPropertyResolver) data.resolver(); try { - Object value = resolver.resolve(data.getBindingProperty(), request); + Object value = resolver.resolve(data.bindingProperty(), request); if (value != null) { - String propertyName = data.getPropertyName(); - propertyValues.add(propertyName, value); + String propertyName = data.propertyName(); + values.put(propertyName, value); } } catch (Exception e) { throw new RequestPropertyBindingException("Unable to resolve property. " + e.getMessage(), e); } } - return propertyValues; - } - - @Override - @NonNull - protected Object createAttribute(@NonNull String attributeName, MethodParameter parameter, @NonNull WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception { - try { - MethodParameter nestedParameter = parameter.nestedIfOptional(); - Class clazz = nestedParameter.getNestedParameterType(); - webRequest.setAttribute(INTROSPECTOR_TARGET_CLASS, clazz, RequestAttributes.SCOPE_REQUEST); - return super.createAttribute(attributeName, parameter, binderFactory, webRequest); - } finally { - webRequest.removeAttribute(INTROSPECTOR_TARGET_CLASS, RequestAttributes.SCOPE_REQUEST); - } - } - - @Override - public Object resolveConstructorArgument(@NonNull String paramName,@NonNull Class paramType, NativeWebRequest request) throws Exception { - Class clazz = (Class) request.getAttribute(INTROSPECTOR_TARGET_CLASS, RequestAttributes.SCOPE_REQUEST); - if (clazz == null) { - return super.resolveConstructorArgument(paramName, paramType, request); - } - - final Map resolvers = introspector.getResolverMapFor(clazz); - final ResolvedPropertyData resolvedPropertyData = resolvers.get(paramName); - final RequestPropertyResolver resolver = (RequestPropertyResolver) resolvedPropertyData.getResolver(); - return resolver.resolve(resolvedPropertyData.getBindingProperty(), request); + return values; } } diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/PropertyResolverRegistry.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/PropertyResolverRegistry.java index 88dc526..df8c48d 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/PropertyResolverRegistry.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/PropertyResolverRegistry.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind; import com.mattbertolini.spring.web.bind.AbstractPropertyResolverRegistry; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/BinderConfiguration.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/BinderConfiguration.java index d66604c..c715934 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/BinderConfiguration.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/BinderConfiguration.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.config; import com.mattbertolini.spring.web.bind.introspect.AnnotatedRequestBeanIntrospector; @@ -36,7 +35,7 @@ import com.mattbertolini.spring.web.servlet.mvc.bind.resolver.SessionParameterRequestPropertyResolver; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; @@ -90,13 +89,12 @@ public Set getPackagesToScan() { } @Override - public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) { - if (!(bean instanceof RequestMappingHandlerAdapter)) { + @Nullable + public Object postProcessBeforeInitialization(Object bean, String beanName) { + if (!(bean instanceof RequestMappingHandlerAdapter adapter)) { return bean; } - RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean; - PropertyResolverRegistry resolverRegistry = createPropertyResolverRegistry(adapter); AnnotatedRequestBeanIntrospector introspector = createIntrospector(resolverRegistry); BeanParameterMethodArgumentResolver resolver = createResolver(introspector); diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/package-info.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/package-info.java new file mode 100644 index 0000000..601f313 --- /dev/null +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.servlet.mvc.bind.config; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/package-info.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/package-info.java new file mode 100644 index 0000000..52dbce0 --- /dev/null +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.servlet.mvc.bind; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/CookieParameterRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/CookieParameterRequestPropertyResolver.java index cab8d4d..8b2848a 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/CookieParameterRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/CookieParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,31 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.CookieParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; -import org.springframework.lang.NonNull; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.util.WebUtils; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; +import java.util.Objects; public class CookieParameterRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { return bindingProperty.hasAnnotation(CookieParameter.class); } @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeWebRequest request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, NativeWebRequest request) { HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); Assert.state(servletRequest != null, "A HttpServletRequest is required for this resolver and none found."); CookieParameter annotation = bindingProperty.getAnnotation(CookieParameter.class); - Assert.state(annotation != null, "No CookieParameter annotation found on type"); + Objects.requireNonNull(annotation, "No CookieParameter annotation found on type"); Cookie cookie = WebUtils.getCookie(servletRequest, annotation.value()); if (cookie == null) { return null; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterMapRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterMapRequestPropertyResolver.java index b4a7786..6d39d58 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterMapRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterMapRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.FormParameter; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterRequestPropertyResolver.java index 10bd6cd..b70b9bf 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,27 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.FormParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; -import org.springframework.lang.NonNull; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import java.util.Objects; + public class FormParameterRequestPropertyResolver extends RequestParameterRequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { FormParameter annotation = bindingProperty.getAnnotation(FormParameter.class); return annotation != null && StringUtils.hasText(annotation.value()); } @Override - @NonNull - protected String getName(@NonNull BindingProperty bindingProperty) { + protected String getName(BindingProperty bindingProperty) { FormParameter annotation = bindingProperty.getAnnotation(FormParameter.class); - Assert.state(annotation != null, "No FormParameter annotation found on type"); + Objects.requireNonNull(annotation, "No FormParameter annotation found on type"); return annotation.value(); } } diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterMapRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterMapRequestPropertyResolver.java index 2a279f0..8ae2af7 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterMapRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterMapRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterRequestPropertyResolver.java index 7016e47..aaeb1d1 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,31 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; -import org.springframework.lang.NonNull; -import org.springframework.util.Assert; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; import org.springframework.web.context.request.NativeWebRequest; +import java.util.Objects; + /** + * Resolve HTTP header values + * * @see NativeWebRequest#getHeaderValues(String) */ public class HeaderParameterRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { HeaderParameter annotation = bindingProperty.getAnnotation(HeaderParameter.class); return annotation != null && StringUtils.hasText(annotation.value()); } @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeWebRequest request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, NativeWebRequest request) { HeaderParameter annotation = bindingProperty.getAnnotation(HeaderParameter.class); - Assert.state(annotation != null, "No HeaderParameter annotation found on type"); + Objects.requireNonNull(annotation, "No HeaderParameter annotation found on type"); return request.getHeaderValues(annotation.value()); } } diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterMapRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterMapRequestPropertyResolver.java index df74f4d..f6dacc3 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterMapRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterMapRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.PathParameter; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterRequestPropertyResolver.java index 9deef1d..f10e11d 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,33 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.PathParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; -import org.springframework.lang.NonNull; -import org.springframework.util.Assert; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.servlet.HandlerMapping; import java.util.Map; +import java.util.Objects; public class PathParameterRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { PathParameter annotation = bindingProperty.getAnnotation(PathParameter.class); return annotation != null && StringUtils.hasText(annotation.value()); } @SuppressWarnings("unchecked") @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeWebRequest request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, NativeWebRequest request) { PathParameter annotation = bindingProperty.getAnnotation(PathParameter.class); - Assert.state(annotation != null, "No PathParameter annotation found on type"); + Objects.requireNonNull(annotation, "No PathParameter annotation found on type"); Map uriTemplateVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); if (uriTemplateVariables == null) { diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestBodyRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestBodyRequestPropertyResolver.java index 9416b76..621897f 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestBodyRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestBodyRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.PropertyResolutionException; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestContextRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestContextRequestPropertyResolver.java index dab9a90..e49c2a6 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestContextRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestContextRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,27 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestContext; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; import org.springframework.http.HttpMethod; -import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.support.RequestContextUtils; -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; import java.time.ZoneId; import java.util.Locale; import java.util.TimeZone; public class RequestContextRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { Class type = bindingProperty.getType(); return bindingProperty.hasAnnotation(RequestContext.class) && ( WebRequest.class.isAssignableFrom(type) || @@ -47,7 +46,8 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { } @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeWebRequest request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, NativeWebRequest request) { Class type = bindingProperty.getType(); if (WebRequest.class.isAssignableFrom(type)) { return request; @@ -64,7 +64,7 @@ public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeW // Not creating a session here. return servletRequest.getSession(false); } else if (HttpMethod.class.isAssignableFrom(type)) { - return HttpMethod.resolve(servletRequest.getMethod()); + return HttpMethod.valueOf(servletRequest.getMethod()); } else if (Locale.class.isAssignableFrom(type)) { return RequestContextUtils.getLocale(servletRequest); } else if(TimeZone.class.isAssignableFrom(type)) { diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterMapRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterMapRequestPropertyResolver.java index 345cf29..208cc37 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterMapRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterMapRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,14 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.PropertyResolutionException; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.Part; import org.springframework.core.ResolvableType; import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; @@ -29,14 +32,11 @@ import org.springframework.web.multipart.MultipartRequest; import org.springframework.web.multipart.support.MultipartResolutionDelegate; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.Part; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.Map; public class RequestParameterMapRequestPropertyResolver implements RequestPropertyResolver { @@ -48,6 +48,7 @@ public boolean supports(@NonNull BindingProperty bindingProperty) { } @Override + @Nullable public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeWebRequest request) { ResolvableType resolvableType = ResolvableType.forMethodParameter(bindingProperty.getMethodParameter()); @@ -65,7 +66,7 @@ public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeW Map parameterMap = request.getParameterMap(); MultiValueMap ret = new LinkedMultiValueMap<>(parameterMap.size()); for (Map.Entry entry : parameterMap.entrySet()) { - ret.put(entry.getKey(), new LinkedList<>(Arrays.asList(entry.getValue()))); + ret.put(entry.getKey(), new ArrayList<>(Arrays.asList(entry.getValue()))); } return ret; } @@ -105,7 +106,7 @@ public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeW } } - private LinkedHashMap resolveServletRequestPartsToMap(NativeWebRequest request) { + private Map resolveServletRequestPartsToMap(NativeWebRequest request) { try { HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) { diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterRequestPropertyResolver.java index 868efb3..d05d999 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,32 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.PropertyResolutionException; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import com.mattbertolini.spring.web.bind.resolver.AbstractNamedRequestPropertyResolver; -import org.springframework.lang.NonNull; -import org.springframework.util.Assert; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.multipart.support.MultipartResolutionDelegate; -import javax.servlet.http.HttpServletRequest; +import java.util.Objects; public class RequestParameterRequestPropertyResolver extends AbstractNamedRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { RequestParameter annotation = bindingProperty.getAnnotation(RequestParameter.class); return annotation != null && StringUtils.hasText(annotation.value()); } @Override - protected Object resolveWithName(@NonNull BindingProperty bindingProperty, String name, @NonNull NativeWebRequest request) { + @Nullable + protected Object resolveWithName(BindingProperty bindingProperty, String name, NativeWebRequest request) { HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); if (servletRequest != null) { try { @@ -55,10 +55,9 @@ protected Object resolveWithName(@NonNull BindingProperty bindingProperty, Strin } @Override - @NonNull - protected String getName(@NonNull BindingProperty bindingProperty) { + protected String getName(BindingProperty bindingProperty) { RequestParameter annotation = bindingProperty.getAnnotation(RequestParameter.class); - Assert.state(annotation != null, "No RequestParameter annotation found on type"); + Objects.requireNonNull(annotation, "No RequestParameter annotation found on type"); return annotation.value(); } } diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestPropertyResolver.java index 7aedadd..34772bb 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.resolver.RequestPropertyResolverBase; diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/SessionParameterRequestPropertyResolver.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/SessionParameterRequestPropertyResolver.java index c7aeb15..162c781 100644 --- a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/SessionParameterRequestPropertyResolver.java +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/SessionParameterRequestPropertyResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,26 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; -import org.springframework.lang.NonNull; -import org.springframework.util.Assert; +import org.springframework.lang.Nullable; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; +import java.util.Objects; + public class SessionParameterRequestPropertyResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { return bindingProperty.hasAnnotation(SessionParameter.class); } @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeWebRequest request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, NativeWebRequest request) { SessionParameter annotation = bindingProperty.getAnnotation(SessionParameter.class); - Assert.state(annotation != null, "No SessionParameter annotation found on type"); + Objects.requireNonNull(annotation, "No SessionParameter annotation found on type"); return request.getAttribute(annotation.value(), RequestAttributes.SCOPE_SESSION); } } diff --git a/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/package-info.java b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/package-info.java new file mode 100644 index 0000000..02e3beb --- /dev/null +++ b/spring-webmvc-annotated-data-binder/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NonNullApi +@NonNullFields +package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/BeanParameterMethodArgumentResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/BeanParameterMethodArgumentResolverTest.java index 19c7e53..1b3b10e 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/BeanParameterMethodArgumentResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/BeanParameterMethodArgumentResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind; import com.mattbertolini.spring.web.bind.RequestPropertyBindingException; @@ -22,25 +21,21 @@ import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import com.mattbertolini.spring.web.bind.introspect.ResolvedPropertyData; import com.mattbertolini.spring.web.servlet.mvc.bind.resolver.RequestPropertyResolver; +import jakarta.validation.Valid; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.PropertyValue; import org.springframework.beans.PropertyValues; import org.springframework.core.MethodParameter; -import org.springframework.format.support.FormattingConversionServiceFactoryBean; -import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; -import javax.validation.Valid; import java.beans.PropertyDescriptor; import java.util.Arrays; import java.util.List; @@ -49,9 +44,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.catchThrowableOfType; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -62,7 +54,7 @@ class BeanParameterMethodArgumentResolverTest { private ServletWebRequest request; private ModelAndViewContainer mavContainer; private AnnotatedRequestBeanIntrospector introspector; - private WebDataBinderFactory webDataBinderFactory; + private MockWebDataBinderFactory webDataBinderFactory; @BeforeEach void setUp() { @@ -70,7 +62,7 @@ void setUp() { request = new ServletWebRequest(servletRequest); mavContainer = new ModelAndViewContainer(); introspector = mock(AnnotatedRequestBeanIntrospector.class); - webDataBinderFactory = mock(WebDataBinderFactory.class); + webDataBinderFactory = new MockWebDataBinderFactory(); resolver = new BeanParameterMethodArgumentResolver(introspector); } @@ -120,8 +112,6 @@ void supportsParameterReturnsFalseWhenAnnotationIsMissing() throws Exception { @Test void resolveArgumentReturnsTheTargetObject() throws Exception { MethodParameter methodParameter = createMethodParameter("anAnnotatedMethod", ABeanClass.class); - ABeanClass target = new ABeanClass(); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(new StubWebDataBinder(target)); Object actual = resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); assertThat(actual).isNotNull(); assertThat(actual.getClass()).isEqualTo(ABeanClass.class); @@ -130,8 +120,6 @@ void resolveArgumentReturnsTheTargetObject() throws Exception { @Test void resolveArgumentUnwrapTheTargetObjectFromOptional() throws Exception { MethodParameter methodParameter = createMethodParameter("optionalTypeAnnotated", Optional.class); - Object target = new ABeanClass(); - when(webDataBinderFactory.createBinder(eq(request), any(Optional.class), anyString())).thenReturn(new StubWebDataBinder(target)); Object actual = resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); assertThat(actual).isNotNull(); assertThat(actual.getClass()).isEqualTo(Optional.class); @@ -143,8 +131,8 @@ void resolveArgumentUnwrapTheTargetObjectFromOptional() throws Exception { @Test void resolveArgumentCallsBinderBind() throws Exception { MethodParameter methodParameter = createMethodParameter("anAnnotatedMethod", ABeanClass.class); - StubWebDataBinder dataBinder = new StubWebDataBinder(new ABeanClass()); - resolver.resolveArgument(methodParameter, mavContainer, request, (webRequest, target, objectName) -> dataBinder); + resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); + MockWebDataBinder dataBinder = webDataBinderFactory.getBinder(); assertThat(dataBinder.isBindInvoked()).isTrue(); } @@ -157,13 +145,10 @@ void resolvesPropertyValues() throws Exception { MethodParameter methodParameter = createMethodParameter("anAnnotatedMethod", ABeanClass.class); - StubWebDataBinder dataBinder = new StubWebDataBinder(new ABeanClass()); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - when(introspector.getResolversFor(ABeanClass.class)).thenReturn(propertyData); resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); - PropertyValues propertyValues = dataBinder.getPropertyValues(); + PropertyValues propertyValues = webDataBinderFactory.getBinder().getPropertyValues(); assertThat(propertyValues.contains("propertyOne")).isTrue(); assertThat(propertyValues.contains("propertyTwo")).isTrue(); @@ -184,13 +169,10 @@ void resolvesOnlyFoundPropertyValues() throws Exception { MethodParameter methodParameter = createMethodParameter("anAnnotatedMethod", ABeanClass.class); - StubWebDataBinder dataBinder = new StubWebDataBinder(new ABeanClass()); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - when(introspector.getResolversFor(ABeanClass.class)).thenReturn(propertyData); resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); - PropertyValues propertyValues = dataBinder.getPropertyValues(); + PropertyValues propertyValues = webDataBinderFactory.getBinder().getPropertyValues(); assertThat(propertyValues.contains("propertyOne")).isFalse(); assertThat(propertyValues.contains("propertyTwo")).isTrue(); @@ -208,7 +190,6 @@ void throwsExceptionWhenResolverErrors() throws Exception { MethodParameter methodParameter = createMethodParameter("anAnnotatedMethod", ABeanClass.class); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(new StubWebDataBinder(new ABeanClass())); when(introspector.getResolversFor(ABeanClass.class)).thenReturn(propertyData); assertThatThrownBy(() -> resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory)) .isInstanceOf(RequestPropertyBindingException.class); @@ -217,36 +198,23 @@ void throwsExceptionWhenResolverErrors() throws Exception { @Test void validatesWhenValidAnnotationPresent() throws Exception { MethodParameter methodParameter = createMethodParameter("aValidMethod", ABeanClass.class); - - StubWebDataBinder dataBinder = new StubWebDataBinder(new ABeanClass()); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); - - assertThat(dataBinder.isValidateInvoked()).isTrue(); + assertThat(webDataBinderFactory.getBinder().isValidateInvoked()).isTrue(); } @Test void validatesWhenValidatedAnnotationPresent() throws Exception { MethodParameter methodParameter = createMethodParameter("aValidatedMethod", ABeanClass.class); - - StubWebDataBinder dataBinder = new StubWebDataBinder(new ABeanClass()); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); - - assertThat(dataBinder.isValidateInvoked()).isTrue(); + assertThat(webDataBinderFactory.getBinder().isValidateInvoked()).isTrue(); } @Test void validatesWithGroups() throws Exception { MethodParameter methodParameter = createMethodParameter("validationGroups", ABeanClass.class); - StubWebDataBinder dataBinder = new StubWebDataBinder(new ABeanClass()); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); - + MockWebDataBinder dataBinder = webDataBinderFactory.getBinder(); assertThat(dataBinder.isValidateInvoked()).isTrue(); assertThat(dataBinder.getValidationHints()).contains(ValidationGroupOne.class, ValidationGroupTwo.class); } @@ -258,9 +226,7 @@ void validationThrowsBindException() throws Exception { BindingResult bindingResult = mock(BindingResult.class); when(bindingResult.hasErrors()).thenReturn(true); - StubWebDataBinder dataBinder = new StubWebDataBinder(new ABeanClass()); - dataBinder.setBindingResult(bindingResult); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(dataBinder); + webDataBinderFactory.setBindingResult(bindingResult); BindException exception = catchThrowableOfType(() -> resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory), BindException.class); assertThat(exception.getBindingResult()).isEqualTo(bindingResult); @@ -273,81 +239,19 @@ void validationHasErrorsWithBindingResultMethodParameter() throws Exception { BindingResult bindingResult = mock(BindingResult.class); when(bindingResult.hasErrors()).thenReturn(true); - StubWebDataBinder dataBinder = new StubWebDataBinder(new ABeanClass()); - dataBinder.setBindingResult(bindingResult); - when(webDataBinderFactory.createBinder(eq(request), any(ABeanClass.class), anyString())).thenReturn(dataBinder); - + webDataBinderFactory.setBindingResult(bindingResult); resolver.resolveArgument(methodParameter, mavContainer, request, webDataBinderFactory); - - assertThat(dataBinder.getBindingResult()).isEqualTo(bindingResult); + assertThat(webDataBinderFactory.getBinder().getBindingResult()).isEqualTo(bindingResult); } private MethodParameter createMethodParameter(String anAnnotatedMethod, Class... parameterTypes) throws NoSuchMethodException { return new MethodParameter(FakeHandlerMethod.class.getMethod(anAnnotatedMethod, parameterTypes), 0); } - private static class StubWebDataBinder extends WebDataBinder { - private boolean bindInvoked = false; - private boolean validateInvoked = true; - private PropertyValues pvs; - private List validationHints; - private BindingResult bindingResult; - - public StubWebDataBinder(Object target) { - super(target); - FormattingConversionServiceFactoryBean conversionServiceFactoryBean = new FormattingConversionServiceFactoryBean(); - conversionServiceFactoryBean.afterPropertiesSet(); - setConversionService(conversionServiceFactoryBean.getObject()); - } - - @Override - public void bind(PropertyValues pvs) { - this.pvs = pvs; - bindInvoked = true; - } - - @Override - public void validate() { - validateInvoked = true; - } - - @Override - public void validate(Object... validationHints) { - this.validationHints = Arrays.asList(validationHints); - validateInvoked = true; - } - - @Override - public BindingResult getBindingResult() { - if (bindingResult == null) { - return super.getBindingResult(); - } - return bindingResult; - } - - public void setBindingResult(BindingResult bindingResult) { - this.bindingResult = bindingResult; - } - - public boolean isBindInvoked() { - return bindInvoked; - } - - public boolean isValidateInvoked() { - return validateInvoked; - } - - public List getValidationHints() { - return validationHints; - } - - public PropertyValues getPropertyValues() { - return pvs; - } - } - private static class MockRequestPropertyResolver implements RequestPropertyResolver { + @Nullable private final Object value; + @Nullable private final RuntimeException exception; private MockRequestPropertyResolver(@Nullable T value, @Nullable RuntimeException exception) { @@ -356,13 +260,14 @@ private MockRequestPropertyResolver(@Nullable T value, @Nullable RuntimeExce } @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { // Not used in this test return true; } @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeWebRequest request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, NativeWebRequest request) { if (exception != null) { throw exception; } @@ -418,10 +323,14 @@ public void withBindingResult(@BeanParameter @Validated ABeanClass aBeanClass, B } } + @SuppressWarnings("unused") private static class ABeanClass { + @Nullable private String propertyOne; + @Nullable private Integer propertyTwo; + @Nullable public String getPropertyOne() { return propertyOne; } @@ -430,6 +339,7 @@ public void setPropertyOne(String propertyOne) { this.propertyOne = propertyOne; } + @Nullable public Integer getPropertyTwo() { return propertyTwo; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/MockWebDataBinder.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/MockWebDataBinder.java new file mode 100644 index 0000000..edb3569 --- /dev/null +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/MockWebDataBinder.java @@ -0,0 +1,92 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mattbertolini.spring.web.servlet.mvc.bind; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValues; +import org.springframework.lang.Nullable; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MockWebDataBinder extends WebDataBinder { + private boolean bindInvoked = false; + private boolean validateInvoked = true; + private PropertyValues pvs; + private List validationHints; + @Nullable + private BindingResult bindingResult; + + public MockWebDataBinder(@Nullable Object target) { + super(target); + pvs = new MutablePropertyValues(); + validationHints = new ArrayList<>(); + } + + public MockWebDataBinder(@Nullable Object target, String objectName) { + super(target, objectName); + pvs = new MutablePropertyValues(); + validationHints = new ArrayList<>(); + } + + @Override + public void bind(PropertyValues pvs) { + this.pvs = pvs; + bindInvoked = true; + } + + @Override + public void validate() { + validateInvoked = true; + } + + @Override + public void validate(Object... validationHints) { + this.validationHints = Arrays.asList(validationHints); + validateInvoked = true; + } + + @Override + public BindingResult getBindingResult() { + if (bindingResult == null) { + return super.getBindingResult(); + } + return bindingResult; + } + + public void setBindingResult(BindingResult bindingResult) { + this.bindingResult = bindingResult; + } + + public boolean isBindInvoked() { + return bindInvoked; + } + + public boolean isValidateInvoked() { + return validateInvoked; + } + + public List getValidationHints() { + return validationHints; + } + + public PropertyValues getPropertyValues() { + return pvs; + } +} diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/MockWebDataBinderFactory.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/MockWebDataBinderFactory.java new file mode 100644 index 0000000..a76bd7b --- /dev/null +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/MockWebDataBinderFactory.java @@ -0,0 +1,74 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mattbertolini.spring.web.servlet.mvc.bind; + +import com.uber.nullaway.annotations.Initializer; +import org.springframework.core.ResolvableType; +import org.springframework.format.support.FormattingConversionServiceFactoryBean; +import org.springframework.lang.Nullable; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; + +public class MockWebDataBinderFactory implements WebDataBinderFactory { + private MockWebDataBinder binder; + @Nullable + private BindingResult bindingResult; + + @Initializer + @Override + public WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName, ResolvableType targetType) throws Exception { + binder = new MockWebDataBinder(target, objectName); + if (target == null) { + binder.setTargetType(targetType); + } + + if (bindingResult != null) { + binder.setBindingResult(bindingResult); + } + + FormattingConversionServiceFactoryBean conversionServiceFactoryBean = new FormattingConversionServiceFactoryBean(); + conversionServiceFactoryBean.afterPropertiesSet(); + binder.setConversionService(conversionServiceFactoryBean.getObject()); + + return binder; + } + + @Initializer + @Override + public WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception { + binder = new MockWebDataBinder(target, objectName); + + if (bindingResult != null) { + binder.setBindingResult(bindingResult); + } + + FormattingConversionServiceFactoryBean conversionServiceFactoryBean = new FormattingConversionServiceFactoryBean(); + conversionServiceFactoryBean.afterPropertiesSet(); + binder.setConversionService(conversionServiceFactoryBean.getObject()); + + return binder; + } + + public void setBindingResult(BindingResult bindingResult) { + this.bindingResult = bindingResult; + } + + public MockWebDataBinder getBinder() { + return binder; + } +} diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/PropertyResolverRegistryTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/PropertyResolverRegistryTest.java index bc4964b..9cdec6d 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/PropertyResolverRegistryTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/PropertyResolverRegistryTest.java @@ -1,10 +1,25 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.mattbertolini.spring.web.servlet.mvc.bind; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import com.mattbertolini.spring.web.servlet.mvc.bind.resolver.RequestPropertyResolver; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.web.context.request.NativeWebRequest; import java.util.Collections; @@ -46,12 +61,13 @@ void addsResolversFromRegistry() { private static class FakeResolver implements RequestPropertyResolver { @Override - public boolean supports(@NonNull BindingProperty bindingProperty) { + public boolean supports(BindingProperty bindingProperty) { return false; } @Override - public Object resolve(@NonNull BindingProperty bindingProperty, @NonNull NativeWebRequest request) { + @Nullable + public Object resolve(BindingProperty bindingProperty, NativeWebRequest request) { return null; } } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/BinderConfigurationTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/BinderConfigurationTest.java index 80721d6..3ad2134 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/BinderConfigurationTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/config/BinderConfigurationTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.mattbertolini.spring.web.servlet.mvc.bind.config; import com.mattbertolini.spring.web.servlet.mvc.bind.PropertyResolverRegistry; diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/CookieParameterRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/CookieParameterRequestPropertyResolverTest.java index d58b62b..8b393ad 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/CookieParameterRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/CookieParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.CookieParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; +import jakarta.servlet.http.Cookie; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; -import javax.servlet.http.Cookie; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; @@ -63,7 +63,7 @@ void supportsReturnsFalseOnMissingAnnotation() throws Exception { void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { // Unlikely to happen as the library always checks the supports method. BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, request)); } @@ -107,14 +107,18 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @CookieParameter("the_cookie") private String annotated; + @Nullable private String notAnnotated; + @Nullable @CookieParameter("the_cookie") private Cookie cookieObject; + @Nullable public String getAnnotated() { return annotated; } @@ -123,6 +127,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -131,6 +136,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public Cookie getCookieObject() { return cookieObject; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/ExceptionThrowingMockMultipartHttpServletRequest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/ExceptionThrowingMockMultipartHttpServletRequest.java index 41a07d1..1fd38b6 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/ExceptionThrowingMockMultipartHttpServletRequest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/ExceptionThrowingMockMultipartHttpServletRequest.java @@ -1,10 +1,25 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Part; import org.springframework.mock.web.MockMultipartHttpServletRequest; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.ServletException; -import javax.servlet.http.Part; import java.io.IOException; import java.util.Collection; diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterMapRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterMapRequestPropertyResolverTest.java index 3c84ca6..6aa36db 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterMapRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterMapRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.PropertyResolutionException; import com.mattbertolini.spring.web.bind.annotation.FormParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; +import jakarta.servlet.http.Part; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartHttpServletRequest; @@ -30,7 +31,6 @@ import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.Part; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.nio.charset.StandardCharsets; @@ -298,32 +298,42 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @FormParameter private Map annotated; + @Nullable private Map notAnnotated; + @Nullable @FormParameter private MultiValueMap multivalue; + @Nullable @FormParameter("name") private String withName; + @Nullable @FormParameter private String notAMap; + @Nullable @FormParameter private Map multipartFileMap; + @Nullable @FormParameter private MultiValueMap multiValueMultipartMap; + @Nullable @FormParameter private Map partMap; + @Nullable @FormParameter private MultiValueMap multiValuePartMap; + @Nullable public Map getAnnotated() { return annotated; } @@ -332,6 +342,7 @@ public void setAnnotated(Map annotated) { this.annotated = annotated; } + @Nullable public Map getNotAnnotated() { return notAnnotated; } @@ -340,6 +351,7 @@ public void setNotAnnotated(Map notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public MultiValueMap getMultivalue() { return multivalue; } @@ -348,6 +360,7 @@ public void setMultivalue(MultiValueMap multivalue) { this.multivalue = multivalue; } + @Nullable public String getWithName() { return withName; } @@ -356,6 +369,7 @@ public void setWithName(String withName) { this.withName = withName; } + @Nullable public String getNotAMap() { return notAMap; } @@ -364,6 +378,7 @@ public void setNotAMap(String notAMap) { this.notAMap = notAMap; } + @Nullable public Map getMultipartFileMap() { return multipartFileMap; } @@ -372,6 +387,7 @@ public void setMultipartFileMap(Map multipartFileMap) { this.multipartFileMap = multipartFileMap; } + @Nullable public MultiValueMap getMultiValueMultipartMap() { return multiValueMultipartMap; } @@ -380,6 +396,7 @@ public void setMultiValueMultipartMap(MultiValueMap multi this.multiValueMultipartMap = multiValueMultipartMap; } + @Nullable public Map getPartMap() { return partMap; } @@ -388,6 +405,7 @@ public void setPartMap(Map partMap) { this.partMap = partMap; } + @Nullable public MultiValueMap getMultiValuePartMap() { return multiValuePartMap; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterRequestPropertyResolverTest.java index b2da2ae..c3f5726 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/FormParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.PropertyResolutionException; import com.mattbertolini.spring.web.bind.annotation.FormParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; +import jakarta.servlet.http.Part; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartHttpServletRequest; @@ -29,7 +30,6 @@ import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.Part; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.nio.charset.StandardCharsets; @@ -73,7 +73,7 @@ void supportsReturnsFalseOnMissingAnnotationValue() throws Exception { void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { // Unlikely to happen as the library always checks the supports method. BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, request)); } @@ -172,23 +172,30 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @FormParameter("testing") private String annotated; + @Nullable private String notAnnotated; + @Nullable @FormParameter("multiple_values") private List multipleValues; + @Nullable @FormParameter private String missingValue; + @Nullable @FormParameter("multipart_file") private MultipartFile multipartFile; + @Nullable @FormParameter("part") private Part part; + @Nullable public String getAnnotated() { return annotated; } @@ -197,6 +204,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -205,6 +213,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public List getMultipleValues() { return multipleValues; } @@ -213,6 +222,7 @@ public void setMultipleValues(List multipleValues) { this.multipleValues = multipleValues; } + @Nullable public String getMissingValue() { return missingValue; } @@ -221,6 +231,7 @@ public void setMissingValue(String missingValue) { this.missingValue = missingValue; } + @Nullable public MultipartFile getMultipartFile() { return multipartFile; } @@ -229,6 +240,7 @@ public void setMultipartFile(MultipartFile multipartFile) { this.multipartFile = multipartFile; } + @Nullable public Part getPart() { return part; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterMapRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterMapRequestPropertyResolverTest.java index 2ca33be..19c8cd1 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterMapRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterMapRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; @@ -21,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.util.MultiValueMap; import org.springframework.web.context.request.NativeWebRequest; @@ -130,23 +130,30 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @HeaderParameter private Map annotated; + @Nullable private Map notAnnotated; + @Nullable @HeaderParameter private MultiValueMap multivalue; + @Nullable @HeaderParameter private HttpHeaders httpHeaders; + @Nullable @HeaderParameter("irrelevant") private String withValue; + @Nullable @HeaderParameter private String notAMap; + @Nullable public Map getAnnotated() { return annotated; } @@ -155,6 +162,7 @@ public void setAnnotated(Map annotated) { this.annotated = annotated; } + @Nullable public Map getNotAnnotated() { return notAnnotated; } @@ -163,6 +171,7 @@ public void setNotAnnotated(Map notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public MultiValueMap getMultivalue() { return multivalue; } @@ -171,6 +180,7 @@ public void setMultivalue(MultiValueMap multivalue) { this.multivalue = multivalue; } + @Nullable public HttpHeaders getHttpHeaders() { return httpHeaders; } @@ -179,6 +189,7 @@ public void setHttpHeaders(HttpHeaders httpHeaders) { this.httpHeaders = httpHeaders; } + @Nullable public String getWithValue() { return withValue; } @@ -187,6 +198,7 @@ public void setWithValue(String withValue) { this.withValue = withValue; } + @Nullable public String getNotAMap() { return notAMap; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterRequestPropertyResolverTest.java index d625bc0..1ebd7f6 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/HeaderParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.HeaderParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.web.context.request.ServletWebRequest; @@ -64,7 +64,7 @@ void supportsReturnsFalseOnMissingAnnotationValue() throws Exception { void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { // Unlikely to happen as the library always checks the supports method. BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, request)); } @@ -100,17 +100,22 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @HeaderParameter("X-HeaderName") private String annotated; + @Nullable private String notAnnotated; + @Nullable @HeaderParameter private String missingValue; + @Nullable @HeaderParameter("X-Multiple") private List multipleValues; + @Nullable public String getAnnotated() { return annotated; } @@ -119,6 +124,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -127,6 +133,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public String getMissingValue() { return missingValue; } @@ -135,6 +142,7 @@ public void setMissingValue(String missingValue) { this.missingValue = missingValue; } + @Nullable public List getMultipleValues() { return multipleValues; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterMapRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterMapRequestPropertyResolverTest.java index d1e4051..6d6744f 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterMapRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterMapRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.PathParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.servlet.HandlerMapping; @@ -100,17 +100,22 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @PathParameter private Map annotated; + @Nullable private Map notAnnotated; + @Nullable @PathParameter("irrelevant") private String withValue; + @Nullable @PathParameter private String notAMap; + @Nullable public Map getAnnotated() { return annotated; } @@ -119,6 +124,7 @@ public void setAnnotated(Map annotated) { this.annotated = annotated; } + @Nullable public Map getNotAnnotated() { return notAnnotated; } @@ -127,6 +133,7 @@ public void setNotAnnotated(Map notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public String getWithValue() { return withValue; } @@ -135,6 +142,7 @@ public void setWithValue(String withValue) { this.withValue = withValue; } + @Nullable public String getNotAMap() { return notAMap; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterRequestPropertyResolverTest.java index 8f5dc34..27c75d3 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/PathParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.PathParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.servlet.HandlerMapping; @@ -67,7 +67,7 @@ void supportsReturnsFalseOnMissingAnnotationValue() throws Exception { void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { // Unlikely to happen as the library always checks the supports method. BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, request)); } @@ -110,14 +110,18 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @PathParameter("pathParamName") private String annotated; + @Nullable private String notAnnotated; + @Nullable @PathParameter private String missingValue; + @Nullable public String getAnnotated() { return annotated; } @@ -126,6 +130,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -134,6 +139,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public String getMissingValue() { return missingValue; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestBodyRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestBodyRequestPropertyResolverTest.java index 24be44c..2251d4a 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestBodyRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestBodyRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.PropertyResolutionException; @@ -24,6 +23,7 @@ import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; @@ -106,11 +106,14 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @RequestBody private String annotated; + @Nullable private String notAnnotated; + @Nullable public String getAnnotated() { return annotated; } @@ -119,6 +122,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestContextRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestContextRequestPropertyResolverTest.java index 16ffbb3..09c31b4 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestContextRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestContextRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,14 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.RequestContext; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.HttpMethod; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpSession; import org.springframework.web.context.request.NativeWebRequest; @@ -29,9 +32,6 @@ import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.i18n.FixedLocaleResolver; -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.time.ZoneId; @@ -189,35 +189,46 @@ private static class NotKnown {} @SuppressWarnings("unused") private static class TestingBean { + @Nullable private WebRequest notAnnotated; + @Nullable @RequestContext private NotKnown notKnown; + @Nullable @RequestContext private HttpServletRequest httpServletRequest; + @Nullable @RequestContext private ServletRequest servletRequest; + @Nullable @RequestContext private WebRequest webRequest; + @Nullable @RequestContext private HttpSession httpSession; + @Nullable @RequestContext private HttpMethod httpMethod; + @Nullable @RequestContext private Locale locale; + @Nullable @RequestContext private TimeZone timeZone; + @Nullable @RequestContext private ZoneId zoneId; + @Nullable public WebRequest getNotAnnotated() { return notAnnotated; } @@ -226,6 +237,7 @@ public void setNotAnnotated(WebRequest notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public NotKnown getNotKnown() { return notKnown; } @@ -234,6 +246,7 @@ public void setNotKnown(NotKnown notKnown) { this.notKnown = notKnown; } + @Nullable public HttpServletRequest getHttpServletRequest() { return httpServletRequest; } @@ -242,6 +255,7 @@ public void setHttpServletRequest(HttpServletRequest httpServletRequest) { this.httpServletRequest = httpServletRequest; } + @Nullable public ServletRequest getServletRequest() { return servletRequest; } @@ -250,6 +264,7 @@ public void setServletRequest(ServletRequest servletRequest) { this.servletRequest = servletRequest; } + @Nullable public WebRequest getWebRequest() { return webRequest; } @@ -258,6 +273,7 @@ public void setWebRequest(WebRequest webRequest) { this.webRequest = webRequest; } + @Nullable public HttpSession getHttpSession() { return httpSession; } @@ -266,6 +282,7 @@ public void setHttpSession(HttpSession httpSession) { this.httpSession = httpSession; } + @Nullable public HttpMethod getHttpMethod() { return httpMethod; } @@ -274,6 +291,7 @@ public void setHttpMethod(HttpMethod httpMethod) { this.httpMethod = httpMethod; } + @Nullable public Locale getLocale() { return locale; } @@ -282,6 +300,7 @@ public void setLocale(Locale locale) { this.locale = locale; } + @Nullable public TimeZone getTimeZone() { return timeZone; } @@ -290,6 +309,7 @@ public void setTimeZone(TimeZone timeZone) { this.timeZone = timeZone; } + @Nullable public ZoneId getZoneId() { return zoneId; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterMapRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterMapRequestPropertyResolverTest.java index 09029a1..79efb78 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterMapRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterMapRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.PropertyResolutionException; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; +import jakarta.servlet.http.Part; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartHttpServletRequest; @@ -30,7 +31,6 @@ import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.Part; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.nio.charset.StandardCharsets; @@ -298,32 +298,42 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @RequestParameter private Map annotated; + @Nullable private Map notAnnotated; + @Nullable @RequestParameter private MultiValueMap multivalue; + @Nullable @RequestParameter private String notAMap; + @Nullable @RequestParameter("irrelevant") private Map valuePresent; + @Nullable @RequestParameter private Map multipartFileMap; + @Nullable @RequestParameter private MultiValueMap multiValueMultipartMap; + @Nullable @RequestParameter private Map partMap; + @Nullable @RequestParameter private MultiValueMap multiValuePartMap; + @Nullable public Map getAnnotated() { return annotated; } @@ -332,6 +342,7 @@ public void setAnnotated(Map annotated) { this.annotated = annotated; } + @Nullable public Map getNotAnnotated() { return notAnnotated; } @@ -340,6 +351,7 @@ public void setNotAnnotated(Map notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public MultiValueMap getMultivalue() { return multivalue; } @@ -348,6 +360,7 @@ public void setMultivalue(MultiValueMap multivalue) { this.multivalue = multivalue; } + @Nullable public String getNotAMap() { return notAMap; } @@ -356,6 +369,7 @@ public void setNotAMap(String notAMap) { this.notAMap = notAMap; } + @Nullable public Map getValuePresent() { return valuePresent; } @@ -364,6 +378,7 @@ public void setValuePresent(Map valuePresent) { this.valuePresent = valuePresent; } + @Nullable public Map getMultipartFileMap() { return multipartFileMap; } @@ -372,6 +387,7 @@ public void setMultipartFileMap(Map multipartFileMap) { this.multipartFileMap = multipartFileMap; } + @Nullable public MultiValueMap getMultiValueMultipartMap() { return multiValueMultipartMap; } @@ -380,6 +396,7 @@ public void setMultiValueMultipartMap(MultiValueMap multi this.multiValueMultipartMap = multiValueMultipartMap; } + @Nullable public Map getPartMap() { return partMap; } @@ -388,6 +405,7 @@ public void setPartMap(Map partMap) { this.partMap = partMap; } + @Nullable public MultiValueMap getMultiValuePartMap() { return multiValuePartMap; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterRequestPropertyResolverTest.java index 37c195e..fafb0d0 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/RequestParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.PropertyResolutionException; import com.mattbertolini.spring.web.bind.annotation.RequestParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; +import jakarta.servlet.http.Part; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartHttpServletRequest; @@ -29,7 +30,6 @@ import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.Part; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.nio.charset.StandardCharsets; @@ -73,7 +73,7 @@ void supportsReturnsFalseOnMissingAnnotationValue() throws Exception { void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { // Unlikely to happen as the library always checks the supports method. BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, request)); } @@ -172,23 +172,30 @@ private BindingProperty bindingProperty(String property) throws IntrospectionExc @SuppressWarnings("unused") private static class TestingBean { + @Nullable @RequestParameter("testing") private String annotated; + @Nullable private String notAnnotated; + @Nullable @RequestParameter private String missingValue; + @Nullable @RequestParameter("multiple_values") private List multipleValues; + @Nullable @RequestParameter("multipart_file") private MultipartFile multipartFile; + @Nullable @RequestParameter("part") private Part part; + @Nullable public String getAnnotated() { return annotated; } @@ -197,6 +204,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } @@ -205,6 +213,7 @@ public void setNotAnnotated(String notAnnotated) { this.notAnnotated = notAnnotated; } + @Nullable public String getMissingValue() { return missingValue; } @@ -213,6 +222,7 @@ public void setMissingValue(String missingValue) { this.missingValue = missingValue; } + @Nullable public List getMultipleValues() { return multipleValues; } @@ -221,6 +231,7 @@ public void setMultipleValues(List multipleValues) { this.multipleValues = multipleValues; } + @Nullable public MultipartFile getMultipartFile() { return multipartFile; } @@ -229,6 +240,7 @@ public void setMultipartFile(MultipartFile multipartFile) { this.multipartFile = multipartFile; } + @Nullable public Part getPart() { return part; } diff --git a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/SessionParameterRequestPropertyResolverTest.java b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/SessionParameterRequestPropertyResolverTest.java index 72c7123..ced6ed3 100644 --- a/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/SessionParameterRequestPropertyResolverTest.java +++ b/spring-webmvc-annotated-data-binder/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/resolver/SessionParameterRequestPropertyResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.resolver; import com.mattbertolini.spring.web.bind.annotation.SessionParameter; import com.mattbertolini.spring.web.bind.introspect.BindingProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpSession; import org.springframework.web.context.request.ServletWebRequest; @@ -60,7 +60,7 @@ void supportsReturnsFalseOnMissingAnnotation() throws Exception { void throwsExceptionIfResolveCalledWithNoAnnotation() throws Exception { // Unlikely to happen as the library always checks the supports method. BindingProperty bindingProperty = bindingProperty("notAnnotated"); - assertThatExceptionOfType(IllegalStateException.class) + assertThatExceptionOfType(NullPointerException.class) .isThrownBy(() -> resolver.resolve(bindingProperty, request)); } @@ -91,11 +91,14 @@ private BindingProperty bindingProperty(String propertyName) throws Introspectio @SuppressWarnings("unused") private static class TestingBean { + @Nullable @SessionParameter("sessionKey") private String annotated; + @Nullable private String notAnnotated; + @Nullable public String getAnnotated() { return annotated; } @@ -104,6 +107,7 @@ public void setAnnotated(String annotated) { this.annotated = annotated; } + @Nullable public String getNotAnnotated() { return notAnnotated; } diff --git a/webflux-annotated-data-binder-spring-boot-starter/build.gradle.kts b/webflux-annotated-data-binder-spring-boot-starter/build.gradle.kts index 7e112b4..42110ac 100644 --- a/webflux-annotated-data-binder-spring-boot-starter/build.gradle.kts +++ b/webflux-annotated-data-binder-spring-boot-starter/build.gradle.kts @@ -10,6 +10,8 @@ dependencies { testImplementation(libs.junitJupiterApi) testImplementation(libs.assertJCore) testImplementation(libs.springBootTest) + testImplementation(libs.jakartaWebsocketClientApi) + testImplementation(libs.jakartaWebsocketApi) } tasks.named("jar").configure { diff --git a/webflux-annotated-data-binder-spring-boot-starter/src/main/java/com/mattbertolini/spring/web/reactive/bind/autoconfigure/WebFluxBinderAutoConfiguration.java b/webflux-annotated-data-binder-spring-boot-starter/src/main/java/com/mattbertolini/spring/web/reactive/bind/autoconfigure/WebFluxBinderAutoConfiguration.java index 5c6799f..b61fab7 100644 --- a/webflux-annotated-data-binder-spring-boot-starter/src/main/java/com/mattbertolini/spring/web/reactive/bind/autoconfigure/WebFluxBinderAutoConfiguration.java +++ b/webflux-annotated-data-binder-spring-boot-starter/src/main/java/com/mattbertolini/spring/web/reactive/bind/autoconfigure/WebFluxBinderAutoConfiguration.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.autoconfigure; import com.mattbertolini.spring.web.reactive.bind.PropertyResolverRegistry; @@ -22,24 +21,24 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; +import java.util.ArrayList; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Set; -@Configuration(proxyBeanMethods = false) +@AutoConfiguration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) @ConditionalOnMissingBean(BinderConfiguration.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) public class WebFluxBinderAutoConfiguration { - private final List packagesToScan = new LinkedList<>(); + private final List packagesToScan = new ArrayList<>(); private final Set customResolvers = new LinkedHashSet<>(); private final Set propertyResolverRegistries = new LinkedHashSet<>(); diff --git a/webflux-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring.factories b/webflux-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 25e6444..0000000 --- a/webflux-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - com.mattbertolini.spring.web.reactive.bind.autoconfigure.WebFluxBinderAutoConfiguration \ No newline at end of file diff --git a/webflux-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/webflux-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..fe8d94e --- /dev/null +++ b/webflux-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.mattbertolini.spring.web.reactive.bind.autoconfigure.WebFluxBinderAutoConfiguration diff --git a/webflux-annotated-data-binder-spring-boot-starter/src/test/java/com/mattbertolini/spring/web/reactive/bind/autoconfigure/WebFluxBinderAutoConfigurationTest.java b/webflux-annotated-data-binder-spring-boot-starter/src/test/java/com/mattbertolini/spring/web/reactive/bind/autoconfigure/WebFluxBinderAutoConfigurationTest.java index 8c9b174..6342779 100644 --- a/webflux-annotated-data-binder-spring-boot-starter/src/test/java/com/mattbertolini/spring/web/reactive/bind/autoconfigure/WebFluxBinderAutoConfigurationTest.java +++ b/webflux-annotated-data-binder-spring-boot-starter/src/test/java/com/mattbertolini/spring/web/reactive/bind/autoconfigure/WebFluxBinderAutoConfigurationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.reactive.bind.autoconfigure; import com.mattbertolini.spring.web.reactive.bind.config.BinderConfiguration; diff --git a/webmvc-annotated-data-binder-spring-boot-starter/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/autoconfigure/WebMvcBinderAutoConfiguration.java b/webmvc-annotated-data-binder-spring-boot-starter/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/autoconfigure/WebMvcBinderAutoConfiguration.java index 1fed7ac..64d1d57 100644 --- a/webmvc-annotated-data-binder-spring-boot-starter/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/autoconfigure/WebMvcBinderAutoConfiguration.java +++ b/webmvc-annotated-data-binder-spring-boot-starter/src/main/java/com/mattbertolini/spring/web/servlet/mvc/bind/autoconfigure/WebMvcBinderAutoConfiguration.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.autoconfigure; import com.mattbertolini.spring.web.servlet.mvc.bind.PropertyResolverRegistry; @@ -22,24 +21,24 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; +import java.util.ArrayList; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Set; -@Configuration(proxyBeanMethods = false) +@AutoConfiguration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) @ConditionalOnMissingBean(BinderConfiguration.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) public class WebMvcBinderAutoConfiguration { - private final List packagesToScan = new LinkedList<>(); + private final List packagesToScan = new ArrayList<>(); private final Set customResolvers = new LinkedHashSet<>(); private final Set propertyResolverRegistries = new LinkedHashSet<>(); diff --git a/webmvc-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring.factories b/webmvc-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 4246bcc..0000000 --- a/webmvc-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - com.mattbertolini.spring.web.servlet.mvc.bind.autoconfigure.WebMvcBinderAutoConfiguration \ No newline at end of file diff --git a/webmvc-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/webmvc-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..975fc27 --- /dev/null +++ b/webmvc-annotated-data-binder-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.mattbertolini.spring.web.servlet.mvc.bind.autoconfigure.WebMvcBinderAutoConfiguration diff --git a/webmvc-annotated-data-binder-spring-boot-starter/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/autoconfigure/WebMvcBinderAutoConfigurationTest.java b/webmvc-annotated-data-binder-spring-boot-starter/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/autoconfigure/WebMvcBinderAutoConfigurationTest.java index c2e542c..e3d2411 100644 --- a/webmvc-annotated-data-binder-spring-boot-starter/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/autoconfigure/WebMvcBinderAutoConfigurationTest.java +++ b/webmvc-annotated-data-binder-spring-boot-starter/src/test/java/com/mattbertolini/spring/web/servlet/mvc/bind/autoconfigure/WebMvcBinderAutoConfigurationTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.mattbertolini.spring.web.servlet.mvc.bind.autoconfigure; import com.mattbertolini.spring.web.servlet.mvc.bind.config.BinderConfiguration;