Skip to content

Commit 05b3ddd

Browse files
Merge pull request #1242 from altro3/generic-annotations-generator
Added generating generic annotations to generator.
2 parents 1304361 + 6a2603f commit 05b3ddd

27 files changed

+558
-73
lines changed

openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautJavaCodegen.java

+188-1
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,12 @@ protected AbstractMicronautJavaCodegen() {
231231
};
232232
reservedWords.addAll(Arrays.asList(reservedWordsArray));
233233

234+
importMapping.put("DateTime", "java.time.Instant");
234235
importMapping.put("LocalDateTime", "java.time.LocalDateTime");
235236
importMapping.put("OffsetDateTime", "java.time.OffsetDateTime");
236237
importMapping.put("ZonedDateTime", "java.time.ZonedDateTime");
237238
importMapping.put("LocalDate", "java.time.LocalDate");
239+
importMapping.put("LocalTime", "java.time.LocalTime");
238240
}
239241

240242
public void setGenerateHttpResponseAlways(boolean generateHttpResponseAlways) {
@@ -658,6 +660,14 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
658660
});
659661
op.formParams.clear();
660662
}
663+
664+
for (var param : op.allParams) {
665+
processGenericAnnotations(param);
666+
}
667+
if (op.returnProperty != null) {
668+
processGenericAnnotations(op.returnProperty);
669+
op.returnType = op.returnProperty.vendorExtensions.get("typeWithEnumWithGenericAnnotations").toString();
670+
}
661671
}
662672

663673
return objs;
@@ -682,6 +692,8 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
682692

683693
if (op.isResponseFile) {
684694
op.returnType = typeMapping.get("responseFile");
695+
op.returnProperty.dataType = op.returnType;
696+
op.returnProperty.datatypeWithEnum = op.returnType;
685697
op.imports.add(op.returnType);
686698
}
687699

@@ -800,14 +812,17 @@ private void wrapOperationReturnType(CodegenOperation op, String wrapperType, bo
800812
originalReturnType = "Void";
801813
op.returnProperty = new CodegenProperty();
802814
op.returnProperty.dataType = "Void";
815+
op.returnProperty.openApiType = "";
803816
}
804817
newReturnType.dataType = typeName + '<' + originalReturnType + '>';
805818
newReturnType.items = op.returnProperty;
806819
}
820+
newReturnType.containerTypeMapped = typeName;
821+
newReturnType.containerType = typeName;
807822
op.vendorExtensions.put("originalReturnType", originalReturnType);
808823

809824
op.returnType = newReturnType.dataType;
810-
op.returnContainer = null;
825+
op.returnContainer = newReturnType.containerTypeMapped;
811826
op.returnProperty = newReturnType;
812827
op.isArray = op.returnProperty.isArray;
813828
}
@@ -887,18 +902,190 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
887902
property.vendorExtensions.put("lombok", lombok);
888903
property.vendorExtensions.put("defaultValueIsNotNull", property.defaultValue != null && !property.defaultValue.equals("null"));
889904
property.vendorExtensions.put("isServer", isServer);
905+
processGenericAnnotations(property);
890906
}
891907
model.vendorExtensions.put("isServer", isServer);
892908
for (var property : model.requiredVars) {
893909
property.vendorExtensions.put("lombok", lombok);
894910
property.vendorExtensions.put("isServer", isServer);
895911
property.vendorExtensions.put("defaultValueIsNotNull", property.defaultValue != null && !property.defaultValue.equals("null"));
912+
processGenericAnnotations(property);
896913
}
897914
}
898915

899916
return objs;
900917
}
901918

919+
private void processGenericAnnotations(CodegenParameter parameter) {
920+
CodegenProperty items = parameter.isMap ? parameter.additionalProperties : parameter.items;
921+
String datatypeWithEnum = parameter.datatypeWithEnum == null ? parameter.dataType : parameter.datatypeWithEnum;
922+
processGenericAnnotations(parameter.dataType, datatypeWithEnum, parameter.isArray, parameter.isMap, parameter.containerTypeMapped, items, parameter.vendorExtensions);
923+
}
924+
925+
private void processGenericAnnotations(CodegenProperty property) {
926+
CodegenProperty items = property.isMap ? property.additionalProperties : property.items;
927+
String datatypeWithEnum = property.datatypeWithEnum == null ? property.dataType : property.datatypeWithEnum;
928+
processGenericAnnotations(property.dataType, datatypeWithEnum, property.isArray, property.isMap, property.containerTypeMapped, items, property.vendorExtensions);
929+
}
930+
931+
private void processGenericAnnotations(String dataType, String dataTypeWithEnum, boolean isArray, boolean isMap, String containerType, CodegenProperty itemsProp, Map<String, Object> ext) {
932+
var typeWithGenericAnnotations = dataType;
933+
var typeWithEnumWithGenericAnnotations = dataTypeWithEnum;
934+
if (useBeanValidation && itemsProp != null && dataType.contains("<")) {
935+
if (isMap) {
936+
var genericAnnotations = genericAnnotations(itemsProp);
937+
processGenericAnnotations(itemsProp);
938+
typeWithGenericAnnotations = "Map<String, " + genericAnnotations + itemsProp.vendorExtensions.get("typeWithGenericAnnotations") + ">";
939+
typeWithEnumWithGenericAnnotations = "Map<String, " + genericAnnotations + itemsProp.vendorExtensions.get("typeWithEnumWithGenericAnnotations") + ">";
940+
} else if (containerType != null) {
941+
var genericAnnotations = genericAnnotations(itemsProp);
942+
processGenericAnnotations(itemsProp);
943+
typeWithGenericAnnotations = containerType + "<" + genericAnnotations + itemsProp.vendorExtensions.get("typeWithGenericAnnotations") + ">";
944+
typeWithEnumWithGenericAnnotations = containerType + "<" + genericAnnotations + itemsProp.vendorExtensions.get("typeWithEnumWithGenericAnnotations") + ">";
945+
}
946+
}
947+
ext.put("typeWithGenericAnnotations", typeWithGenericAnnotations);
948+
ext.put("typeWithEnumWithGenericAnnotations", typeWithEnumWithGenericAnnotations);
949+
}
950+
951+
private boolean isPrimitive(String type) {
952+
if (type == null) {
953+
return false;
954+
}
955+
return switch (type) {
956+
case "array", "string", "boolean", "byte", "uri", "url", "uuid", "email", "integer", "long", "float", "double",
957+
"number", "partial-time", "date", "date-time", "bigdecimal", "biginteger" -> true;
958+
default -> false;
959+
};
960+
}
961+
962+
private String genericAnnotations(CodegenProperty prop) {
963+
964+
var type = prop.openApiType == null ? null : prop.openApiType.toLowerCase();
965+
966+
var result = new StringBuilder();
967+
968+
if (prop.isModel) {
969+
result.append("@Valid ");
970+
}
971+
if (!isPrimitive(type)) {
972+
return result.toString();
973+
}
974+
975+
if (StringUtils.isNotEmpty(prop.pattern)) {
976+
if ("email".equals(type)) {
977+
result.append("@Email(regexp = \"");
978+
} else {
979+
result.append("@Pattern(regexp = \"");
980+
}
981+
result.append(prop.pattern).append("\") ");
982+
}
983+
984+
var containsNotEmpty = false;
985+
986+
if (prop.minLength != null || prop.maxLength != null) {
987+
if (prop.minLength != null && prop.minLength == 1 && prop.maxLength == null && !prop.isNullable) {
988+
result.append("@NotEmpty ");
989+
containsNotEmpty = true;
990+
} else {
991+
result.append("@Size(");
992+
if (prop.minLength != null) {
993+
result.append("min = ").append(prop.minLength);
994+
}
995+
if (prop.maxLength != null) {
996+
if (prop.minLength != null) {
997+
result.append(", ");
998+
}
999+
result.append("max = ").append(prop.maxLength);
1000+
}
1001+
result.append(") ");
1002+
}
1003+
}
1004+
1005+
if (prop.minItems != null || prop.maxItems != null) {
1006+
if (prop.minItems != null && prop.minItems == 1 && prop.maxItems == null && !prop.isNullable) {
1007+
result.append("@NotEmpty ");
1008+
containsNotEmpty = true;
1009+
} else {
1010+
result.append("@Size(");
1011+
if (prop.minItems != null) {
1012+
result.append("min = ").append(prop.minItems);
1013+
}
1014+
if (prop.maxItems != null) {
1015+
if (prop.minItems != null) {
1016+
result.append(", ");
1017+
}
1018+
result.append("max = ").append(prop.maxItems);
1019+
}
1020+
result.append(") ");
1021+
}
1022+
}
1023+
if (prop.isNullable) {
1024+
if (isGenerateHardNullable()) {
1025+
result.append("@HardNullable ");
1026+
} else {
1027+
result.append("@Nullable ");
1028+
}
1029+
} else if (!containsNotEmpty) {
1030+
result.append("@NotNull ");
1031+
}
1032+
if (StringUtils.isNotEmpty(prop.minimum)) {
1033+
try {
1034+
var longNumber = Long.parseLong(prop.minimum);
1035+
if (prop.exclusiveMinimum) {
1036+
longNumber++;
1037+
}
1038+
if (longNumber == 0 && StringUtils.isEmpty(prop.maximum)) {
1039+
result.append("@PositiveOrZero ");
1040+
} else if (longNumber == 1 && StringUtils.isEmpty(prop.maximum)) {
1041+
result.append("@Positive ");
1042+
} else {
1043+
result.append("@Min(").append(longNumber).append(") ");
1044+
}
1045+
} catch (Exception e) {
1046+
result.append("@DecimalMin(");
1047+
if (prop.exclusiveMinimum) {
1048+
result.append("value = ");
1049+
}
1050+
result.append('"').append(prop.minimum).append('"');
1051+
if (prop.exclusiveMinimum) {
1052+
result.append(", inclusive = false");
1053+
}
1054+
result.append(") ");
1055+
}
1056+
}
1057+
if (StringUtils.isNotEmpty(prop.maximum)) {
1058+
try {
1059+
var longNumber = Long.parseLong(prop.maximum);
1060+
if (prop.exclusiveMaximum) {
1061+
longNumber--;
1062+
}
1063+
if (longNumber == 0 && StringUtils.isEmpty(prop.minimum)) {
1064+
result.append("@NegativeOrZero ");
1065+
} else if (longNumber == -1 && StringUtils.isEmpty(prop.minimum)) {
1066+
result.append("@Negative ");
1067+
} else {
1068+
result.append("@Max(").append(longNumber).append(") ");
1069+
}
1070+
} catch (Exception e) {
1071+
result.append("@DecimalMax(");
1072+
if (prop.exclusiveMaximum) {
1073+
result.append("value = ");
1074+
}
1075+
result.append('"').append(prop.maximum).append('"');
1076+
if (prop.exclusiveMaximum) {
1077+
result.append(", inclusive = false");
1078+
}
1079+
result.append(") ");
1080+
}
1081+
}
1082+
return result.toString();
1083+
}
1084+
1085+
public boolean isGenerateHardNullable() {
1086+
return false;
1087+
}
1088+
9021089
private void processParentModel(CodegenModel model, List<CodegenProperty> requiredVarsWithoutDiscriminator, List<CodegenProperty> requiredParentVarsWithoutDiscriminator) {
9031090
var parent = model.getParentModel();
9041091
var hasParent = parent != null;

openapi-generator/src/main/java/io/micronaut/openapi/generator/JavaMicronautServerCodegen.java

+5
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,11 @@ public void setParameterExampleValue(CodegenParameter p) {
273273
}
274274
}
275275

276+
@Override
277+
public boolean isGenerateHardNullable() {
278+
return generateHardNullable;
279+
}
280+
276281
@Override
277282
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
278283
objs = super.postProcessOperationsWithModels(objs, allModels);

openapi-generator/src/main/resources/templates/java-micronaut/client/api.mustache

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import io.micronaut.http.HttpResponse;
1717
{{#imports}}
1818
import {{import}};
1919
{{/imports}}
20-
{{#withGeneratedAnnotation}}
20+
{{#generatedAnnotation}}
2121
import {{javaxPackage}}.annotation.Generated;
22-
{{/withGeneratedAnnotation}}
22+
{{/generatedAnnotation}}
2323
import java.util.ArrayList;
2424
import java.util.HashMap;
2525
import java.util.List;
@@ -46,9 +46,9 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
4646
{{#additionalClientTypeAnnotations}}
4747
{{{.}}}
4848
{{/additionalClientTypeAnnotations}}
49-
{{#withGeneratedAnnotation}}
49+
{{#generatedAnnotation}}
5050
{{>common/generatedAnnotation}}
51-
{{/withGeneratedAnnotation}}
51+
{{/generatedAnnotation}}
5252
@Client({{#configureClientId}}id = "{{clientId}}", path = {{/configureClientId}}"${{openbrace}}{{{applicationName}}}{{basePathSeparator}}base-path{{closebrace}}")
5353
public interface {{classname}} {
5454
{{#operations}}

openapi-generator/src/main/resources/templates/java-micronaut/client/auth/Authorization.mustache

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import java.lang.annotation.Target;
1111

1212
import static java.lang.annotation.ElementType.METHOD;
1313
import static java.lang.annotation.RetentionPolicy.RUNTIME;
14-
{{#withGeneratedAnnotation}}
14+
{{#generatedAnnotation}}
1515
import {{javaxPackage}}.annotation.Generated;
16-
{{/withGeneratedAnnotation}}
16+
{{/generatedAnnotation}}
1717

18-
{{#withGeneratedAnnotation}}
18+
{{#generatedAnnotation}}
1919
{{>common/generatedAnnotation}}
20-
{{/withGeneratedAnnotation}}
20+
{{/generatedAnnotation}}
2121
@Documented
2222
@Retention(RUNTIME)
2323
@Target(METHOD)

openapi-generator/src/main/resources/templates/java-micronaut/client/auth/AuthorizationBinder.mustache

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import io.micronaut.http.client.bind.ClientRequestUriContext;
1313
import jakarta.inject.Singleton;
1414
import java.util.ArrayList;
1515
import java.util.List;
16-
{{#withGeneratedAnnotation}}
16+
{{#generatedAnnotation}}
1717
import {{javaxPackage}}.annotation.Generated;
18-
{{/withGeneratedAnnotation}}
18+
{{/generatedAnnotation}}
1919

20-
{{#withGeneratedAnnotation}}
20+
{{#generatedAnnotation}}
2121
{{>common/generatedAnnotation}}
22-
{{/withGeneratedAnnotation}}
22+
{{/generatedAnnotation}}
2323
@Singleton
2424
public class AuthorizationBinder implements AnnotatedClientRequestBinder<Authorization> {
2525

openapi-generator/src/main/resources/templates/java-micronaut/client/auth/AuthorizationFilter.mustache

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ import java.util.List;
3737
import java.util.Map;
3838
import java.util.stream.Collectors;
3939
import java.util.stream.Stream;
40-
{{#withGeneratedAnnotation}}
40+
{{#generatedAnnotation}}
4141
import {{javaxPackage}}.annotation.Generated;
42-
{{/withGeneratedAnnotation}}
42+
{{/generatedAnnotation}}
4343

44-
{{#withGeneratedAnnotation}}
44+
{{#generatedAnnotation}}
4545
{{>common/generatedAnnotation}}
46-
{{/withGeneratedAnnotation}}
46+
{{/generatedAnnotation}}
4747
{{#lombok}}
4848
@Slf4j
4949
{{/lombok}}

openapi-generator/src/main/resources/templates/java-micronaut/client/auth/Authorizations.mustache

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import io.micronaut.core.bind.annotation.Bindable;
66
import java.lang.annotation.Documented;
77
import java.lang.annotation.Retention;
88
import java.lang.annotation.Target;
9-
{{#withGeneratedAnnotation}}
9+
{{#generatedAnnotation}}
1010
import {{javaxPackage}}.annotation.Generated;
11-
{{/withGeneratedAnnotation}}
11+
{{/generatedAnnotation}}
1212

1313
import static java.lang.annotation.ElementType.METHOD;
1414
import static java.lang.annotation.RetentionPolicy.RUNTIME;
1515

16-
{{#withGeneratedAnnotation}}
16+
{{#generatedAnnotation}}
1717
{{>common/generatedAnnotation}}
18-
{{/withGeneratedAnnotation}}
18+
{{/generatedAnnotation}}
1919
@Documented
2020
@Retention(RUNTIME)
2121
@Target(METHOD)

openapi-generator/src/main/resources/templates/java-micronaut/client/auth/configuration/ApiKeyAuthConfiguration.mustache

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ import io.micronaut.context.annotation.Parameter;
77
import io.micronaut.core.annotation.NonNull;
88
import io.micronaut.http.MutableHttpRequest;
99
import io.micronaut.http.cookie.Cookie;
10-
{{#withGeneratedAnnotation}}
10+
{{#generatedAnnotation}}
1111
import {{javaxPackage}}.annotation.Generated;
12-
{{/withGeneratedAnnotation}}
12+
{{/generatedAnnotation}}
1313
{{#lombok}}
1414
import lombok.Getter;
1515
import lombok.Setter;
1616
{{/lombok}}
1717

18-
{{#withGeneratedAnnotation}}
18+
{{#generatedAnnotation}}
1919
{{>common/generatedAnnotation}}
20-
{{/withGeneratedAnnotation}}
20+
{{/generatedAnnotation}}
2121
{{#lombok}}
2222
@Getter
2323
@Setter

openapi-generator/src/main/resources/templates/java-micronaut/client/auth/configuration/ConfigurableAuthorization.mustache

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ package {{invokerPackage}}.auth.configuration;
33

44
import io.micronaut.core.annotation.NonNull;
55
import io.micronaut.http.MutableHttpRequest;
6-
{{#withGeneratedAnnotation}}
6+
{{#generatedAnnotation}}
77
import {{javaxPackage}}.annotation.Generated;
8-
{{/withGeneratedAnnotation}}
8+
{{/generatedAnnotation}}
99

10-
{{#withGeneratedAnnotation}}
10+
{{#generatedAnnotation}}
1111
{{>common/generatedAnnotation}}
12-
{{/withGeneratedAnnotation}}
12+
{{/generatedAnnotation}}
1313
public interface ConfigurableAuthorization {
1414
1515
String getName();

0 commit comments

Comments
 (0)