Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to wrap return type in a generic class #295

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class JaxRsProjectSettings {
public String javaPackage = "org.example.api";
public String classNamePrefix = "";
public String classNameSuffix = "";
public String genericReturnType = null;

/**
* Constructor.
Expand Down Expand Up @@ -167,4 +168,12 @@ public String getClassNameSuffix() {
public void setClassNameSuffix(String classNameSuffix) {
this.classNameSuffix = classNameSuffix;
}

public String getGenericReturnType() {
return genericReturnType;
}

public void setGenericReturnType(String genericReturnType) {
this.genericReturnType = genericReturnType;
}
}
36 changes: 28 additions & 8 deletions core/src/main/java/io/apicurio/hub/api/codegen/OpenApi2JaxRs.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -552,16 +551,19 @@ protected String generateJavaInterface(CodegenInfo info, CodegenJavaInterface in
reactive = Boolean.TRUE.equals(methodInfo.getAsync());
}

final String genericReturnType = getSettings().genericReturnType;

Optional.ofNullable(methodInfo.getReturn())
.map(rt -> generateTypeName(
rt,
true,
String.format("%s.ws.rs.core.Response", topLevelPackage)))
.map(rt -> generateGenericReturnType(rt, genericReturnType))
.map(rt -> reactive ? generateReactiveTypeName(rt) : rt)
.map(Object::toString)
.ifPresentOrElse(
operationMethod::setReturnType,
() -> setVoidReturnType(operationMethod, reactive));
() -> setVoidReturnType(operationMethod, reactive, genericReturnType));

Optional.ofNullable(methodInfo.getArguments())
.map(Collection::stream)
Expand Down Expand Up @@ -751,12 +753,17 @@ protected Type<?> generateTypeName(CodegenJavaSchema schema, Boolean required, S
return parseType(defaultType);
}

protected void setVoidReturnType(MethodSource<JavaInterfaceSource> operationMethod, boolean reactive) {
if (reactive) {
operationMethod.setReturnType(generateReactiveTypeName(VOID));
} else {
operationMethod.setReturnTypeVoid();
}
protected void setVoidReturnType(MethodSource<JavaInterfaceSource> operationMethod, boolean reactive, String genericReturnType) {
Optional.of(VOID)
.map(type -> generateGenericReturnType(type, genericReturnType))
.map(type -> reactive ? generateReactiveTypeName(type) : type)
.ifPresent(type -> {
if (type != VOID) {
operationMethod.setReturnType(type);
} else {
operationMethod.setReturnTypeVoid();
}
});
}

/**
Expand All @@ -769,6 +776,19 @@ protected Type<?> generateReactiveTypeName(Type<?> coreType) {
return parseType(String.format("java.util.concurrent.CompletionStage<%s>", coreType.toString()));
}

/**
* Generates the generic type wrapping response type.
*
* @param coreType
* @param genericReturnType
*/
private Type<?> generateGenericReturnType(Type<?> coreType, String genericReturnType) {
if (genericReturnType == null) {
return coreType;
}
return parseType(String.format("%s<%s>", genericReturnType, coreType.toString()));
}

/**
* Converts a set of strings into an array literal format.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ private static enum Reactive {
*/
@Test
public void testGenerateFull() throws IOException {
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, "_expected-full/generated-api", false);
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, null, "_expected-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFullPrefixed() throws IOException {
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, false,
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, null, false,
"_expected-full-prefixed/generated-api", "Test", "", false);
}

Expand All @@ -54,7 +54,7 @@ public void testGenerateFullPrefixed() throws IOException {
*/
@Test
public void testGenerateFullSuffixed() throws IOException {
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, false,
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, null, false,
"_expected-full-suffixed/generated-api", "", "Test", false);
}

Expand All @@ -63,47 +63,63 @@ public void testGenerateFullSuffixed() throws IOException {
*/
@Test
public void testGenerateFull_GatewayApi() throws IOException {
doFullTest("OpenApi2JaxRsTest/gateway-api.json", UpdateOnly.no, Reactive.no, "_expected-gatewayApi-full/generated-api", false);
doFullTest("OpenApi2JaxRsTest/gateway-api.json", UpdateOnly.no, Reactive.no, null, "_expected-gatewayApi-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_RegistryApi() throws IOException {
doFullTest("OpenApi2JaxRsTest/registry-api.json", UpdateOnly.no, Reactive.no, "_expected-registryApi-full/generated-api", false);
doFullTest("OpenApi2JaxRsTest/registry-api.json", UpdateOnly.no, Reactive.no, null, "_expected-registryApi-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_RegistryApiV2() throws IOException {
doFullTest("OpenApi2JaxRsTest/registry-api-v2.json", UpdateOnly.yes, Reactive.no, "_expected-registry-api-v2/generated-api", false);
doFullTest("OpenApi2JaxRsTest/registry-api-v2.json", UpdateOnly.yes, Reactive.no, null, "_expected-registry-api-v2/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateUpdateOnly() throws IOException {
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.yes, Reactive.no, "_expected-full/generated-api", false);
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.yes, Reactive.no, null, "_expected-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFullReactive() throws IOException {
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.yes, "_expected-reactive-full/generated-api", false);
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.yes, null, "_expected-reactive-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFullGenericReturnType() throws IOException {
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, "org.jboss.resteasy.reactive.RestResponse", "_expected-genericReturnType-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFullGenericReturnTypeReactive() throws IOException {
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.yes, "org.jboss.resteasy.reactive.RestResponse", "_expected-genericReturnTypeReactive-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateWithCLIGenCI() throws IOException {
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, true,
doFullTest("OpenApi2JaxRsTest/beer-api.json", UpdateOnly.no, Reactive.no, null, true,
"_expected-full-with-ci/generated-api", "", "", false);
}

Expand All @@ -113,124 +129,127 @@ public void testGenerateWithCLIGenCI() throws IOException {
@Test
public void testGenerateFull_Issue885Api() throws IOException {
// Note: I can't seem to get this working in the maven build, but it works in Eclipse.
doFullTest("OpenApi2JaxRsTest/issue-885-api.json", UpdateOnly.no, Reactive.no, "_expected-issue885Api-full/generated-api", false);
doFullTest("OpenApi2JaxRsTest/issue-885-api.json", UpdateOnly.no, Reactive.no, null, "_expected-issue885Api-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_MultipleMediaTypes() throws IOException {
doFullTest("OpenApi2JaxRsTest/mmt-api.json", UpdateOnly.no, Reactive.no, "_expected-mmt-full/generated-api", false);
doFullTest("OpenApi2JaxRsTest/mmt-api.json", UpdateOnly.no, Reactive.no, null, "_expected-mmt-full/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_ContextRoot() throws IOException {
doFullTest("OpenApi2JaxRsTest/context-root.json", UpdateOnly.no, Reactive.no, "_expected-context-root/generated-api", false);
doFullTest("OpenApi2JaxRsTest/context-root.json", UpdateOnly.no, Reactive.no, null, "_expected-context-root/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_SimpleType() throws IOException {
doFullTest("OpenApi2JaxRsTest/simple-type.json", UpdateOnly.no, Reactive.no, "_expected-simple-type/generated-api", false);
doFullTest("OpenApi2JaxRsTest/simple-type.json", UpdateOnly.no, Reactive.no, null, "_expected-simple-type/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_BeanAnnotations() throws IOException {
doFullTest("OpenApi2JaxRsTest/bean-annotations.json", UpdateOnly.no, Reactive.no, "_expected-bean-annotations/generated-api", false);
doFullTest("OpenApi2JaxRsTest/bean-annotations.json", UpdateOnly.no, Reactive.no, null, "_expected-bean-annotations/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_Inheritance() throws IOException {
doFullTest("OpenApi2JaxRsTest/inheritance.json", UpdateOnly.yes, Reactive.no, "_expected-inheritance/generated-api", false);
doFullTest("OpenApi2JaxRsTest/inheritance.json", UpdateOnly.yes, Reactive.no, null, "_expected-inheritance/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_NZDAX() throws IOException {
doFullTest("OpenApi2JaxRsTest/nzdax.json", UpdateOnly.yes, Reactive.no, "_expected-nzdax/generated-api", false);
doFullTest("OpenApi2JaxRsTest/nzdax.json", UpdateOnly.yes, Reactive.no, null, "_expected-nzdax/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testGenerateFull_CustomResponseType() throws IOException {
doFullTest("OpenApi2JaxRsTest/custom-response-type.json", UpdateOnly.yes, Reactive.no, "_expected-custom-response-type/generated-api", false);
doFullTest("OpenApi2JaxRsTest/custom-response-type.json", UpdateOnly.yes, Reactive.no, null, "_expected-custom-response-type/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testSchemaExtends() throws IOException {
doFullTest("OpenApi2JaxRsTest/schema-extends.json", UpdateOnly.yes, Reactive.no, "_expected-schema-extends/generated-api", false);
doFullTest("OpenApi2JaxRsTest/schema-extends.json", UpdateOnly.yes, Reactive.no, null, "_expected-schema-extends/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testMasStudio() throws IOException {
doFullTest("OpenApi2JaxRsTest/mas-studio.json", UpdateOnly.no, Reactive.no, "_expected-mas-studio/generated-api", false);
doFullTest("OpenApi2JaxRsTest/mas-studio.json", UpdateOnly.no, Reactive.no, null, "_expected-mas-studio/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testPetStore() throws IOException {
doFullTest("OpenApi2JaxRsTest/petstore-openapi.json", UpdateOnly.no, Reactive.no, "_expected-petstore/generated-api", false);
doFullTest("OpenApi2JaxRsTest/petstore-openapi.json", UpdateOnly.no, Reactive.no, null, "_expected-petstore/generated-api", false);
}

/**
* Test method for {@link io.apicurio.hub.api.codegen.OpenApi2JaxRs#generate()}.
*/
@Test
public void testConstraintParameters() throws IOException {
doFullTest("OpenApi2JaxRsTest/constrained-parameters.json", UpdateOnly.no, Reactive.no, "_expected-constrained-parameters/generated-api", false);
doFullTest("OpenApi2JaxRsTest/constrained-parameters.json", UpdateOnly.no, Reactive.no, null, "_expected-constrained-parameters/generated-api", false);
}

/**
* Shared test method.
* @param apiDef
* @param updateOnly
* @param reactive
* @param genericReturnType
* @param expectedFilesPath
* @param debug
* @throws IOException
*/
private void doFullTest(String apiDef, UpdateOnly updateOnly, Reactive reactive, String expectedFilesPath, boolean debug) throws IOException {
doFullTest(apiDef, updateOnly, reactive, false, expectedFilesPath, "", "", debug);
private void doFullTest(String apiDef, UpdateOnly updateOnly, Reactive reactive, String genericReturnType, String expectedFilesPath, boolean debug) throws IOException {
doFullTest(apiDef, updateOnly, reactive, genericReturnType, false, expectedFilesPath, "", "", debug);
}

/**
* Shared test method.
*
* @param apiDef
* @param updateOnly
* @param reactive
* @param genericReturnType
* @param generateCLiGenCI
* @param expectedFilesPath
* @param namePrefix
* @param nameSuffix
* @param debug
* @throws IOException
*/
private void doFullTest(String apiDef, UpdateOnly updateOnly, Reactive reactive, boolean generateCLiGenCI,
String expectedFilesPath, String namePrefix, String nameSuffix, boolean debug) throws IOException {
private void doFullTest(String apiDef, UpdateOnly updateOnly, Reactive reactive, String genericReturnType, boolean generateCLiGenCI,
String expectedFilesPath, String namePrefix, String nameSuffix, boolean debug) throws IOException {
JaxRsProjectSettings settings = new JaxRsProjectSettings();
settings.codeOnly = false;
settings.reactive = reactive == Reactive.yes;
Expand All @@ -240,6 +259,7 @@ private void doFullTest(String apiDef, UpdateOnly updateOnly, Reactive reactive,
settings.javaPackage = "org.example.api";
settings.classNamePrefix = namePrefix;
settings.classNameSuffix = nameSuffix;
settings.genericReturnType = genericReturnType;

OpenApi2JaxRs generator = new OpenApi2JaxRs();
generator.setSettings(settings);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example.api</groupId>
<artifactId>generated-api</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Beer API</name>
<description>The official Beer API! Search for both beers and breweries.</description>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<version.jakarta.ws.rs-jakarta.ws.rs-api>3.1.0</version.jakarta.ws.rs-jakarta.ws.rs-api>
<version.jakarta.validation-jakarta.validation-api>3.0.2</version.jakarta.validation-jakarta.validation-api>
<version.jakarta.enterprise-jakarta.enterprise.cdi-api>4.0.1</version.jakarta.enterprise-jakarta.enterprise.cdi-api>
<version.com.fasterxml.jackson>2.15.1</version.com.fasterxml.jackson>
</properties>

<dependencies>
<!-- Third Party Dependencies -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${version.com.fasterxml.jackson}</version>
</dependency>
<!-- Specification Dependencies -->
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>${version.jakarta.ws.rs-jakarta.ws.rs-api}</version>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>${version.jakarta.enterprise-jakarta.enterprise.cdi-api}</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${version.jakarta.validation-jakarta.validation-api}</version>
</dependency>
</dependencies>
</project>
Loading