From 592ca7e3273d2f087eb5d15760b443f4b771be51 Mon Sep 17 00:00:00 2001 From: Bernhard Lutzmann Date: Thu, 11 Mar 2021 21:09:34 +0100 Subject: [PATCH] Add param converter for LocalDate fix #5860 --- ...lDateCustomParamConverterProviderTest.java | 84 +++++++++++++++++++ .../test/simple/LocalDateParamTest.java | 52 ++++++++++++ .../common/processor/EndpointIndexer.java | 8 ++ .../processor/ResteasyReactiveDotNames.java | 2 + .../processor/ServerEndpointIndexer.java | 5 ++ .../converters/LocalDateParamConverter.java | 34 ++++++++ 6 files changed, 185 insertions(+) create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/LocalDateCustomParamConverterProviderTest.java create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/LocalDateParamTest.java create mode 100644 independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/LocalDateParamConverter.java diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/LocalDateCustomParamConverterProviderTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/LocalDateCustomParamConverterProviderTest.java new file mode 100644 index 0000000000000..2f7da02dc2298 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/LocalDateCustomParamConverterProviderTest.java @@ -0,0 +1,84 @@ +package io.quarkus.resteasy.reactive.server.test.simple; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import javax.ws.rs.ext.ParamConverter; +import javax.ws.rs.ext.ParamConverterProvider; +import javax.ws.rs.ext.Provider; + +import org.hamcrest.Matchers; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class LocalDateCustomParamConverterProviderTest { + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(HelloResource.class, CustomLocalDateParamConverterProvider.class, + CustomLocalDateParamConverter.class)); + + @Test + public void localDateAsQueryParam() { + RestAssured.get("/hello?date=1981-W38-6") + .then().body(Matchers.equalTo("hello#1981-09-19")); + } + + @Test + public void localDateAsPathParam() { + RestAssured.get("/hello/1995-W38-4") + .then().body(Matchers.equalTo("hello@1995-09-21")); + } + + @Path("hello") + public static class HelloResource { + + @GET + public String helloQuery(@QueryParam("date") LocalDate date) { + return "hello#" + date; + } + + @GET + @Path("{date}") + public String helloPath(@PathParam("date") LocalDate date) { + return "hello@" + date; + } + } + + public static class CustomLocalDateParamConverter implements ParamConverter { + + @Override + public LocalDate fromString(String value) { + return LocalDate.parse(value, DateTimeFormatter.ISO_WEEK_DATE); + } + + @Override + public String toString(LocalDate value) { + return value.format(DateTimeFormatter.ISO_WEEK_DATE); + } + } + + @Provider + public static class CustomLocalDateParamConverterProvider implements ParamConverterProvider { + + @Override + public ParamConverter getConverter(Class rawType, Type genericType, Annotation[] annotations) { + if (rawType == LocalDate.class) { + return (ParamConverter) new CustomLocalDateParamConverter(); + } + return null; + } + } +} diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/LocalDateParamTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/LocalDateParamTest.java new file mode 100644 index 0000000000000..5f7fced579066 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/LocalDateParamTest.java @@ -0,0 +1,52 @@ +package io.quarkus.resteasy.reactive.server.test.simple; + +import java.time.LocalDate; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; + +import org.hamcrest.Matchers; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class LocalDateParamTest { + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(HelloResource.class)); + + @Test + public void localDateAsQueryParam() { + RestAssured.get("/hello?date=1984-08-08") + .then().body(Matchers.equalTo("hello#1984-08-08")); + } + + @Test + public void localDateAsPathParam() { + RestAssured.get("/hello/1995-09-21") + .then().body(Matchers.equalTo("hello@1995-09-21")); + } + + @Path("hello") + public static class HelloResource { + + @GET + public String helloQuery(@QueryParam("date") LocalDate date) { + return "hello#" + date; + } + + @GET + @Path("{date}") + public String helloPath(@PathParam("date") LocalDate date) { + return "hello@" + date; + } + } +} 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 d7421b9cd2039..4aabff2af8a16 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 @@ -17,6 +17,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.HEADER_PARAM; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.INTEGER; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.LIST; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.LOCAL_DATE; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.LONG; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.MATRIX_PARAM; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.MULTI; @@ -893,6 +894,10 @@ && isContextType(paramType.asClassType())) { elementType = paramType.name().toString(); handlePathSegmentParam(builder); typeHandled = true; + } else if ((paramType.name().equals(LOCAL_DATE)) && (type == ParameterType.PATH || type == ParameterType.QUERY)) { + elementType = paramType.name().toString(); + handleLocalDateParam(builder); + typeHandled = true; } if (!typeHandled) { @@ -922,6 +927,9 @@ protected boolean handleCustomParameter(Map anns, P protected void handlePathSegmentParam(PARAM builder) { } + protected void handleLocalDateParam(PARAM builder) { + } + protected void handleOtherParam(Map existingConverters, String errorLocation, boolean hasRuntimeConverters, PARAM builder, String elementType) { } 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 02f54ba4e4798..db9d9f3f0f206 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 @@ -8,6 +8,7 @@ import java.io.OutputStream; import java.math.BigDecimal; import java.math.BigInteger; +import java.time.LocalDate; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -164,6 +165,7 @@ public final class ResteasyReactiveDotNames { public static final DotName MAP = DotName.createSimple(Map.class.getName()); public static final DotName MULTI_VALUED_MAP = DotName.createSimple(MultivaluedMap.class.getName()); public static final DotName PATH_SEGMENT = DotName.createSimple(PathSegment.class.getName()); + public static final DotName LOCAL_DATE = DotName.createSimple(LocalDate.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 6666ba25e93b1..adcda24bd2af2 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 @@ -38,6 +38,7 @@ import org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames; import org.jboss.resteasy.reactive.server.core.parameters.ParameterExtractor; import org.jboss.resteasy.reactive.server.core.parameters.converters.ListConverter; +import org.jboss.resteasy.reactive.server.core.parameters.converters.LocalDateParamConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.OptionalConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.ParameterConverterSupplier; import org.jboss.resteasy.reactive.server.core.parameters.converters.PathSegmentParamConverter; @@ -282,6 +283,10 @@ protected void handlePathSegmentParam(ServerIndexedParameter builder) { builder.setConverter(new PathSegmentParamConverter.Supplier()); } + protected void handleLocalDateParam(ServerIndexedParameter builder) { + builder.setConverter(new LocalDateParamConverter.Supplier()); + } + protected ParameterConverterSupplier extractConverter(String elementType, IndexView indexView, Map existingConverters, String errorLocation, boolean hasRuntimeConverters) { return null; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/LocalDateParamConverter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/LocalDateParamConverter.java new file mode 100644 index 0000000000000..373ca033dfdb4 --- /dev/null +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/LocalDateParamConverter.java @@ -0,0 +1,34 @@ +package org.jboss.resteasy.reactive.server.core.parameters.converters; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import org.jboss.resteasy.reactive.server.model.ParamConverterProviders; + +public class LocalDateParamConverter implements ParameterConverter { + + @Override + public Object convert(Object parameter) { + return LocalDate.parse(String.valueOf(parameter), DateTimeFormatter.ISO_LOCAL_DATE); + } + + @Override + public void init(ParamConverterProviders deployment, Class rawType, Type genericType, + Annotation[] annotations) { + // no init required + } + + public static class Supplier implements ParameterConverterSupplier { + + @Override + public String getClassName() { + return LocalDateParamConverter.class.getName(); + } + + @Override + public ParameterConverter get() { + return new LocalDateParamConverter(); + } + } +}