2323import com .fasterxml .jackson .dataformat .yaml .YAMLGenerator ;
2424import com .fasterxml .jackson .datatype .jsr310 .JavaTimeModule ;
2525import io .fabric8 .kubernetes .api .model .KubernetesResource ;
26+ import io .fabric8 .kubernetes .api .model .KubernetesResourceList ;
2627import io .fabric8 .kubernetes .api .model .runtime .RawExtension ;
2728import io .fabric8 .kubernetes .client .KubernetesClientException ;
2829import io .fabric8 .kubernetes .model .jackson .UnmatchedFieldTypeModule ;
3940import java .util .Collections ;
4041import java .util .List ;
4142import java .util .Map ;
42- import java .util .regex .Matcher ;
43- import java .util .regex .Pattern ;
44- import java .util .stream .Collectors ;
4543
4644public class Serialization {
4745 private Serialization () {
@@ -57,8 +55,6 @@ private Serialization() {
5755
5856 private static volatile ObjectMapper YAML_MAPPER ;
5957
60- private static final String DOCUMENT_DELIMITER = "---" ;
61-
6258 /**
6359 * {@link ObjectMapper} singleton instance used internally by the Kubernetes client.
6460 *
@@ -213,22 +209,7 @@ public static <T> T unmarshal(InputStream is, ObjectMapper mapper) {
213209 */
214210 @ Deprecated
215211 public static <T > T unmarshal (InputStream is , ObjectMapper mapper , Map <String , String > parameters ) {
216- // it's not well documented which Serialization methods are aware of input that can contain
217- // multiple docs
218- String specFile ;
219- try {
220- specFile = IOHelpers .readFully (is );
221- } catch (IOException e1 ) {
222- throw new RuntimeException ("Could not read stream" );
223- }
224- if (containsMultipleDocuments (specFile )) {
225- return (T ) getKubernetesResourceList (Collections .emptyMap (), specFile );
226- } else if (specFile .contains (DOCUMENT_DELIMITER )) {
227- specFile = specFile .replaceAll ("^---([ \\ t].*?)?\\ r?\\ n" , "" );
228- specFile = specFile .replaceAll ("\\ n---([ \\ t].*?)?\\ r?\\ n?$" , "\n " );
229- }
230-
231- return unmarshal (new ByteArrayInputStream (specFile .getBytes (StandardCharsets .UTF_8 )), mapper , new TypeReference <T >() {
212+ return unmarshal (is , mapper , new TypeReference <T >() {
232213 @ Override
233214 public Type getType () {
234215 return KubernetesResource .class ;
@@ -247,24 +228,51 @@ private static <T> T unmarshal(InputStream is, ObjectMapper mapper, TypeReferenc
247228 } while (intch > -1 && Character .isWhitespace (intch ));
248229 bis .reset ();
249230
250- final T result ;
231+ T result = null ;
232+ List <KubernetesResource > listResult = null ;
251233 if (intch != '{' && intch != '[' ) {
252234 final Load yaml = new Load (LoadSettings .builder ().build ());
253- final Object obj = yaml .loadFromInputStream (bis );
254- if (obj instanceof Map ) {
255- result = mapper .convertValue (obj , type );
256- } else {
257- result = mapper .convertValue (new RawExtension (obj ), type );
235+ // if multiple docs exist, only non-null resources will be kept
236+ final Iterable <Object > objs = yaml .loadAllFromInputStream (bis );
237+ for (Object obj : objs ) {
238+ Object value = null ;
239+ if (obj instanceof Map ) {
240+ value = mapper .convertValue (obj , type );
241+ } else if (obj != null ) {
242+ value = mapper .convertValue (new RawExtension (obj ), type );
243+ }
244+ if (value != null ) {
245+ if (result == null ) {
246+ result = (T ) value ;
247+ } else {
248+ if (listResult == null ) {
249+ listResult = new ArrayList <>();
250+ accumulateResult (result , listResult );
251+ }
252+ accumulateResult (value , listResult );
253+ }
254+ }
258255 }
259256 } else {
260257 result = mapper .readerFor (type ).readValue (bis );
261258 }
259+ if (listResult != null ) {
260+ return (T ) listResult ;
261+ }
262262 return result ;
263263 } catch (IOException e ) {
264264 throw KubernetesClientException .launderThrowable (e );
265265 }
266266 }
267267
268+ private static <T > void accumulateResult (T result , List <KubernetesResource > listResult ) {
269+ if (result instanceof KubernetesResourceList ) {
270+ listResult .addAll (((KubernetesResourceList ) result ).getItems ());
271+ } else {
272+ listResult .add ((KubernetesResource ) result );
273+ }
274+ }
275+
268276 /**
269277 * Unmarshals a {@link String}
270278 * <p>
@@ -382,42 +390,6 @@ public static <T> T unmarshal(InputStream is, TypeReference<T> type, Map<String,
382390 return unmarshal (is , JSON_MAPPER , type , parameters );
383391 }
384392
385- private static List <KubernetesResource > getKubernetesResourceList (Map <String , String > parameters , String specFile ) {
386- return splitSpecFile (specFile ).stream ().filter (Serialization ::validate )
387- .map (
388- document -> (KubernetesResource ) Serialization .unmarshal (new ByteArrayInputStream (document .getBytes ()), parameters ))
389- .filter (o -> o != null )
390- .collect (Collectors .toList ());
391- }
392-
393- static boolean containsMultipleDocuments (String specFile ) {
394- final long validDocumentCount = splitSpecFile (specFile ).stream ().filter (Serialization ::validate )
395- .count ();
396- return validDocumentCount > 1 ;
397- }
398-
399- private static List <String > splitSpecFile (String aSpecFile ) {
400- final List <String > documents = new ArrayList <>();
401- final StringBuilder documentBuilder = new StringBuilder ();
402- for (String line : aSpecFile .split ("\r ?\n " )) {
403- if (line .startsWith (DOCUMENT_DELIMITER )) {
404- documents .add (documentBuilder .toString ());
405- documentBuilder .setLength (0 );
406- } else {
407- documentBuilder .append (line ).append (System .lineSeparator ());
408- }
409- }
410- if (documentBuilder .length () > 0 ) {
411- documents .add (documentBuilder .toString ());
412- }
413- return documents ;
414- }
415-
416- private static boolean validate (String document ) {
417- Matcher keyValueMatcher = Pattern .compile ("(\\ S+):\\ s(\\ S*)(?:\\ b(?!:)|$)" ).matcher (document );
418- return !document .isEmpty () && keyValueMatcher .find ();
419- }
420-
421393 /**
422394 * Create a copy of the resource via serialization.
423395 *
0 commit comments