19
19
import java .io .IOException ;
20
20
import java .io .Reader ;
21
21
import java .io .StringReader ;
22
- import java .util .*;
22
+ import java .io .Writer ;
23
+ import java .util .ArrayList ;
24
+ import java .util .Collections ;
25
+ import java .util .Comparator ;
26
+ import java .util .HashMap ;
27
+ import java .util .Iterator ;
28
+ import java .util .List ;
29
+ import java .util .Map ;
30
+ import java .util .Set ;
23
31
import okio .ByteString ;
24
32
import org .apache .commons .lang3 .tuple .MutablePair ;
25
33
import org .apache .commons .lang3 .tuple .Pair ;
26
34
import org .slf4j .Logger ;
27
35
import org .slf4j .LoggerFactory ;
36
+ import org .yaml .snakeyaml .DumperOptions ;
28
37
import org .yaml .snakeyaml .constructor .Constructor ;
38
+ import org .yaml .snakeyaml .introspector .Property ;
39
+ import org .yaml .snakeyaml .nodes .MappingNode ;
29
40
import org .yaml .snakeyaml .nodes .Node ;
41
+ import org .yaml .snakeyaml .nodes .NodeTuple ;
30
42
import org .yaml .snakeyaml .nodes .ScalarNode ;
43
+ import org .yaml .snakeyaml .nodes .Tag ;
44
+ import org .yaml .snakeyaml .representer .Represent ;
45
+ import org .yaml .snakeyaml .representer .Representer ;
31
46
32
47
public class Yaml {
33
48
private static Map <String , Class <?>> classes = new HashMap <>();
@@ -259,6 +274,46 @@ public static List<Object> loadAll(Reader reader) throws IOException {
259
274
return list ;
260
275
}
261
276
277
+ /**
278
+ * Takes an API object and returns a YAML String representing that object.
279
+ *
280
+ * @param object The API object to dump.
281
+ * @return A YAML String representing the API object.
282
+ */
283
+ public static String dump (Object object ) {
284
+ return getSnakeYaml ().dump (object );
285
+ }
286
+
287
+ /**
288
+ * Takes an API object and writes a YAML string representing that object to the writer.
289
+ *
290
+ * @param object The API object to dump
291
+ * @param writer The writer to write the YAML to.
292
+ */
293
+ public static void dump (Object object , Writer writer ) {
294
+ getSnakeYaml ().dump (object , writer );
295
+ }
296
+
297
+ /**
298
+ * Takes an Iterator of YAML API objects and returns a YAML string representing all of them
299
+ *
300
+ * @param data The list of YAML API objects
301
+ * @return A String representing the list of YAML API objects.
302
+ */
303
+ public static String dumpAll (Iterator <? extends Object > data ) {
304
+ return getSnakeYaml ().dumpAll (data );
305
+ }
306
+
307
+ /**
308
+ * Takes an Iterator of YAML API objects and writes a YAML String representing all of them.
309
+ *
310
+ * @param data The list of YAML API objects.
311
+ * @param output The writer to output the YAML String to.
312
+ */
313
+ public static void dumpAll (Iterator <? extends Object > data , Writer output ) {
314
+ getSnakeYaml ().dumpAll (data , output );
315
+ }
316
+
262
317
/** Defines constructor logic for custom types in this library. */
263
318
public static class CustomConstructor extends Constructor {
264
319
@ Override
@@ -285,9 +340,93 @@ private byte[] constructByteArray(ScalarNode node) {
285
340
}
286
341
}
287
342
343
+ public static class CustomRepresenter extends Representer {
344
+ public CustomRepresenter () {
345
+ this .setDefaultFlowStyle (DumperOptions .FlowStyle .BLOCK );
346
+ this .representers .put (IntOrString .class , new RepresentIntOrString ());
347
+ this .representers .put (byte [].class , new RepresentByteArray ());
348
+ }
349
+
350
+ private class RepresentIntOrString implements Represent {
351
+ @ Override
352
+ public Node representData (Object data ) {
353
+ IntOrString intOrString = (IntOrString ) data ;
354
+ if (intOrString .isInteger ()) {
355
+ return CustomRepresenter .this .representData (intOrString .getIntValue ());
356
+ } else {
357
+ return CustomRepresenter .this .representData (intOrString .getStrValue ());
358
+ }
359
+ }
360
+ }
361
+
362
+ private class RepresentByteArray implements Represent {
363
+ @ Override
364
+ public Node representData (Object data ) {
365
+ String value = ByteString .of ((byte []) data ).base64 ();
366
+ return representScalar (Tag .STR , value );
367
+ }
368
+ }
369
+
370
+ /**
371
+ * This returns the ordering of properties that by convention should appear at the beginning of
372
+ * a Yaml object in Kubernetes.
373
+ */
374
+ private int getPropertyPosition (String property ) {
375
+ switch (property ) {
376
+ case "apiVersion" :
377
+ return 0 ;
378
+ case "kind" :
379
+ return 1 ;
380
+ case "metadata" :
381
+ return 2 ;
382
+ case "spec" :
383
+ return 3 ;
384
+ case "type" :
385
+ return 4 ;
386
+ default :
387
+ return Integer .MAX_VALUE ;
388
+ }
389
+ }
390
+
391
+ @ Override
392
+ protected MappingNode representJavaBean (Set <Property > properties , Object javaBean ) {
393
+ MappingNode node = super .representJavaBean (properties , javaBean );
394
+ // Always set the tag to MAP so that SnakeYaml doesn't print out the class name as a tag.
395
+ node .setTag (Tag .MAP );
396
+ // Sort the output of our map so that we put certain keys, such as apiVersion, first.
397
+ Collections .sort (
398
+ node .getValue (),
399
+ new Comparator <NodeTuple >() {
400
+ @ Override
401
+ public int compare (NodeTuple a , NodeTuple b ) {
402
+ String nameA = ((ScalarNode ) a .getKeyNode ()).getValue ();
403
+ String nameB = ((ScalarNode ) b .getKeyNode ()).getValue ();
404
+ int intCompare =
405
+ Integer .compare (getPropertyPosition (nameA ), getPropertyPosition (nameB ));
406
+ if (intCompare != 0 ) {
407
+ return intCompare ;
408
+ } else {
409
+ return nameA .compareTo (nameB );
410
+ }
411
+ }
412
+ });
413
+ return node ;
414
+ }
415
+
416
+ @ Override
417
+ protected NodeTuple representJavaBeanProperty (
418
+ Object javaBean , Property property , Object propertyValue , Tag customTag ) {
419
+ // returning null for a null property value means we won't output it in the Yaml
420
+ if (propertyValue == null ) {
421
+ return null ;
422
+ }
423
+ return super .representJavaBeanProperty (javaBean , property , propertyValue , customTag );
424
+ }
425
+ }
426
+
288
427
/** @return An instantiated SnakeYaml Object. */
289
428
public static org .yaml .snakeyaml .Yaml getSnakeYaml () {
290
- return new org .yaml .snakeyaml .Yaml (new CustomConstructor ());
429
+ return new org .yaml .snakeyaml .Yaml (new CustomConstructor (), new CustomRepresenter () );
291
430
}
292
431
293
432
/**
0 commit comments