diff --git a/changelog/@unreleased/pr-1723.v2.yml b/changelog/@unreleased/pr-1723.v2.yml new file mode 100644 index 000000000..2f1070563 --- /dev/null +++ b/changelog/@unreleased/pr-1723.v2.yml @@ -0,0 +1,5 @@ +type: improvement +improvement: + description: annotation-processor uses `of(String)` factory methods by default. + links: + - https://github.com/palantir/conjure-java/pull/1723 diff --git a/conjure-undertow-processor/src/main/java/com/palantir/conjure/java/undertow/processor/data/DefaultDecoderNames.java b/conjure-undertow-processor/src/main/java/com/palantir/conjure/java/undertow/processor/data/DefaultDecoderNames.java index 459449589..4286337d9 100644 --- a/conjure-undertow-processor/src/main/java/com/palantir/conjure/java/undertow/processor/data/DefaultDecoderNames.java +++ b/conjure-undertow-processor/src/main/java/com/palantir/conjure/java/undertow/processor/data/DefaultDecoderNames.java @@ -118,14 +118,15 @@ static Optional getUnknownDecoderFactoryFunction(TypeMirror typeMirro return Optional.of(CodeBlock.of("$T::parseShort", Short.class)); case DECLARED: DeclaredType declaredType = (DeclaredType) typeMirror; - return getValueOfDecoderFactoryFunction(declaredType) - .or(() -> getStringConstructorDecoderFactoryFunction(declaredType)); + return getValueOfDecoderFactoryFunction(declaredType, "valueOf") + .or(() -> getStringConstructorDecoderFactoryFunction(declaredType)) + .or(() -> getValueOfDecoderFactoryFunction(declaredType, "of")); default: return Optional.empty(); } } - private static Optional getValueOfDecoderFactoryFunction(DeclaredType declaredType) { + private static Optional getValueOfDecoderFactoryFunction(DeclaredType declaredType, String methodName) { TypeElement typeElement = (TypeElement) declaredType.asElement(); // T valueOf(String) return typeElement.getEnclosedElements().stream() @@ -133,11 +134,11 @@ private static Optional getValueOfDecoderFactoryFunction(DeclaredType .map(ExecutableElement.class::cast) .filter(element -> element.getModifiers().contains(Modifier.PUBLIC) && element.getModifiers().contains(Modifier.STATIC) - && element.getSimpleName().contentEquals("valueOf") + && element.getSimpleName().contentEquals(methodName) && element.getParameters().size() == 1 && isStringMirror(element.getParameters().get(0).asType()) && Objects.equals(TypeName.get(declaredType), TypeName.get(element.getReturnType()))) - .map(_element -> CodeBlock.of("$T::valueOf", TypeName.get(declaredType))) + .map(_element -> CodeBlock.of("$T::" + methodName, TypeName.get(declaredType))) .findFirst(); } diff --git a/conjure-undertow-processor/src/test/java/com/palantir/conjure/java/undertow/processor/ConjureUndertowAnnotationProcessorTest.java b/conjure-undertow-processor/src/test/java/com/palantir/conjure/java/undertow/processor/ConjureUndertowAnnotationProcessorTest.java index bfe7450f9..70956ba3d 100644 --- a/conjure-undertow-processor/src/test/java/com/palantir/conjure/java/undertow/processor/ConjureUndertowAnnotationProcessorTest.java +++ b/conjure-undertow-processor/src/test/java/com/palantir/conjure/java/undertow/processor/ConjureUndertowAnnotationProcessorTest.java @@ -32,6 +32,7 @@ import com.palantir.conjure.java.undertow.processor.sample.MultipleBodyInterface; import com.palantir.conjure.java.undertow.processor.sample.NameClashContextParam; import com.palantir.conjure.java.undertow.processor.sample.NameClashExchangeParam; +import com.palantir.conjure.java.undertow.processor.sample.OfFactory; import com.palantir.conjure.java.undertow.processor.sample.OptionalPrimitives; import com.palantir.conjure.java.undertow.processor.sample.OverloadedResource; import com.palantir.conjure.java.undertow.processor.sample.ParameterNotAnnotated; @@ -77,6 +78,11 @@ public void testMultipleBodies() { assertTestFileCompileAndMatches(TEST_CLASSES_BASE_DIR, MultipleBodyInterface.class); } + @Test + public void testOfFactoryMethod() { + assertTestFileCompileAndMatches(TEST_CLASSES_BASE_DIR, OfFactory.class); + } + @Test public void testPrimitiveQueryParams() { assertTestFileCompileAndMatches(TEST_CLASSES_BASE_DIR, PrimitiveQueryParams.class); diff --git a/conjure-undertow-processor/src/test/java/com/palantir/conjure/java/undertow/processor/sample/OfFactory.java b/conjure-undertow-processor/src/test/java/com/palantir/conjure/java/undertow/processor/sample/OfFactory.java new file mode 100644 index 000000000..8179eab06 --- /dev/null +++ b/conjure-undertow-processor/src/test/java/com/palantir/conjure/java/undertow/processor/sample/OfFactory.java @@ -0,0 +1,43 @@ +/* + * (c) Copyright 2021 Palantir Technologies Inc. All rights reserved. + * + * 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.palantir.conjure.java.undertow.processor.sample; + +import com.palantir.conjure.java.undertow.annotations.Handle; +import com.palantir.conjure.java.undertow.annotations.HttpMethod; + +public interface OfFactory { + + @Handle(method = HttpMethod.GET, path = "/{pathVar}") + void ping(@Handle.PathParam PathVariable pathVar); + + final class PathVariable { + private final String value; + + private PathVariable(String value) { + this.value = value; + } + + public static PathVariable of(String value) { + return new PathVariable(value); + } + + @Override + public String toString() { + return "PathVariable{value='" + value + '\'' + '}'; + } + } +} diff --git a/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/OfFactoryEndpoints.java.generated b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/OfFactoryEndpoints.java.generated new file mode 100644 index 000000000..666767d32 --- /dev/null +++ b/conjure-undertow-processor/src/test/resources/com/palantir/conjure/java/undertow/processor/sample/OfFactoryEndpoints.java.generated @@ -0,0 +1,84 @@ +package com.palantir.conjure.java.undertow.processor.sample; + +import com.google.common.collect.ImmutableList; +import com.palantir.conjure.java.undertow.annotations.ParamDecoders; +import com.palantir.conjure.java.undertow.annotations.PathParamDeserializer; +import com.palantir.conjure.java.undertow.lib.Deserializer; +import com.palantir.conjure.java.undertow.lib.Endpoint; +import com.palantir.conjure.java.undertow.lib.UndertowRuntime; +import com.palantir.conjure.java.undertow.lib.UndertowService; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import io.undertow.util.Methods; +import io.undertow.util.StatusCodes; +import java.lang.Exception; +import java.lang.Override; +import java.lang.String; +import java.util.List; +import javax.annotation.processing.Generated; + +@Generated("com.palantir.conjure.java.undertow.processor.generate.ConjureUndertowEndpointsGenerator") +public final class OfFactoryEndpoints implements UndertowService { + private final OfFactory delegate; + + private OfFactoryEndpoints(OfFactory delegate) { + this.delegate = delegate; + } + + public static UndertowService of(OfFactory delegate) { + return new OfFactoryEndpoints(delegate); + } + + @Override + public List endpoints(UndertowRuntime runtime) { + return ImmutableList.of(new PingEndpoint(runtime, delegate)); + } + + private static final class PingEndpoint implements HttpHandler, Endpoint { + private final UndertowRuntime runtime; + + private final OfFactory delegate; + + private final Deserializer pathVarDeserializer; + + PingEndpoint(UndertowRuntime runtime, OfFactory delegate) { + this.runtime = runtime; + this.delegate = delegate; + this.pathVarDeserializer = new PathParamDeserializer<>( + "pathVar", ParamDecoders.complexParamDecoder(runtime.plainSerDe(), OfFactory.PathVariable::of)); + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + OfFactory.PathVariable pathVar = this.pathVarDeserializer.deserialize(exchange); + this.delegate.ping(pathVar); + exchange.setStatusCode(StatusCodes.NO_CONTENT); + } + + @Override + public HttpString method() { + return Methods.GET; + } + + @Override + public String template() { + return "/{pathVar}"; + } + + @Override + public String serviceName() { + return "OfFactory"; + } + + @Override + public String name() { + return "ping"; + } + + @Override + public HttpHandler handler() { + return this; + } + } +}