@@ -231,10 +231,12 @@ protected AbstractMicronautJavaCodegen() {
231
231
};
232
232
reservedWords .addAll (Arrays .asList (reservedWordsArray ));
233
233
234
+ importMapping .put ("DateTime" , "java.time.Instant" );
234
235
importMapping .put ("LocalDateTime" , "java.time.LocalDateTime" );
235
236
importMapping .put ("OffsetDateTime" , "java.time.OffsetDateTime" );
236
237
importMapping .put ("ZonedDateTime" , "java.time.ZonedDateTime" );
237
238
importMapping .put ("LocalDate" , "java.time.LocalDate" );
239
+ importMapping .put ("LocalTime" , "java.time.LocalTime" );
238
240
}
239
241
240
242
public void setGenerateHttpResponseAlways (boolean generateHttpResponseAlways ) {
@@ -658,6 +660,14 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
658
660
});
659
661
op .formParams .clear ();
660
662
}
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
+ }
661
671
}
662
672
663
673
return objs ;
@@ -682,6 +692,8 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
682
692
683
693
if (op .isResponseFile ) {
684
694
op .returnType = typeMapping .get ("responseFile" );
695
+ op .returnProperty .dataType = op .returnType ;
696
+ op .returnProperty .datatypeWithEnum = op .returnType ;
685
697
op .imports .add (op .returnType );
686
698
}
687
699
@@ -800,14 +812,17 @@ private void wrapOperationReturnType(CodegenOperation op, String wrapperType, bo
800
812
originalReturnType = "Void" ;
801
813
op .returnProperty = new CodegenProperty ();
802
814
op .returnProperty .dataType = "Void" ;
815
+ op .returnProperty .openApiType = "" ;
803
816
}
804
817
newReturnType .dataType = typeName + '<' + originalReturnType + '>' ;
805
818
newReturnType .items = op .returnProperty ;
806
819
}
820
+ newReturnType .containerTypeMapped = typeName ;
821
+ newReturnType .containerType = typeName ;
807
822
op .vendorExtensions .put ("originalReturnType" , originalReturnType );
808
823
809
824
op .returnType = newReturnType .dataType ;
810
- op .returnContainer = null ;
825
+ op .returnContainer = newReturnType . containerTypeMapped ;
811
826
op .returnProperty = newReturnType ;
812
827
op .isArray = op .returnProperty .isArray ;
813
828
}
@@ -887,18 +902,190 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
887
902
property .vendorExtensions .put ("lombok" , lombok );
888
903
property .vendorExtensions .put ("defaultValueIsNotNull" , property .defaultValue != null && !property .defaultValue .equals ("null" ));
889
904
property .vendorExtensions .put ("isServer" , isServer );
905
+ processGenericAnnotations (property );
890
906
}
891
907
model .vendorExtensions .put ("isServer" , isServer );
892
908
for (var property : model .requiredVars ) {
893
909
property .vendorExtensions .put ("lombok" , lombok );
894
910
property .vendorExtensions .put ("isServer" , isServer );
895
911
property .vendorExtensions .put ("defaultValueIsNotNull" , property .defaultValue != null && !property .defaultValue .equals ("null" ));
912
+ processGenericAnnotations (property );
896
913
}
897
914
}
898
915
899
916
return objs ;
900
917
}
901
918
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
+
902
1089
private void processParentModel (CodegenModel model , List <CodegenProperty > requiredVarsWithoutDiscriminator , List <CodegenProperty > requiredParentVarsWithoutDiscriminator ) {
903
1090
var parent = model .getParentModel ();
904
1091
var hasParent = parent != null ;
0 commit comments