Skip to content

Commit

Permalink
Merge pull request OpenAPITools#20 from tvallin/helidon-generators
Browse files Browse the repository at this point in the history
Java Helidon Server MP Basic generator
  • Loading branch information
tvallin authored May 26, 2022
2 parents 4f9fcf7 + 6055f5e commit 03da8ee
Show file tree
Hide file tree
Showing 46 changed files with 1,338 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public abstract class JavaHelidonCommonCodegen extends AbstractJavaCodegen
static final String HELIDON_SE = "se";

static final String MICROPROFILE_REST_CLIENT_DEFAULT_ROOT_PACKAGE = "javax";
static final String HELIDON_NIMA = "nima";
static final String HELIDON_NIMA_ANNOTATIONS = "nima-annotations";

static final String MICROPROFILE_ROOT_PACKAGE_PROPERTY = "rootJavaEEPackage";

static final String SERIALIZATION_LIBRARY_JACKSON = "jackson";
static final String SERIALIZATION_LIBRARY_JSONB = "jsonb";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,74 @@

package org.openapitools.codegen.languages;

import io.swagger.v3.oas.models.media.Schema;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.meta.features.DocumentationFeature;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.OperationsMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JavaHelidonServerCodegen extends JavaHelidonCommonCodegen {

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

protected String serializationLibrary = null;

public JavaHelidonServerCodegen() {
modifyFeatureSet(features -> features.includeDocumentationFeatures(DocumentationFeature.Readme));

outputFolder = "generated-code" + File.separator + "java";
templateDir = "java-helidon" + File.separator + "server";
embeddedTemplateDir = "java-helidon" + File.separator + "common";
invokerPackage = "org.openapitools.server";
artifactId = "openapi-java-server";
apiPackage = invokerPackage + ".api";
modelPackage = invokerPackage + ".model";

updateOption(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
updateOption(CodegenConstants.ARTIFACT_ID, artifactId);
updateOption(CodegenConstants.API_PACKAGE, apiPackage);
updateOption(CodegenConstants.MODEL_PACKAGE, modelPackage);

modelTestTemplateFiles.put("model_test.mustache", ".java");

cliOptions.add(CliOption.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations"));
cliOptions.add(CliOption.newBoolean(PERFORM_BEANVALIDATION, "Perform BeanValidation"));

supportedLibraries.put(HELIDON_MP, "Helidon MP Server");
supportedLibraries.put(HELIDON_SE, "Helidon SE Server");
supportedLibraries.put(HELIDON_NIMA, "Helidon NIMA Server");
supportedLibraries.put(HELIDON_NIMA_ANNOTATIONS, "Helidon NIMA Annotations Server");

CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY,
"library template (sub-template) to use");
libraryOption.setEnum(supportedLibraries);
libraryOption.setDefault(HELIDON_MP);
cliOptions.add(libraryOption);
setLibrary(HELIDON_MP);

CliOption serializationLibrary = new CliOption(CodegenConstants.SERIALIZATION_LIBRARY,
"Serialization library, defaults to Jackson");
Map<String, String> serializationOptions = new HashMap<>();
serializationOptions.put(SERIALIZATION_LIBRARY_JACKSON, "Use Jackson as serialization library");
serializationOptions.put(SERIALIZATION_LIBRARY_JSONB, "Use JSON-B as serialization library");
serializationLibrary.setEnum(serializationOptions);
cliOptions.add(serializationLibrary);
setSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);

this.setLegacyDiscriminatorBehavior(false);
}

@Override
public void setUseBeanValidation(boolean useBeanValidation) {
throw new UnsupportedOperationException("Not implemented");
Expand All @@ -27,4 +93,125 @@ public void setUseBeanValidation(boolean useBeanValidation) {
public void setPerformBeanValidation(boolean performBeanValidation) {
throw new UnsupportedOperationException("Not implemented");
}

@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}

@Override
public String getName() {
return "java-helidon-server";
}

@Override
public String getHelp() {
return "Generates a Helidon MP or SE server";
}

@Override
public void processOpts() {
super.processOpts();
supportingFiles.clear();

if (!additionalProperties.containsKey(MICROPROFILE_ROOT_PACKAGE_PROPERTY)) {
additionalProperties.put(MICROPROFILE_ROOT_PACKAGE_PROPERTY, MICROPROFILE_REST_CLIENT_DEFAULT_ROOT_PACKAGE);
}

if (additionalProperties.containsKey(CodegenConstants.SERIALIZATION_LIBRARY)) {
setSerializationLibrary(additionalProperties.get(CodegenConstants.SERIALIZATION_LIBRARY).toString());
}

String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/");

if (additionalProperties.containsKey("jsr310") && isLibrary(HELIDON_MP)) {
supportingFiles.add(new SupportingFile("JavaTimeFormatter.mustache", invokerFolder, "JavaTimeFormatter.java"));
}

if (isLibrary(HELIDON_MP)) {
String apiExceptionFolder = (sourceFolder + File.separator
+ apiPackage().replace('.', File.separatorChar)).replace('/', File.separatorChar);
String resourceFolder = "src" + File.separator + "main" + File.separator + "resources";
String metaInfFolder = resourceFolder + File.separator + "META-INF";
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
//supportingFiles.add(new SupportingFile("api_exception.mustache", apiExceptionFolder, "ApiException.java"));
//supportingFiles.add(new SupportingFile("api_exception_mapper.mustache", apiExceptionFolder, "ApiExceptionMapper.java"));
supportingFiles.add(new SupportingFile("RestApplication.mustache", invokerFolder, "RestApplication.java"));
supportingFiles.add(new SupportingFile("logging.properties.mustache", resourceFolder, "logging.properties"));
supportingFiles.add(new SupportingFile("microprofile-config.properties.mustache", metaInfFolder, "microprofile-config.properties"));
supportingFiles.add(new SupportingFile("beans.xml.mustache", metaInfFolder, "beans.xml"));
} else if (isLibrary(HELIDON_SE)) {
throw new UnsupportedOperationException("Not implemented");
} else if (isLibrary(HELIDON_NIMA)) {
throw new UnsupportedOperationException("Not implemented");
} else if (isLibrary(HELIDON_NIMA_ANNOTATIONS)) {
throw new UnsupportedOperationException("Not implemented");
} else {
LOGGER.error("Unknown library option (-l/--library): {}", getLibrary());
}

if (getSerializationLibrary() == null) {
LOGGER.info("No serializationLibrary configured, using '{}' as fallback", SERIALIZATION_LIBRARY_JACKSON);
setSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
}
switch (getSerializationLibrary()) {
case SERIALIZATION_LIBRARY_JACKSON:
additionalProperties.put(SERIALIZATION_LIBRARY_JACKSON, "true");
additionalProperties.remove(SERIALIZATION_LIBRARY_JSONB);
supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache", invokerFolder, "RFC3339DateFormat.java"));
break;
case SERIALIZATION_LIBRARY_JSONB:
additionalProperties.put(SERIALIZATION_LIBRARY_JSONB, "true");
additionalProperties.remove(SERIALIZATION_LIBRARY_JACKSON);
break;
default:
additionalProperties.remove(SERIALIZATION_LIBRARY_JACKSON);
additionalProperties.remove(SERIALIZATION_LIBRARY_JSONB);
LOGGER.error("Unknown serialization library option");
break;
}
}

@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
super.postProcessOperationsWithModels(objs, allModels);
if (HELIDON_MP.equals(getLibrary())) {
return AbstractJavaJAXRSServerCodegen.jaxrsPostProcessOperations(objs);
} else {
throw new UnsupportedOperationException("Not implemented");
}
}

@Override
public CodegenModel fromModel(String name, Schema model) {
CodegenModel codegenModel = super.fromModel(name, model);
if (HELIDON_MP.equals(getLibrary())) {
// Remove io.swagger.annotations.ApiModel import
codegenModel.imports.remove("ApiModel");
codegenModel.imports.remove("ApiModelProperty");
}
return codegenModel;
}

@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
generateYAMLSpecFile(objs);
return super.postProcessSupportingFileData(objs);
}

public String getSerializationLibrary() {
return serializationLibrary;
}

public void setSerializationLibrary(String serializationLibrary) {
if (SERIALIZATION_LIBRARY_JACKSON.equalsIgnoreCase(serializationLibrary)) {
this.serializationLibrary = SERIALIZATION_LIBRARY_JACKSON;
} else if (SERIALIZATION_LIBRARY_JSONB.equalsIgnoreCase(serializationLibrary)) {
this.serializationLibrary = SERIALIZATION_LIBRARY_JSONB;
} else {
throw new IllegalArgumentException("Unexpected serializationLibrary value: " + serializationLibrary);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ org.openapitools.codegen.languages.HaskellYesodServerCodegen
org.openapitools.codegen.languages.JavaClientCodegen
org.openapitools.codegen.languages.JavaCXFClientCodegen
org.openapitools.codegen.languages.JavaHelidonClientCodegen
org.openapitools.codegen.languages.JavaHelidonServerCodegen
org.openapitools.codegen.languages.JavaInflectorServerCodegen
org.openapitools.codegen.languages.JavaMicronautClientCodegen
org.openapitools.codegen.languages.JavaMicronautServerCodegen
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{{>licenseInfo}}
package {{invokerPackage}};

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

/**
* Class that add parsing/formatting support for Java 8+ {@code OffsetDateTime} class.
* It's generated for java clients when {@code AbstractJavaCodegen#dateLibrary} specified as {@code java8}.
*/
{{>generatedAnnotation}}
public class JavaTimeFormatter {
private DateTimeFormatter offsetDateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
/**
* Get the date format used to parse/format {@code OffsetDateTime} parameters.
* @return DateTimeFormatter
*/
public DateTimeFormatter getOffsetDateTimeFormatter() {
return offsetDateTimeFormatter;
}

/**
* Set the date format used to parse/format {@code OffsetDateTime} parameters.
* @param offsetDateTimeFormatter {@code DateTimeFormatter}
*/
public void setOffsetDateTimeFormatter(DateTimeFormatter offsetDateTimeFormatter) {
this.offsetDateTimeFormatter = offsetDateTimeFormatter;
}

/**
* Parse the given string into {@code OffsetDateTime} object.
* @param str String
* @return {@code OffsetDateTime}
*/
public OffsetDateTime parseOffsetDateTime(String str) {
try {
return OffsetDateTime.parse(str, offsetDateTimeFormatter);
} catch (DateTimeParseException e) {
throw new RuntimeException(e);
}
}
/**
* Format the given {@code OffsetDateTime} object into string.
* @param offsetDateTime {@code OffsetDateTime}
* @return {@code OffsetDateTime} in string format
*/
public String formatOffsetDateTime(OffsetDateTime offsetDateTime) {
return offsetDateTimeFormatter.format(offsetDateTime);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{{>licenseInfo}}
package {{invokerPackage}};

import com.fasterxml.jackson.databind.util.StdDateFormat;

import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class RFC3339DateFormat extends DateFormat {
private static final long serialVersionUID = 1L;
private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC");
private final StdDateFormat fmt = new StdDateFormat()
.withTimeZone(TIMEZONE_Z)
.withColonInTimeZone(true);
public RFC3339DateFormat() {
this.calendar = new GregorianCalendar();
}

@Override
public Date parse(String source, ParsePosition pos) {
return fmt.parse(source, pos);
}

@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
return fmt.format(date, toAppendTo, fieldPosition);
}

@Override
public Object clone() {
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package {{invokerPackage}};

import {{rootJavaEEPackage}}.enterprise.context.ApplicationScoped;
import {{rootJavaEEPackage}}.ws.rs.ApplicationPath;
import {{rootJavaEEPackage}}.ws.rs.core.Application;

@ApplicationScoped
@ApplicationPath("{{{contextPath}}}")
public class RestApplication extends Application {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{{>licenseInfo}}

package {{invokerPackage}};

import java.util.Collection;
import java.util.Iterator;

{{>generatedAnnotation}}
public class StringUtil {
/**
* Check if the given array contains the given value (with case-insensitive comparison).
*
* @param array The array
* @param value The value to search
* @return true if the array contains the value
*/
public static boolean containsIgnoreCase(String[] array, String value) {
for (String str : array) {
if (value == null && str == null) {
return true;
}
if (value != null && value.equalsIgnoreCase(str)) {
return true;
}
}
return false;
}

/**
* Join an array of strings with the given separator.
* <p>
* Note: This might be replaced by utility method from commons-lang or guava someday
* if one of those libraries is added as dependency.
* </p>
*
* @param array The array of strings
* @param separator The separator
* @return the resulting string
*/
public static String join(String[] array, String separator) {
int len = array.length;
if (len == 0) {
return "";
}

StringBuilder out = new StringBuilder();
out.append(array[0]);
for (int i = 1; i < len; i++) {
out.append(separator).append(array[i]);
}
return out.toString();
}

/**
* Join a list of strings with the given separator.
*
* @param list The list of strings
* @param separator The separator
* @return the resulting string
*/
public static String join(Collection<String> list, String separator) {
Iterator<String> iterator = list.iterator();
StringBuilder out = new StringBuilder();
if (iterator.hasNext()) {
out.append(iterator.next());
}
while (iterator.hasNext()) {
out.append(separator).append(iterator.next());
}
return out.toString();
}
}
Loading

0 comments on commit 03da8ee

Please sign in to comment.