From 633c793336744ae304a5ba169b960286dfd14369 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 27 Jun 2023 09:59:05 +0300 Subject: [PATCH] Add support for java.time.Year as JAX-RS parameter Closes: #34324 --- .../common/processor/EndpointIndexer.java | 4 +- .../processor/ResteasyReactiveDotNames.java | 2 + .../processor/ServerEndpointIndexer.java | 4 + .../converters/YearParamConverter.java | 55 +++++++++ .../vertx/test/simple/YearParamTest.java | 104 ++++++++++++++++++ 5 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/YearParamConverter.java create mode 100644 independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/YearParamTest.java diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java index 5bf03b3e6830f..56a3bf6639784 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java @@ -75,6 +75,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.TRANSACTIONAL; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.UNI; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.URI_INFO; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.YEAR; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.ZONED_DATE_TIME; import java.lang.reflect.Modifier; @@ -147,8 +148,7 @@ public abstract class EndpointIndexer SUPPORT_TEMPORAL_PARAMS = Set.of(INSTANT, LOCAL_DATE, LOCAL_TIME, LOCAL_DATE_TIME, - OFFSET_TIME, - OFFSET_DATE_TIME, ZONED_DATE_TIME); + OFFSET_TIME, OFFSET_DATE_TIME, ZONED_DATE_TIME, YEAR); protected static final Logger log = Logger.getLogger(EndpointIndexer.class); protected static final String[] EMPTY_STRING_ARRAY = new String[] {}; diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java index 191449b553310..69d1747782895 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java @@ -10,6 +10,7 @@ import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.OffsetTime; +import java.time.Year; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Collection; @@ -200,6 +201,7 @@ public final class ResteasyReactiveDotNames { public static final DotName OFFSET_DATE_TIME = DotName.createSimple(OffsetDateTime.class.getName()); public static final DotName OFFSET_TIME = DotName.createSimple(OffsetTime.class.getName()); public static final DotName ZONED_DATE_TIME = DotName.createSimple(ZonedDateTime.class.getName()); + public static final DotName YEAR = DotName.createSimple(Year.class.getName()); public static final DotName UNI = DotName.createSimple(Uni.class.getName()); public static final DotName MULTI = DotName.createSimple(Multi.class.getName()); diff --git a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java index f562f684d943f..5044f7eb4b3ee 100644 --- a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java +++ b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java @@ -20,6 +20,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.OFFSET_TIME; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.SET; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.SORTED_SET; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.YEAR; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.ZONED_DATE_TIME; import java.io.File; @@ -79,6 +80,7 @@ import org.jboss.resteasy.reactive.server.core.parameters.converters.RuntimeResolvedConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.SetConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.SortedSetConverter; +import org.jboss.resteasy.reactive.server.core.parameters.converters.YearParamConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.ZonedDateTimeParamConverter; import org.jboss.resteasy.reactive.server.mapping.URITemplate; import org.jboss.resteasy.reactive.server.model.HandlerChainCustomizer; @@ -504,6 +506,8 @@ private ParameterConverterSupplier determineTemporalConverter(DotName paramType, return new OffsetTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName); } else if (ZONED_DATE_TIME.equals(paramType)) { return new ZonedDateTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName); + } else if (YEAR.equals(paramType)) { + return new YearParamConverter.Supplier(format, dateTimeFormatterProviderClassName); } throw new RuntimeException( diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/YearParamConverter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/YearParamConverter.java new file mode 100644 index 0000000000000..818a143ccdb8b --- /dev/null +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/YearParamConverter.java @@ -0,0 +1,55 @@ +package org.jboss.resteasy.reactive.server.core.parameters.converters; + +import static java.time.temporal.ChronoField.YEAR; + +import java.time.Year; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.SignStyle; + +public class YearParamConverter extends TemporalParamConverter { + + // lifted from the JDK as PARSER is private... + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .toFormatter(); + + // this can be called by generated code + public YearParamConverter() { + super(PARSER); + } + + public YearParamConverter(DateTimeFormatter formatter) { + super(formatter); + } + + @Override + protected Year convert(String value) { + return Year.parse(value); + } + + @Override + protected Year convert(String value, DateTimeFormatter formatter) { + return Year.parse(value, formatter); + } + + public static class Supplier extends TemporalSupplier { + + public Supplier() { + } + + public Supplier(String pattern, String dateTimeFormatterProviderClassName) { + super(pattern, dateTimeFormatterProviderClassName); + } + + @Override + protected YearParamConverter createConverter(DateTimeFormatter dateTimeFormatter) { + return new YearParamConverter(dateTimeFormatter); + } + + @Override + public String getClassName() { + return YearParamConverter.class.getName(); + } + } +} diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/YearParamTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/YearParamTest.java new file mode 100644 index 0000000000000..1764f6171220a --- /dev/null +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/YearParamTest.java @@ -0,0 +1,104 @@ +package org.jboss.resteasy.reactive.server.vertx.test.simple; + +import java.time.Year; +import java.time.format.DateTimeFormatter; + +import jakarta.ws.rs.CookieParam; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.QueryParam; + +import org.hamcrest.Matchers; +import org.jboss.resteasy.reactive.DateFormat; +import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.restassured.RestAssured; + +public class YearParamTest { + + @RegisterExtension + static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(HelloResource.class, CustomDateTimeFormatterProvider.class)); + + @Test + public void yearAsQueryParam() { + RestAssured.get("/hello?date=01984") + .then().statusCode(200).body(Matchers.equalTo("hello#1984")); + } + + @Test + public void yearAsPathParam() { + RestAssured.get("/hello/1821") + .then().statusCode(200).body(Matchers.equalTo("hello@1821")); + } + + @Test + public void yearAsFormParam() { + RestAssured.given().formParam("date", "995").post("/hello") + .then().statusCode(200).body(Matchers.equalTo("hello:995")); + } + + @Test + public void yearAsHeader() { + RestAssured.with().header("date", "1984") + .get("/hello/header") + .then().statusCode(200).body(Matchers.equalTo("hello=1984")); + } + + @Test + public void yearAsCookie() { + RestAssured.with().cookie("date", "1984") + .get("/hello/cookie") + .then().statusCode(200).body(Matchers.equalTo("hello/1984")); + } + + @Path("hello") + public static class HelloResource { + + @GET + public String helloQuery(@QueryParam("date") @DateFormat(pattern = "yyyyy") Year date) { + return "hello#" + date; + } + + @GET + @Path("{date}") + public String helloPath(@PathParam("date") Year date) { + return "hello@" + date; + } + + @POST + public String helloForm( + @FormParam("date") @DateFormat(dateTimeFormatterProvider = CustomDateTimeFormatterProvider.class) Year date) { + return "hello:" + date; + } + + @GET + @Path("cookie") + public String helloCookie( + @CookieParam("date") Year date) { + return "hello/" + date; + } + + @GET + @Path("header") + public String helloHeader( + @HeaderParam("date") Year date) { + return "hello=" + date; + } + } + + public static class CustomDateTimeFormatterProvider implements DateFormat.DateTimeFormatterProvider { + @Override + public DateTimeFormatter get() { + return DateTimeFormatter.ofPattern("yyy"); + } + } + +}