Skip to content

Commit

Permalink
[Server MP] REST API files only + class/interface implementation (Ope…
Browse files Browse the repository at this point in the history
  • Loading branch information
tvallin authored Sep 7, 2022
1 parent 74cb874 commit 2a217a2
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public class JavaHelidonServerCodegen extends JavaHelidonCommonCodegen {

private final Logger LOGGER = LoggerFactory.getLogger(JavaHelidonServerCodegen.class);

//TODO remove it if MP does not support it
public static final String INTERFACE_ONLY = "interfaceOnly";
public static final String USE_ABSTRACT_CLASS = "useAbstractClass";
public static final String GRADLE_PROJECT = "gradleProject";
Expand All @@ -59,7 +58,6 @@ public class JavaHelidonServerCodegen extends JavaHelidonCommonCodegen {
protected String implFolder = "src/main/java";
protected String serializationLibrary = null;

//TODO remove it if MP does not support it
private boolean interfaceOnly = false;
private boolean useAbstractClass = false;
private boolean gradleProject = false;
Expand Down Expand Up @@ -138,6 +136,7 @@ public void processOpts() {
supportingFiles.clear();
dateLibrary = "java8";

addApiTemplateFiles();
SupportingFile pomFile = new SupportingFile("pom.mustache", "", "pom.xml");
SupportingFile readmeFile = new SupportingFile("README.mustache", "", "README.md");
SupportingFile openApiFile = new SupportingFile("openapi.mustache",
Expand Down Expand Up @@ -183,6 +182,10 @@ public void processOpts() {
}
if (!gradleProject) {
additionalProperties.remove(GRADLE_PROJECT);
} else {
modifiable.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
modifiable.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
modifiable.remove(pomFile);
}

if (!additionalProperties.containsKey(MICROPROFILE_ROOT_PACKAGE)) {
Expand Down Expand Up @@ -210,9 +213,6 @@ public void processOpts() {
} else if (isLibrary(HELIDON_SE)) {
artifactId = "openapi-helidon-se-server";

//TODO move this lines from this clause if MP will support it
addApiTemplateFiles();

modifiable.add(new SupportingFile("application.mustache",
("src.main.resources").replace(".", java.io.File.separator), "application.yaml"));
modifiable.add(new SupportingFile("mainTest.mustache",
Expand All @@ -237,12 +237,6 @@ public void processOpts() {
importMapping.put("ByteArrayInputStream", "java.io.ByteArrayInputStream");
}
importMapping.put("Handler", "io.helidon.webserver.Handler");
//TODO after adding gradle support for Helidon MP move these lines from this clause to the top of the method
if (gradleProject) {
modifiable.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
modifiable.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
modifiable.remove(pomFile);
}
processSupportingFiles(modifiable, unmodifiable);
} else if (isLibrary(HELIDON_NIMA)) {
throw new UnsupportedOperationException("Not implemented");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import javax.validation.Valid;{{/useBeanValidation}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}
{{>generatedAnnotation}}
public {{#interfaceOnly}}interface{{/interfaceOnly}}{{^interfaceOnly}}{{^fullProject}}abstract {{/fullProject}}class{{/interfaceOnly}} {{classname}} {
public {{#interfaceOnly}}interface{{/interfaceOnly}}{{^interfaceOnly}}{{#useAbstractClass}}abstract {{/useAbstractClass}}class{{/interfaceOnly}} {{classname}} {
{{#operations}}
{{#operation}}

{{#interfaceOnly}}{{>apiAbstract}}{{/interfaceOnly}}{{^interfaceOnly}}{{^fullProject}}{{>apiAbstract}}{{/fullProject}}{{#fullProject}}{{>apiMethod}}{{/fullProject}}{{/interfaceOnly}}
{{#interfaceOnly}}{{>apiAbstract}}{{/interfaceOnly}}{{^interfaceOnly}}{{#useAbstractClass}}{{>apiAbstract}}{{/useAbstractClass}}{{^useAbstractClass}}{{>apiMethod}}{{/useAbstractClass}}{{/interfaceOnly}}
{{/operation}}
}
{{/operations}}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
@Path("{{{path}}}"){{/subresourceOperation}}{{#hasConsumes}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}
abstract {{#supportAsync}}{{>returnAsyncTypeInterface}}{{/supportAsync}}{{^supportAsync}}{{#returnResponse}}Response{{/returnResponse}}{{^returnResponse}}{{{returnType}}}{{/returnResponse}}{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>cookieParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}});
abstract {{#supportAsync}}{{>returnAsyncTypeInterface}}{{/supportAsync}}{{^supportAsync}}Response{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>cookieParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}});
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{{>licenseInfo}}
package {{package}};

{{#imports}}import {{import}};
{{/imports}}

import {{rootJavaEEPackage}}.ws.rs.*;
import {{rootJavaEEPackage}}.ws.rs.core.Response;

{{#supportAsync}}
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
{{/supportAsync}}

import java.io.InputStream;
import java.util.Map;
import java.util.List;
{{#useBeanValidation}}import javax.validation.constraints.*;
import javax.validation.Valid;{{/useBeanValidation}}

@Path("{{commonPath}}"){{#hasConsumes}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}
{{>generatedAnnotation}}
public class {{classname}}Impl {{#interfaceOnly}}implements{{/interfaceOnly}}{{^interfaceOnly}}extends{{/interfaceOnly}} {{classname}} {
{{#operations}}
{{#operation}}

{{>apiMethod}}
{{/operation}}
}
{{/operations}}
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package org.openapitools.codegen.java.helidon;

import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.java.assertions.JavaFileAssert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

public class JavaHelidonMpServerCodegenTest {

Expand All @@ -37,19 +41,29 @@ private CodegenConfigurator createConfigurator() {

private void generate(CodegenConfigurator config) {
generator.opts(config.toClientOptInput());
generator.setGenerateMetadata(false);
generator.generate();
}

private void generate() {
generate(createConfigurator());
}

//TODO remove it or change after MP implements new fullProject option
@Ignore
@Test
public void testAbstractClass() {
public void testRestApiFilesOnly() {
generate(createConfigurator().addAdditionalProperty("fullProject", "false"));

JavaFileAssert.assertThat(Paths.get(apiPackage + "/PetService.java"))
.fileContains("public class PetService");

File outputFile = Paths.get(outputPath).toFile();
assertThat(Objects.requireNonNull(outputFile.listFiles()).length, is(1));
}

@Test
public void testAbstractClass() {
generate(createConfigurator().addAdditionalProperty("useAbstractClass", "true"));

JavaFileAssert.assertThat(Paths.get(apiPackage + "/PetService.java"))
.fileContains("public abstract class PetService")
.assertMethod("addPet", "Pet")
Expand All @@ -59,7 +73,13 @@ public void testAbstractClass() {
.fileContains("public abstract class StoreService")
.assertMethod("placeOrder", "Order")
.doesNotHaveImplementation()
.hasReturnType("Order");
.hasReturnType("Response");

JavaFileAssert.assertThat(Paths.get(apiPackage + "/StoreServiceImpl.java"))
.fileContains("public class StoreServiceImpl extends StoreService")
.assertMethod("placeOrder", "Order")
.hasReturnType("Response")
.bodyContainsLines("return Response.ok().entity(\"magic!\").build();");
}

@Test
Expand Down Expand Up @@ -152,7 +172,22 @@ public void doGenerateInterfaceOnly() {
.fileContains("public interface StoreService")
.assertMethod("placeOrder", "Order")
.doesNotHaveImplementation()
.hasReturnType("Order");
.hasReturnType("Response");

JavaFileAssert.assertThat(Paths.get(apiPackage + "/StoreServiceImpl.java"))
.fileContains("public class StoreServiceImpl implements StoreService")
.assertMethod("placeOrder", "Order")
.hasReturnType("Response")
.bodyContainsLines("return Response.ok().entity(\"magic!\").build();");
}

@Test
public void testGenerateGradleProject() {
generate(createConfigurator().addAdditionalProperty("gradleProject", "true"));

assertThat(Paths.get(outputPath + "/build.gradle").toFile().exists(), is(true));
assertThat(Paths.get(outputPath + "/settings.gradle").toFile().exists(), is(true));
TestUtils.assertFileNotExists(Paths.get(outputPath + "/pom.xml"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.stream.Stream;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;

public class FunctionalHelidonMPServerTest extends FunctionalBase {
Expand All @@ -48,11 +52,9 @@ void buildProjectInterfaceOnly() {
buildAndVerify("target/openapi-java-server.jar");
}

//TODO remove it or change after MP implements new fullProject option
@Ignore
@Test
void buildProjectAbstractClasses() {
generate(createConfigurator().addAdditionalProperty(FULL_PROJECT, "false"));
generate(createConfigurator().addAdditionalProperty(USE_ABSTRACT_CLASS, "true"));
buildAndVerify("target/openapi-java-server.jar");
}

Expand All @@ -61,4 +63,32 @@ void buildFullProject() {
generate(createConfigurator().addAdditionalProperty(FULL_PROJECT, "true"));
buildAndVerify("target/openapi-java-server.jar");
}

@Test
void verifyFullProjectSemantics() {
// Generate project for first time and record pom's timestamp
generate(createConfigurator());
buildAndVerify("target/openapi-java-server.jar");
Path pom1 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom1), is(true));
long lastModified = pom1.toFile().lastModified();

// Re-generate project over same directory with fullProject unspecified
generate(createConfigurator(outputPath));
Path pom2 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom2), is(true));
assertThat(pom2.toFile().lastModified(), is(lastModified)); // not overwritten

// Re-generate project over same directory with fullProject false
generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "false"));
Path pom3 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom3), is(true));
assertThat(pom3.toFile().lastModified(), is(lastModified)); // not overwritten

// Re-generate project over same directory with fullProject true
generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "true"));
Path pom4 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom4), is(true));
assertThat(pom4.toFile().lastModified(), is(not(lastModified))); // overwritten
}
}

0 comments on commit 2a217a2

Please sign in to comment.