11package io .zenwave360 .sdk .plugins ;
22
3+ import com .fasterxml .jackson .core .JsonProcessingException ;
4+ import com .fasterxml .jackson .databind .ObjectMapper ;
35import io .zenwave360 .sdk .doc .DocumentedOption ;
46import io .zenwave360 .sdk .generators .AbstractAsyncapiGenerator ;
57import io .zenwave360 .sdk .utils .AntStyleMatcher ;
8+ import io .zenwave360 .sdk .utils .JSONPath ;
69import io .zenwave360 .sdk .zdl .GeneratedProjectFiles ;
710import org .apache .avro .LogicalTypes ;
811import org .apache .avro .Schema ;
@@ -154,31 +157,124 @@ private String asJsonArray(Collection<File> avscFiles) throws IOException {
154157 }
155158 }
156159
157- return "[" + String .join ("," , allSchemas ) + "]" ;
160+ var jsonArrayString = "[" + String .join ("," , allSchemas ) + "]" ;
161+ return sortSchemas (jsonArrayString );
162+ }
163+
164+ public String sortSchemas (String jsonArrayString ) throws JsonProcessingException {
165+ if (isAvroVersionLater ("1.12.0" )) {
166+ return jsonArrayString ;
167+ }
168+ log .info ("Avro version detected {} < 1.12.0. Sorting schemas..." , AVRO_VERSION );
169+ var objectMapper = new ObjectMapper ();
170+
171+ List <Map <String , Object >> schemas = objectMapper .readValue (jsonArrayString , List .class );
172+ var schemasToSort = JSONPath .get (schemas , "$.[?(@.type == 'record' || @.type == 'enum')]" , List .<Map <String , Object >>of ());
173+
174+ log .debug ("Sorting schemas: {}" , JSONPath .get (schemasToSort , "$.[*].name" , List .of ()));
175+ schemasToSort .sort (createDependencyComparator ());
176+ log .debug ("Sorted schemas: {}" , JSONPath .get (schemasToSort , "$.[*].name" , List .of ()));
177+
178+ return objectMapper .writerWithDefaultPrettyPrinter ().writeValueAsString (schemasToSort );
179+ }
180+
181+ private Comparator <Map <String , Object >> createDependencyComparator () {
182+ return (map1 , map2 ) -> {
183+ String name1 = (String ) map1 .get ("name" );
184+ String name2 = (String ) map2 .get ("name" );
185+ String type1 = (String ) map1 .get ("type" );
186+ String type2 = (String ) map2 .get ("type" );
187+
188+ List <String > dependencies1 = extractDependencies (map1 );
189+ List <String > dependencies2 = extractDependencies (map2 );
190+
191+ boolean map1IsEnum = "enum" .equals (type1 );
192+ boolean map2IsEnum = "enum" .equals (type2 );
193+ boolean map1HasNoDeps = dependencies1 .isEmpty ();
194+ boolean map2HasNoDeps = dependencies2 .isEmpty ();
195+
196+ // Enums and maps with no dependencies go first
197+ if ((map1IsEnum || map1HasNoDeps ) && !(map2IsEnum || map2HasNoDeps )) {
198+ return -1 ; // map1 comes before map2
199+ } else if (!(map1IsEnum || map1HasNoDeps ) && (map2IsEnum || map2HasNoDeps )) {
200+ return 1 ; // map1 comes after map2
201+ }
202+
203+ boolean map1DependsOnMap2 = dependencies1 .contains (name2 );
204+ boolean map2DependsOnMap1 = dependencies2 .contains (name1 );
205+
206+ if (map1DependsOnMap2 && !map2DependsOnMap1 ) {
207+ return 1 ; // map1 comes after map2
208+ } else if (!map1DependsOnMap2 && map2DependsOnMap1 ) {
209+ return -1 ; // map1 comes before map2
210+ }
211+ return 0 ; // no dependency relationship
212+ };
213+ }
214+
215+ private List <String > extractDependencies (Map <String , Object > schema ) {
216+ List <Object > fieldTypes = JSONPath .get (schema , "$.fields[*].type" , List .of ());
217+ List <String > dependencies = new ArrayList <>();
218+
219+ for (Object fieldType : fieldTypes ) {
220+ if (fieldType instanceof String ) {
221+ dependencies .add ((String ) fieldType );
222+ } else if (fieldType instanceof Map ) {
223+ Map <String , Object > typeMap = (Map <String , Object >) fieldType ;
224+ String items = JSONPath .get (typeMap , "$.items" , null );
225+ if (items != null ) {
226+ dependencies .add (items );
227+ }
228+ }
229+ }
230+
231+ return dependencies ;
158232 }
159233
160234 protected void setCompilerProperties (SpecificCompiler compiler , AvroCompilerProperties properties ) {
161235 compiler .setTemplateDir (properties .templateDirectory );
162236 compiler .setStringType (GenericData .StringType .valueOf (properties .stringType ));
163237 compiler .setFieldVisibility (SpecificCompiler .FieldVisibility .valueOf (properties .fieldVisibility .toUpperCase ()));
164- compiler .setCreateOptionalGetters (properties .createOptionalGetters );
165- compiler .setGettersReturnOptional (properties .gettersReturnOptional );
166- compiler .setOptionalGettersForNullableFieldsOnly (properties .optionalGettersForNullableFieldsOnly );
167238 compiler .setCreateSetters (properties .createSetters );
168- // compiler.setCreateNullSafeAnnotations(properties.createNullSafeAnnotations);
169- // compiler.setNullSafeAnnotationNullable(properties.nullSafeAnnotationNullable);
170- // compiler.setNullSafeAnnotationNotNull(properties.nullSafeAnnotationNotNull);
171- compiler .setEnableDecimalLogicalType (properties .enableDecimalLogicalType );
172239 compiler .setOutputCharacterEncoding (properties .outputCharacterEncoding );
173- compiler .setAdditionalVelocityTools (properties .instantiateAdditionalVelocityTools ());
174- // compiler.setRecordSpecificClass(properties.recordSpecificClass);
175- // compiler.setErrorSpecificClass(properties.errorSpecificClass);
176240
241+ if (isAvroVersionLater ("1.8.0" )) {
242+ setCompilerProperties_v1_8_0 (compiler , properties );
243+ }
244+ if (isAvroVersionLater ("1.8.2" )) {
245+ setCompilerProperties_v1_8_2 (compiler , properties );
246+ }
247+ if (isAvroVersionLater ("1.9.0" )) {
248+ setCompilerProperties_v1_9_0 (compiler , properties );
249+ }
250+ if (isAvroVersionLater ("1.11.0" )) {
251+ setCompilerProperties_v1_11_0 (compiler , properties );
252+ }
253+ if (isAvroVersionLater ("1.12.0" )) {
254+ setCompilerProperties_v1_12_0 (compiler , properties );
255+ }
256+ }
257+
258+ protected void setCompilerProperties_v1_8_0 (SpecificCompiler compiler , AvroCompilerProperties properties ) {
259+ compiler .setEnableDecimalLogicalType (properties .enableDecimalLogicalType );
260+ }
261+
262+ protected void setCompilerProperties_v1_8_2 (SpecificCompiler compiler , AvroCompilerProperties properties ) {
263+ compiler .setCreateOptionalGetters (properties .createOptionalGetters );
264+ compiler .setGettersReturnOptional (properties .gettersReturnOptional );
177265 if (properties .customConversions != null ) {
178266 for (var conversionClass : properties .customConversions ) {
179267 compiler .addCustomConversion (conversionClass );
180268 }
181269 }
270+ }
271+
272+ protected void setCompilerProperties_v1_9_0 (SpecificCompiler compiler , AvroCompilerProperties properties ) {
273+ compiler .setOptionalGettersForNullableFieldsOnly (properties .optionalGettersForNullableFieldsOnly );
274+ compiler .setAdditionalVelocityTools (properties .instantiateAdditionalVelocityTools ());
275+ }
276+
277+ protected void setCompilerProperties_v1_11_0 (SpecificCompiler compiler , AvroCompilerProperties properties ) {
182278 if (properties .customLogicalTypeFactories != null ) {
183279 for (var logicalTypeFactoryClass : properties .customLogicalTypeFactories ) {
184280 try {
@@ -189,8 +285,41 @@ protected void setCompilerProperties(SpecificCompiler compiler, AvroCompilerProp
189285 throw new RuntimeException ("Failed to instantiate logical type factory " + logicalTypeFactoryClass , e );
190286 }
191287 }
288+ }
289+ }
192290
291+ protected void setCompilerProperties_v1_12_0 (SpecificCompiler compiler , AvroCompilerProperties properties ) {
292+ compiler .setCreateNullSafeAnnotations (properties .createNullSafeAnnotations );
293+ compiler .setRecordSpecificClass (properties .recordSpecificClass );
294+ compiler .setErrorSpecificClass (properties .errorSpecificClass );
295+ }
296+
297+ protected void setCompilerProperties_v1_12_1 (SpecificCompiler compiler , AvroCompilerProperties properties ) {
298+ // compiler.setNullSafeAnnotationNullable(properties.nullSafeAnnotationNullable);
299+ // compiler.setNullSafeAnnotationNotNull(properties.nullSafeAnnotationNotNull);
300+ }
301+
302+ private static final String AVRO_VERSION = _getAvroVersion ();
303+ private static String _getAvroVersion () {
304+ Package avroPackage = Schema .class .getPackage ();
305+ if (avroPackage != null && avroPackage .getImplementationVersion () != null ) {
306+ return avroPackage .getImplementationVersion ();
193307 }
308+ return "0.0.0" ;
194309 }
195310
311+ private boolean isAvroVersionLater (String version ) {
312+ String [] currentVersionParts = AVRO_VERSION .split ("\\ ." );
313+ String [] targetVersionParts = version .split ("\\ ." );
314+
315+ int currentMajor = Integer .parseInt (currentVersionParts [0 ]);
316+ int currentMinor = Integer .parseInt (currentVersionParts [1 ]);
317+ int targetMajor = Integer .parseInt (targetVersionParts [0 ]);
318+ int targetMinor = Integer .parseInt (targetVersionParts [1 ]);
319+
320+ return currentMajor > targetMajor ||
321+ (currentMajor == targetMajor && currentMinor >= targetMinor );
322+ }
323+
324+
196325}
0 commit comments