From e72ef047c5192169e934ff0ff2321f9aa9764073 Mon Sep 17 00:00:00 2001 From: Yun Zhou Date: Wed, 26 Aug 2026 13:53:56 -0700 Subject: [PATCH] Encapsulate simple and one level paramaterized types Add 5 factory methods to TypeMarker and an implementation of ParameterizedType for simple types and the 4 base parameterized types that conjure generates. This reduces the need for most TypeMarkers, while also being reasonably readable, and type safe, so that no casting of TypeMarkers is needed by the caller. TypeMarkers are still produced for parameterized types that have more than one level of parameterization. In practice, this comprises a vanishingly small number of types. --- ...RequestProcessingTestServiceEndpoints.java | 6 +- .../product/ErrorServiceEndpoints.java | 18 ++-- .../ServiceUsingExternalTypesEndpoints.java | 2 +- .../another/TestServiceEndpoints.java | 37 ++++---- .../product/EmptyPathServiceEndpoints.java | 2 +- .../product/ErrorServiceEndpoints.java | 18 ++-- .../palantir/product/EteServiceEndpoints.java | 66 +++++++------ .../ExternalLongTestServiceEndpoints.java | 12 +-- .../test/api/AsyncMarkersEndpoints.java | 6 +- .../test/api/AsyncMarkersEndpoints.java | 6 +- .../NameCollisionServiceEndpoints.java | 8 +- .../UndertowServiceHandlerGenerator.java | 37 +++++++- conjure-undertow-lib/build.gradle | 4 + .../conjure/java/undertow/lib/TypeMarker.java | 93 ++++++++++++++++++- .../ConjureUndertowEndpointsGenerator.java | 47 ++++++++-- .../CookieParamsEndpoints.java.generated | 2 +- ...aultDecoderServiceEndpoints.java.generated | 8 +- ...edEndpointResourceEndpoints.java.generated | 2 +- ...DeprecatedResourceEndpoints.java.generated | 2 +- .../ExtendsNestedEndpoints.java.generated | 2 +- ...ndsSimpleInterfaceEndpoints.java.generated | 2 +- .../GenericImplEndpoints.java.generated | 4 +- ...tipleBodyInterfaceEndpoints.java.generated | 6 +- ...OverloadedResourceEndpoints.java.generated | 4 +- ...PrimitiveBodyParamEndpoints.java.generated | 2 +- ...SafeLoggableParamsEndpoints.java.generated | 6 +- 26 files changed, 279 insertions(+), 123 deletions(-) diff --git a/conjure-java-core/src/integrationInput/java/asyncrequest/com/palantir/product/AsyncRequestProcessingTestServiceEndpoints.java b/conjure-java-core/src/integrationInput/java/asyncrequest/com/palantir/product/AsyncRequestProcessingTestServiceEndpoints.java index f02402fd8..5742d4fd0 100644 --- a/conjure-java-core/src/integrationInput/java/asyncrequest/com/palantir/product/AsyncRequestProcessingTestServiceEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/asyncrequest/com/palantir/product/AsyncRequestProcessingTestServiceEndpoints.java @@ -58,7 +58,7 @@ private static final class DelayEndpoint implements HttpHandler, Endpoint, Retur DelayEndpoint(UndertowRuntime runtime, UndertowAsyncRequestProcessingTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -113,7 +113,7 @@ private static final class DelayFiveSecondTimeoutEndpoint DelayFiveSecondTimeoutEndpoint(UndertowRuntime runtime, UndertowAsyncRequestProcessingTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -321,7 +321,7 @@ private static final class FutureTraceIdEndpoint implements HttpHandler, Endpoin FutureTraceIdEndpoint(UndertowRuntime runtime, UndertowAsyncRequestProcessingTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Object.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/endpointerrors/com/palantir/product/ErrorServiceEndpoints.java b/conjure-java-core/src/integrationInput/java/endpointerrors/com/palantir/product/ErrorServiceEndpoints.java index 8e517a212..1396704b5 100644 --- a/conjure-java-core/src/integrationInput/java/endpointerrors/com/palantir/product/ErrorServiceEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/endpointerrors/com/palantir/product/ErrorServiceEndpoints.java @@ -54,8 +54,8 @@ private static final class TestBasicErrorEndpoint implements HttpHandler, Endpoi TestBasicErrorEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Boolean.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -105,8 +105,8 @@ private static final class TestImportedErrorEndpoint implements HttpHandler, End TestImportedErrorEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Boolean.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -156,8 +156,8 @@ private static final class TestMultipleErrorsAndPackagesEndpoint implements Http TestMultipleErrorsAndPackagesEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker>() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.optionalOf(String.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -208,7 +208,7 @@ private static final class TestEmptyBodyEndpoint implements HttpHandler, Endpoin TestEmptyBodyEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Boolean.class), this); } @Override @@ -255,7 +255,7 @@ private static final class TestBinaryEndpoint implements HttpHandler, Endpoint { TestBinaryEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Boolean.class), this); } @Override @@ -302,7 +302,7 @@ private static final class TestOptionalBinaryEndpoint implements HttpHandler, En TestOptionalBinaryEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(OptionalBinaryResponseMode.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/externalfallbacktypes/com/palantir/product/external/ServiceUsingExternalTypesEndpoints.java b/conjure-java-core/src/integrationInput/java/externalfallbacktypes/com/palantir/product/external/ServiceUsingExternalTypesEndpoints.java index 8feaf267d..08e64ce83 100644 --- a/conjure-java-core/src/integrationInput/java/externalfallbacktypes/com/palantir/product/external/ServiceUsingExternalTypesEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/externalfallbacktypes/com/palantir/product/external/ServiceUsingExternalTypesEndpoints.java @@ -49,7 +49,7 @@ private static final class ExternalEndpoint implements HttpHandler, Endpoint { this.runtime = runtime; this.delegate = delegate; this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker>() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.mapOf(String.class, String.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/servicevanilla/com/palantir/another/TestServiceEndpoints.java b/conjure-java-core/src/integrationInput/java/servicevanilla/com/palantir/another/TestServiceEndpoints.java index 62370c0e3..729555b55 100644 --- a/conjure-java-core/src/integrationInput/java/servicevanilla/com/palantir/another/TestServiceEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/servicevanilla/com/palantir/another/TestServiceEndpoints.java @@ -86,7 +86,8 @@ private static final class GetFileSystemsEndpoint implements HttpHandler, Endpoi GetFileSystemsEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = + runtime.bodySerDe().serializer(TypeMarker.mapOf(String.class, BackingFileSystem.class), this); } @Override @@ -139,8 +140,8 @@ private static final class CreateDatasetEndpoint implements HttpHandler, Endpoin CreateDatasetEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(CreateDatasetRequest.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Dataset.class), this); } @Override @@ -191,7 +192,7 @@ private static final class GetDatasetEndpoint implements HttpHandler, Endpoint { GetDatasetEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(Dataset.class), this); } @Override @@ -395,7 +396,7 @@ private static final class GetAliasedStringEndpoint implements HttpHandler, Endp GetAliasedStringEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(AliasedString.class), this); } @Override @@ -534,7 +535,7 @@ private static final class GetBranchesEndpoint implements HttpHandler, Endpoint GetBranchesEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.setOf(String.class), this); } @Override @@ -585,7 +586,7 @@ private static final class GetBranchesDeprecatedEndpoint implements HttpHandler, GetBranchesDeprecatedEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.setOf(String.class), this); } @Override @@ -644,7 +645,7 @@ private static final class GetBranchesDeprecatedForRemovalEndpoint implements Ht GetBranchesDeprecatedForRemovalEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.setOf(String.class), this); } @Override @@ -706,7 +707,7 @@ private static final class ResolveBranchEndpoint implements HttpHandler, Endpoin ResolveBranchEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(String.class), this); } @Override @@ -762,7 +763,7 @@ private static final class TestParamEndpoint implements HttpHandler, Endpoint { TestParamEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(String.class), this); } @Override @@ -819,8 +820,8 @@ private static final class TestQueryParamsEndpoint implements HttpHandler, Endpo TestQueryParamsEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(String.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Integer.class), this); } @Override @@ -878,7 +879,7 @@ private static final class TestNoResponseQueryParamsEndpoint implements HttpHand TestNoResponseQueryParamsEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(String.class), this); } @Override @@ -934,7 +935,7 @@ private static final class TestBooleanEndpoint implements HttpHandler, Endpoint TestBooleanEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Boolean.class), this); } @Override @@ -980,7 +981,7 @@ private static final class TestDoubleEndpoint implements HttpHandler, Endpoint { TestDoubleEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Double.class), this); } @Override @@ -1026,7 +1027,7 @@ private static final class TestIntegerEndpoint implements HttpHandler, Endpoint TestIntegerEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Integer.class), this); } @Override @@ -1074,8 +1075,8 @@ private static final class TestPostOptionalEndpoint implements HttpHandler, Endp TestPostOptionalEndpoint(UndertowRuntime runtime, TestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker>() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.optionalOf(String.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(String.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/EmptyPathServiceEndpoints.java b/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/EmptyPathServiceEndpoints.java index dd8c4534b..5bef71630 100644 --- a/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/EmptyPathServiceEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/EmptyPathServiceEndpoints.java @@ -41,7 +41,7 @@ private static final class EmptyPathEndpoint implements HttpHandler, Endpoint { EmptyPathEndpoint(UndertowRuntime runtime, UndertowEmptyPathService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Boolean.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/ErrorServiceEndpoints.java b/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/ErrorServiceEndpoints.java index 80b7b78be..efdd159a6 100644 --- a/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/ErrorServiceEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/ErrorServiceEndpoints.java @@ -54,8 +54,8 @@ private static final class TestBasicErrorEndpoint implements HttpHandler, Endpoi TestBasicErrorEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Boolean.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -105,8 +105,8 @@ private static final class TestImportedErrorEndpoint implements HttpHandler, End TestImportedErrorEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Boolean.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -156,8 +156,8 @@ private static final class TestMultipleErrorsAndPackagesEndpoint implements Http TestMultipleErrorsAndPackagesEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker>() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.optionalOf(String.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -208,7 +208,7 @@ private static final class TestEmptyBodyEndpoint implements HttpHandler, Endpoin TestEmptyBodyEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Boolean.class), this); } @Override @@ -255,7 +255,7 @@ private static final class TestBinaryEndpoint implements HttpHandler, Endpoint { TestBinaryEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Boolean.class), this); } @Override @@ -302,7 +302,7 @@ private static final class TestOptionalBinaryEndpoint implements HttpHandler, En TestOptionalBinaryEndpoint(UndertowRuntime runtime, UndertowErrorService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(OptionalBinaryResponseMode.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/EteServiceEndpoints.java b/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/EteServiceEndpoints.java index b54edeba1..9f87faad1 100644 --- a/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/EteServiceEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/EteServiceEndpoints.java @@ -94,7 +94,7 @@ private static final class StringEndpoint implements HttpHandler, Endpoint { StringEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -145,7 +145,7 @@ private static final class IntegerEndpoint implements HttpHandler, Endpoint { IntegerEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Integer.class), this); } @Override @@ -191,7 +191,7 @@ private static final class Double_Endpoint implements HttpHandler, Endpoint { Double_Endpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Double.class), this); } @Override @@ -237,7 +237,7 @@ private static final class Boolean_Endpoint implements HttpHandler, Endpoint { Boolean_Endpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Boolean.class), this); } @Override @@ -283,7 +283,7 @@ private static final class SafelongEndpoint implements HttpHandler, Endpoint { SafelongEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(SafeLong.class), this); } @Override @@ -329,7 +329,7 @@ private static final class RidEndpoint implements HttpHandler, Endpoint { RidEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(ResourceIdentifier.class), this); } @Override @@ -375,7 +375,7 @@ private static final class BearertokenEndpoint implements HttpHandler, Endpoint BearertokenEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(BearerToken.class), this); } @Override @@ -421,7 +421,7 @@ private static final class OptionalStringEndpoint implements HttpHandler, Endpoi OptionalStringEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(String.class), this); } @Override @@ -471,7 +471,7 @@ private static final class OptionalEmptyEndpoint implements HttpHandler, Endpoin OptionalEmptyEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(String.class), this); } @Override @@ -521,7 +521,7 @@ private static final class DatetimeEndpoint implements HttpHandler, Endpoint { DatetimeEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(OffsetDateTime.class), this); } @Override @@ -610,7 +610,7 @@ private static final class PathEndpoint implements HttpHandler, Endpoint { PathEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -659,7 +659,7 @@ private static final class ExternalLongPathEndpoint implements HttpHandler, Endp ExternalLongPathEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(Long.class), this); } @Override @@ -708,7 +708,7 @@ private static final class OptionalExternalLongQueryEndpoint implements HttpHand OptionalExternalLongQueryEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(Long.class), this); } @Override @@ -763,8 +763,8 @@ private static final class NotNullBodyEndpoint implements HttpHandler, Endpoint NotNullBodyEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(StringAliasExample.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(StringAliasExample.class), this); } @Override @@ -811,7 +811,7 @@ private static final class AliasOneEndpoint implements HttpHandler, Endpoint { AliasOneEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(StringAliasExample.class), this); } @Override @@ -862,7 +862,7 @@ private static final class OptionalAliasOneEndpoint implements HttpHandler, Endp OptionalAliasOneEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(StringAliasExample.class), this); } @Override @@ -915,7 +915,7 @@ private static final class AliasTwoEndpoint implements HttpHandler, Endpoint { AliasTwoEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(NestedStringAliasExample.class), this); } @Override @@ -970,9 +970,9 @@ private static final class NotNullBodyExternalImportEndpoint implements HttpHand this.runtime = runtime; this.delegate = delegate; this.deserializer = runtime.bodySerDe() - .deserializer(new TypeMarker() {}, this); + .deserializer(TypeMarker.of(allexamples.com.palantir.product.StringAliasExample.class), this); this.serializer = runtime.bodySerDe() - .serializer(new TypeMarker() {}, this); + .serializer(TypeMarker.of(allexamples.com.palantir.product.StringAliasExample.class), this); } @Override @@ -1024,10 +1024,9 @@ private static final class OptionalBodyExternalImportEndpoint implements HttpHan this.delegate = delegate; this.deserializer = runtime.bodySerDe() .deserializer( - new TypeMarker>() {}, this); + TypeMarker.optionalOf(allexamples.com.palantir.product.StringAliasExample.class), this); this.serializer = runtime.bodySerDe() - .serializer( - new TypeMarker>() {}, this); + .serializer(TypeMarker.optionalOf(allexamples.com.palantir.product.StringAliasExample.class), this); } @Override @@ -1080,8 +1079,7 @@ private static final class OptionalQueryExternalImportEndpoint implements HttpHa this.runtime = runtime; this.delegate = delegate; this.serializer = runtime.bodySerDe() - .serializer( - new TypeMarker>() {}, this); + .serializer(TypeMarker.optionalOf(allexamples.com.palantir.product.StringAliasExample.class), this); } @Override @@ -1179,7 +1177,7 @@ private static final class EnumQueryEndpoint implements HttpHandler, Endpoint { EnumQueryEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(SimpleEnum.class), this); } @Override @@ -1230,7 +1228,7 @@ private static final class EnumListQueryEndpoint implements HttpHandler, Endpoin EnumListQueryEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.listOf(SimpleEnum.class), this); } @Override @@ -1281,7 +1279,7 @@ private static final class OptionalEnumQueryEndpoint implements HttpHandler, End OptionalEnumQueryEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(SimpleEnum.class), this); } @Override @@ -1336,7 +1334,7 @@ private static final class EnumHeaderEndpoint implements HttpHandler, Endpoint { EnumHeaderEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(SimpleEnum.class), this); } @Override @@ -1387,7 +1385,7 @@ private static final class JsonErrorsHeaderEndpoint implements HttpHandler, Endp JsonErrorsHeaderEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -1436,7 +1434,7 @@ private static final class ErrorParameterSerializationEndpoint implements HttpHa ErrorParameterSerializationEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -1485,7 +1483,7 @@ private static final class AliasLongEndpointEndpoint implements HttpHandler, End AliasLongEndpointEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker>() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.optionalOf(LongAlias.class), this); } @Override @@ -1737,8 +1735,8 @@ private static final class UnionEndpoint implements HttpHandler, Endpoint { UnionEndpoint(UndertowRuntime runtime, UndertowEteService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(SimpleUnion.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(SimpleUnion.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/ExternalLongTestServiceEndpoints.java b/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/ExternalLongTestServiceEndpoints.java index b08fcf07a..3501ef37d 100644 --- a/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/ExternalLongTestServiceEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/undertow/com/palantir/product/ExternalLongTestServiceEndpoints.java @@ -49,7 +49,7 @@ private static final class TestDangerousLongEndpoint implements HttpHandler, End TestDangerousLongEndpoint(UndertowRuntime runtime, UndertowExternalLongTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Long.class), this); } @Override @@ -96,7 +96,7 @@ private static final class TestSafeExternalLongEndpoint implements HttpHandler, TestSafeExternalLongEndpoint(UndertowRuntime runtime, UndertowExternalLongTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Long.class), this); } @Override @@ -143,7 +143,7 @@ private static final class TestLongEndpoint implements HttpHandler, Endpoint { TestLongEndpoint(UndertowRuntime runtime, UndertowExternalLongTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(Long.class), this); } @Override @@ -190,7 +190,7 @@ private static final class TestDangerousLongAliasEndpoint implements HttpHandler TestDangerousLongAliasEndpoint(UndertowRuntime runtime, UndertowExternalLongTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(DangerousLongAlias.class), this); } @Override @@ -237,7 +237,7 @@ private static final class TestSafeExternalLongAliasEndpoint implements HttpHand TestSafeExternalLongAliasEndpoint(UndertowRuntime runtime, UndertowExternalLongTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(SafeLongAlias.class), this); } @Override @@ -284,7 +284,7 @@ private static final class TestLongAliasEndpoint implements HttpHandler, Endpoin TestLongAliasEndpoint(UndertowRuntime runtime, UndertowExternalLongTestService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(ExternalLongAlias.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/undertowasync/test/api/AsyncMarkersEndpoints.java b/conjure-java-core/src/integrationInput/java/undertowasync/test/api/AsyncMarkersEndpoints.java index 285b32a01..0bde6e28f 100644 --- a/conjure-java-core/src/integrationInput/java/undertowasync/test/api/AsyncMarkersEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/undertowasync/test/api/AsyncMarkersEndpoints.java @@ -48,7 +48,7 @@ private static final class AsyncMarkerEndpoint implements HttpHandler, Endpoint, AsyncMarkerEndpoint(UndertowRuntime runtime, AsyncMarkers delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -100,7 +100,7 @@ private static final class AsyncTagEndpoint implements HttpHandler, Endpoint, Re AsyncTagEndpoint(UndertowRuntime runtime, AsyncMarkers delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -155,7 +155,7 @@ private static final class SyncEndpoint implements HttpHandler, Endpoint { SyncEndpoint(UndertowRuntime runtime, AsyncMarkers delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/undertowasyncdisabled/test/api/AsyncMarkersEndpoints.java b/conjure-java-core/src/integrationInput/java/undertowasyncdisabled/test/api/AsyncMarkersEndpoints.java index 83dd86ca5..c215ff750 100644 --- a/conjure-java-core/src/integrationInput/java/undertowasyncdisabled/test/api/AsyncMarkersEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/undertowasyncdisabled/test/api/AsyncMarkersEndpoints.java @@ -48,7 +48,7 @@ private static final class AsyncMarkerEndpoint implements HttpHandler, Endpoint AsyncMarkerEndpoint(UndertowRuntime runtime, AsyncMarkers delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -95,7 +95,7 @@ private static final class AsyncTagEndpoint implements HttpHandler, Endpoint, Re AsyncTagEndpoint(UndertowRuntime runtime, AsyncMarkers delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -150,7 +150,7 @@ private static final class SyncEndpoint implements HttpHandler, Endpoint { SyncEndpoint(UndertowRuntime runtime, AsyncMarkers delegate) { this.runtime = runtime; this.delegate = delegate; - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override diff --git a/conjure-java-core/src/integrationInput/java/undertownamecollisions/com/palantir/product/NameCollisionServiceEndpoints.java b/conjure-java-core/src/integrationInput/java/undertownamecollisions/com/palantir/product/NameCollisionServiceEndpoints.java index 4c3df686a..e2ddfba1f 100644 --- a/conjure-java-core/src/integrationInput/java/undertownamecollisions/com/palantir/product/NameCollisionServiceEndpoints.java +++ b/conjure-java-core/src/integrationInput/java/undertownamecollisions/com/palantir/product/NameCollisionServiceEndpoints.java @@ -57,8 +57,8 @@ private static final class IntEndpoint implements HttpHandler, Endpoint { IntEndpoint(UndertowRuntime runtime, UndertowNameCollisionService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); - this.serializer = runtime.bodySerDe().serializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(String.class), this); + this.serializer = runtime.bodySerDe().serializer(TypeMarker.of(String.class), this); } @Override @@ -123,7 +123,7 @@ private static final class NoContextEndpoint implements HttpHandler, Endpoint { NoContextEndpoint(UndertowRuntime runtime, UndertowNameCollisionService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(String.class), this); } @Override @@ -171,7 +171,7 @@ private static final class ContextEndpoint implements HttpHandler, Endpoint { ContextEndpoint(UndertowRuntime runtime, UndertowNameCollisionService delegate) { this.runtime = runtime; this.delegate = delegate; - this.deserializer = runtime.bodySerDe().deserializer(new TypeMarker() {}, this); + this.deserializer = runtime.bodySerDe().deserializer(TypeMarker.of(String.class), this); } @Override diff --git a/conjure-java-core/src/main/java/com/palantir/conjure/java/services/UndertowServiceHandlerGenerator.java b/conjure-java-core/src/main/java/com/palantir/conjure/java/services/UndertowServiceHandlerGenerator.java index d43c2da43..d745d8833 100644 --- a/conjure-java-core/src/main/java/com/palantir/conjure/java/services/UndertowServiceHandlerGenerator.java +++ b/conjure-java-core/src/main/java/com/palantir/conjure/java/services/UndertowServiceHandlerGenerator.java @@ -287,10 +287,10 @@ private TypeSpec generateEndpointHandler( FieldSpec.builder(type, DESERIALIZER_VAR_NAME, Modifier.PRIVATE, Modifier.FINAL) .build()); ctorBuilder.addStatement( - "this.$1N = $2N.bodySerDe().deserializer(new $3T() {}, this)", + "this.$1N = $2N.bodySerDe().deserializer($3L, this)", DESERIALIZER_VAR_NAME, RUNTIME_VAR_NAME, - ParameterizedTypeName.get(ClassName.get(TypeMarker.class), typeName)); + typeMarker(typeName)); }); endpointDefinition.getReturns().ifPresent(returnType -> { @@ -301,10 +301,10 @@ private TypeSpec generateEndpointHandler( endpointBuilder.addField(FieldSpec.builder(type, SERIALIZER_VAR_NAME, Modifier.PRIVATE, Modifier.FINAL) .build()); ctorBuilder.addStatement( - "this.$1N = $2N.bodySerDe().serializer(new $3T() {}, this)", + "this.$1N = $2N.bodySerDe().serializer($3L, this)", SERIALIZER_VAR_NAME, RUNTIME_VAR_NAME, - ParameterizedTypeName.get(ClassName.get(TypeMarker.class), typeName)); + typeMarker(typeName)); } }); @@ -404,6 +404,35 @@ private static void addTags(EndpointDefinition endpointDefinition, TypeSpec.Buil private static final ClassName IMMUTABLE_LIST_NAME = ClassName.get(ImmutableList.class); private static final ClassName SET_NAME = ClassName.get(Set.class); private static final ClassName IMMUTABLE_SET_NAME = ClassName.get(ImmutableSet.class); + private static final ClassName MAP_NAME = ClassName.get(Map.class); + private static final Map TYPE_MARKER_FACTORIES = Map.of( + LIST_NAME, "listOf", SET_NAME, "setOf", ClassName.get(Optional.class), "optionalOf", MAP_NAME, "mapOf"); + + private static CodeBlock typeMarker(TypeName type) { + if (type instanceof ClassName className) { + return CodeBlock.of("$T.of($T.class)", TypeMarker.class, className); + } + if (type instanceof ParameterizedTypeName parameterized + && TYPE_MARKER_FACTORIES.containsKey(parameterized.rawType()) + && hasExpectedSimpleTypeArguments(parameterized)) { + CodeBlock.Builder result = CodeBlock.builder() + .add("$T.$L(", TypeMarker.class, TYPE_MARKER_FACTORIES.get(parameterized.rawType())); + for (int index = 0; index < parameterized.typeArguments().size(); index++) { + if (index > 0) { + result.add(", "); + } + result.add("$T.class", parameterized.typeArguments().get(index)); + } + return result.add(")").build(); + } + return CodeBlock.of("new $T<$T>() {}", TypeMarker.class, type); + } + + private static boolean hasExpectedSimpleTypeArguments(ParameterizedTypeName type) { + int expectedArguments = MAP_NAME.equals(type.rawType()) ? 2 : 1; + return type.typeArguments().size() == expectedArguments + && type.typeArguments().stream().allMatch(ClassName.class::isInstance); + } private TypeName immutableCollection(TypeName input) { // Note that only the outermost collection is considered for replacement to avoid diff --git a/conjure-undertow-lib/build.gradle b/conjure-undertow-lib/build.gradle index bea5a17c0..4328419b2 100644 --- a/conjure-undertow-lib/build.gradle +++ b/conjure-undertow-lib/build.gradle @@ -33,4 +33,8 @@ dependencies { // Recommend a higher version of wildfly (1.6.0.Final+) then the one shipped with undertow to avoid CVEs. runtimeOnly 'org.wildfly.common:wildfly-common' + + testImplementation 'org.assertj:assertj-core' + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.junit.jupiter:junit-jupiter-api' } diff --git a/conjure-undertow-lib/src/main/java/com/palantir/conjure/java/undertow/lib/TypeMarker.java b/conjure-undertow-lib/src/main/java/com/palantir/conjure/java/undertow/lib/TypeMarker.java index d83021cf4..989db1b77 100644 --- a/conjure-undertow-lib/src/main/java/com/palantir/conjure/java/undertow/lib/TypeMarker.java +++ b/conjure-undertow-lib/src/main/java/com/palantir/conjure/java/undertow/lib/TypeMarker.java @@ -21,6 +21,12 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; /** * Captures generic type information. @@ -81,12 +87,95 @@ public final String toString() { /** Create a new {@link TypeMarker} instance wrapping the provided {@link Type}. */ public static TypeMarker of(Type type) { - return new WrappingTypeMarker(type); + return new WrappingTypeMarker<>(type); } - private static final class WrappingTypeMarker extends TypeMarker { + public static TypeMarker of(Class type) { + return new WrappingTypeMarker<>(type); + } + + public static TypeMarker> listOf(Class elementType) { + return new WrappingTypeMarker<>(new ParameterizedTypeImpl(List.class, elementType)); + } + + public static TypeMarker> setOf(Class elementType) { + return new WrappingTypeMarker<>(new ParameterizedTypeImpl(Set.class, elementType)); + } + + public static TypeMarker> optionalOf(Class valueType) { + return new WrappingTypeMarker<>(new ParameterizedTypeImpl(Optional.class, valueType)); + } + + public static TypeMarker> mapOf(Class keyType, Class valueType) { + return new WrappingTypeMarker<>(new ParameterizedTypeImpl(Map.class, keyType, valueType)); + } + + private static final class WrappingTypeMarker extends TypeMarker { private WrappingTypeMarker(Type type) { super(type); } } + + private static final class ParameterizedTypeImpl implements ParameterizedType { + private final Class rawType; + private final Type[] typeArguments; + + private ParameterizedTypeImpl(Class rawType, Class... actualTypeArguments) { + this.rawType = Preconditions.checkNotNull(rawType, "Raw type is required"); + this.typeArguments = actualTypeArguments.clone(); + for (Type typeArgument : this.typeArguments) { + Preconditions.checkNotNull(typeArgument, "Type argument is required"); + } + } + + @Override + public Type[] getActualTypeArguments() { + return typeArguments.clone(); + } + + @Override + public Type getRawType() { + return rawType; + } + + @Override + public Type getOwnerType() { + return null; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other instanceof ParameterizedType that) { + return Objects.equals(getOwnerType(), that.getOwnerType()) + && rawType.equals(that.getRawType()) + && Arrays.equals(typeArguments, that.getActualTypeArguments()); + } + return false; + } + + @Override + public int hashCode() { + return Arrays.hashCode(typeArguments) ^ Objects.hashCode(getOwnerType()) ^ Objects.hashCode(rawType); + } + + @Override + public String getTypeName() { + StringBuilder result = new StringBuilder(rawType.getTypeName()).append('<'); + for (int index = 0; index < typeArguments.length; index++) { + if (index > 0) { + result.append(", "); + } + result.append(typeArguments[index].getTypeName()); + } + return result.append('>').toString(); + } + + @Override + public String toString() { + return getTypeName(); + } + } } diff --git a/conjure-undertow-processor/src/main/java/com/palantir/conjure/java/undertow/processor/generate/ConjureUndertowEndpointsGenerator.java b/conjure-undertow-processor/src/main/java/com/palantir/conjure/java/undertow/processor/generate/ConjureUndertowEndpointsGenerator.java index 4fce12833..ad27aedbf 100644 --- a/conjure-undertow-processor/src/main/java/com/palantir/conjure/java/undertow/processor/generate/ConjureUndertowEndpointsGenerator.java +++ b/conjure-undertow-processor/src/main/java/com/palantir/conjure/java/undertow/processor/generate/ConjureUndertowEndpointsGenerator.java @@ -205,11 +205,10 @@ public Void body( .build()) .constructorInitializer(CodeBlock.builder() .addStatement( - "this.$N = $L.deserializer(new $T<$T>() {}, $N, this)", + "this.$N = $L.deserializer($L, $N, this)", deserializerFieldName, deserializerFactory, - TypeMarker.class, - requestBodyType, + typeMarker(requestBodyType), RUNTIME_NAME) .build()) .build()); @@ -457,11 +456,10 @@ public Void context() { .build()) .constructorInitializer(CodeBlock.builder() .addStatement( - "this.$N = $L.serializer(new $T<$T>() {}, $N, this)", + "this.$N = $L.serializer($L, $N, this)", returnType.serializerFieldName(), returnType.serializerFactory(), - TypeMarker.class, - responseTypeName, + typeMarker(responseTypeName), RUNTIME_NAME) .build()) .build()); @@ -813,6 +811,43 @@ private static Optional getSafeLogging( }; } + private static final ClassName MAP_NAME = ClassName.get(Map.class); + private static final Map TYPE_MARKER_FACTORIES = Map.of( + ClassName.get(List.class), + "listOf", + ClassName.get(Set.class), + "setOf", + ClassName.get(Optional.class), + "optionalOf", + MAP_NAME, + "mapOf"); + + private static CodeBlock typeMarker(TypeName type) { + if (type instanceof ClassName className) { + return CodeBlock.of("$T.of($T.class)", TypeMarker.class, className); + } + if (type instanceof ParameterizedTypeName parameterized + && TYPE_MARKER_FACTORIES.containsKey(parameterized.rawType()) + && hasExpectedSimpleTypeArguments(parameterized)) { + CodeBlock.Builder result = CodeBlock.builder() + .add("$T.$L(", TypeMarker.class, TYPE_MARKER_FACTORIES.get(parameterized.rawType())); + for (int index = 0; index < parameterized.typeArguments().size(); index++) { + if (index > 0) { + result.add(", "); + } + result.add("$T.class", parameterized.typeArguments().get(index)); + } + return result.add(")").build(); + } + return CodeBlock.of("new $T<$T>() {}", TypeMarker.class, type); + } + + private static boolean hasExpectedSimpleTypeArguments(ParameterizedTypeName type) { + int expectedArguments = MAP_NAME.equals(type.rawType()) ? 2 : 1; + return type.typeArguments().size() == expectedArguments + && type.typeArguments().stream().allMatch(ClassName.class::isInstance); + } + private static final Map> COLLECTION_CLASSES = ImmutableMap.>builder() .put(ClassName.get(Collection.class), ImmutableList.class) .put(ClassName.get(List.class), ImmutableList.class) diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/CookieParamsEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/CookieParamsEndpoints.java.generated index 92085b33e..b1c728f54 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/CookieParamsEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/CookieParamsEndpoints.java.generated @@ -68,7 +68,7 @@ public final class CookieParamsEndpoints implements UndertowService { "optionalIntCookie", ParamDecoders.optionalIntegerParamDecoder(runtime.plainSerDe())); this.decoderCookieDeserializer = new CookieDeserializer<>("decoderCookie", CookieParams.StringParamDecoder.INSTANCE); - this.cookieParamsSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.cookieParamsSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DefaultDecoderServiceEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DefaultDecoderServiceEndpoints.java.generated index 44c13407c..12bdea317 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DefaultDecoderServiceEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DefaultDecoderServiceEndpoints.java.generated @@ -154,7 +154,7 @@ public final class DefaultDecoderServiceEndpoints implements UndertowService { "createFactory", ParamDecoders.complexCollectionParamDecoder( runtime.plainSerDe(), DefaultDecoderService.CreateFactory::create)); - this.queryParamSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.queryParamSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override @@ -333,7 +333,7 @@ public final class DefaultDecoderServiceEndpoints implements UndertowService { "createFactory", ParamDecoders.complexCollectionParamDecoder( runtime.plainSerDe(), DefaultDecoderService.CreateFactory::create)); - this.formParamSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.formParamSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override @@ -491,7 +491,7 @@ public final class DefaultDecoderServiceEndpoints implements UndertowService { "createFactory", ParamDecoders.complexCollectionParamDecoder( runtime.plainSerDe(), DefaultDecoderService.CreateFactory::create)); - this.headersSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.headersSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override @@ -623,7 +623,7 @@ public final class DefaultDecoderServiceEndpoints implements UndertowService { "createFactory", ParamDecoders.complexParamDecoder( runtime.plainSerDe(), DefaultDecoderService.CreateFactory::create)); - this.pathParamSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.pathParamSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DeprecatedEndpointResourceEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DeprecatedEndpointResourceEndpoints.java.generated index c5c139c5f..ab8ed86d8 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DeprecatedEndpointResourceEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DeprecatedEndpointResourceEndpoints.java.generated @@ -48,7 +48,7 @@ public final class DeprecatedEndpointResourceEndpoints implements UndertowServic PingEndpoint(UndertowRuntime runtime, DeprecatedEndpointResource delegate) { this.runtime = runtime; this.delegate = delegate; - this.pingSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.pingSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DeprecatedResourceEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DeprecatedResourceEndpoints.java.generated index 078ce421e..259eb93e4 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DeprecatedResourceEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/DeprecatedResourceEndpoints.java.generated @@ -49,7 +49,7 @@ public final class DeprecatedResourceEndpoints implements UndertowService { PingEndpoint(UndertowRuntime runtime, DeprecatedResource delegate) { this.runtime = runtime; this.delegate = delegate; - this.pingSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.pingSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/ExtendsNestedEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/ExtendsNestedEndpoints.java.generated index 44bc29521..fcfd3b3f4 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/ExtendsNestedEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/ExtendsNestedEndpoints.java.generated @@ -89,7 +89,7 @@ public final class ExtendsNestedEndpoints implements UndertowService { GreetEndpoint(UndertowRuntime runtime, ExtendsNested delegate) { this.runtime = runtime; this.delegate = delegate; - this.greetSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.greetSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/ExtendsSimpleInterfaceEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/ExtendsSimpleInterfaceEndpoints.java.generated index 6e67e3b6a..7e0e86dde 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/ExtendsSimpleInterfaceEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/ExtendsSimpleInterfaceEndpoints.java.generated @@ -89,7 +89,7 @@ public final class ExtendsSimpleInterfaceEndpoints implements UndertowService { GreetEndpoint(UndertowRuntime runtime, ExtendsSimpleInterface delegate) { this.runtime = runtime; this.delegate = delegate; - this.greetSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.greetSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/GenericImplEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/GenericImplEndpoints.java.generated index e10cc5ae1..78c330f23 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/GenericImplEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/GenericImplEndpoints.java.generated @@ -58,13 +58,13 @@ public final class GenericImplEndpoints implements UndertowService { GenericEndpoint(UndertowRuntime runtime, GenericImpl delegate) { this.runtime = runtime; this.delegate = delegate; - this.inputDeserializer = DefaultSerDe.INSTANCE.deserializer(new TypeMarker() {}, runtime, this); + this.inputDeserializer = DefaultSerDe.INSTANCE.deserializer(TypeMarker.of(String.class), runtime, this); this.pathParamDeserializer = new PathParamDeserializer<>( "pathParam", ParamDecoders.complexParamDecoder(runtime.plainSerDe(), GenericImpl.ParamExample::valueOf)); this.queryParamDeserializer = new QueryParamDeserializer<>( "queryParam", ParamDecoders.integerCollectionParamDecoder(runtime.plainSerDe())); - this.genericSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.genericSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(Boolean.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/MultipleBodyInterfaceEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/MultipleBodyInterfaceEndpoints.java.generated index a3980b771..1ab140b65 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/MultipleBodyInterfaceEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/MultipleBodyInterfaceEndpoints.java.generated @@ -49,9 +49,9 @@ public final class MultipleBodyInterfaceEndpoints implements UndertowService { PostEndpoint(UndertowRuntime runtime, MultipleBodyInterface delegate) { this.runtime = runtime; this.delegate = delegate; - this.oneDeserializer = DefaultSerDe.INSTANCE.deserializer(new TypeMarker() {}, runtime, this); - this.twoDeserializer = DefaultSerDe.INSTANCE.deserializer(new TypeMarker() {}, runtime, this); - this.threeDeserializer = DefaultSerDe.INSTANCE.deserializer(new TypeMarker() {}, runtime, this); + this.oneDeserializer = DefaultSerDe.INSTANCE.deserializer(TypeMarker.of(String.class), runtime, this); + this.twoDeserializer = DefaultSerDe.INSTANCE.deserializer(TypeMarker.of(String.class), runtime, this); + this.threeDeserializer = DefaultSerDe.INSTANCE.deserializer(TypeMarker.of(String.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/OverloadedResourceEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/OverloadedResourceEndpoints.java.generated index 0510a67d0..152887800 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/OverloadedResourceEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/OverloadedResourceEndpoints.java.generated @@ -49,7 +49,7 @@ public final class OverloadedResourceEndpoints implements UndertowService { EndpointEndpoint_0(UndertowRuntime runtime, OverloadedResource delegate) { this.runtime = runtime; this.delegate = delegate; - this.endpointSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.endpointSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override @@ -102,7 +102,7 @@ public final class OverloadedResourceEndpoints implements UndertowService { this.delegate = delegate; this.valueDeserializer = new QueryParamDeserializer<>("q", ParamDecoders.stringCollectionParamDecoder(runtime.plainSerDe())); - this.endpointSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.endpointSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/PrimitiveBodyParamEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/PrimitiveBodyParamEndpoints.java.generated index b52001dff..28327991a 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/PrimitiveBodyParamEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/PrimitiveBodyParamEndpoints.java.generated @@ -46,7 +46,7 @@ public final class PrimitiveBodyParamEndpoints implements UndertowService { this.runtime = runtime; this.delegate = delegate; this.countDeserializer = PrimitiveBodyParam.IntParamDeserializerFactory.INSTANCE.deserializer( - new TypeMarker() {}, runtime, this); + TypeMarker.of(Integer.class), runtime, this); } @Override diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/SafeLoggableParamsEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/SafeLoggableParamsEndpoints.java.generated index a4e64dab4..031c2f078 100644 --- a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/SafeLoggableParamsEndpoints.java.generated +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/SafeLoggableParamsEndpoints.java.generated @@ -381,7 +381,7 @@ public final class SafeLoggableParamsEndpoints implements UndertowService { this.contextDeserializer = new QueryParamDeserializer<>( "context", ParamDecoders.stringCollectionParamDecoder(runtime.plainSerDe())); this.safeLoggingReusesContextSerializer = - DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override @@ -437,8 +437,8 @@ public final class SafeLoggableParamsEndpoints implements UndertowService { BodyParamEndpoint(UndertowRuntime runtime, SafeLoggableParams delegate) { this.runtime = runtime; this.delegate = delegate; - this.bodyDeserializer = DefaultSerDe.INSTANCE.deserializer(new TypeMarker() {}, runtime, this); - this.bodyParamSerializer = DefaultSerDe.INSTANCE.serializer(new TypeMarker() {}, runtime, this); + this.bodyDeserializer = DefaultSerDe.INSTANCE.deserializer(TypeMarker.of(String.class), runtime, this); + this.bodyParamSerializer = DefaultSerDe.INSTANCE.serializer(TypeMarker.of(String.class), runtime, this); } @Override