1 package net.avcompris.commons3.yaml;
2
3 import static com.google.common.base.Preconditions.checkArgument;
4 import static com.google.common.base.Preconditions.checkNotNull;
5 import static com.google.common.base.Preconditions.checkState;
6 import static java.nio.charset.StandardCharsets.UTF_8;
7
8 import java.io.BufferedInputStream;
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.InputStreamReader;
14 import java.io.Reader;
15 import java.io.StringReader;
16 import java.util.Date;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.stream.Collectors;
20
21 import javax.annotation.Nullable;
22
23 import org.apache.commons.lang3.NotImplementedException;
24
25
26 public abstract class YamlUtils {
27
28 public static Yaml loadYaml(final InputStream is) throws IOException {
29
30 checkNotNull(is, "is");
31
32
33
34
35
36
37 final Map<Object, Object> map;
38
39 try (BufferedInputStream bis = new BufferedInputStream(is)) {
40
41 try (Reader reader = new InputStreamReader(bis, UTF_8)) {
42
43 map = new YamlLoader().load(reader);
44 }
45 }
46
47 return new YamlImpl(map);
48 }
49
50 public static Yaml loadYaml(final File yamlFile) throws IOException {
51
52 checkNotNull(yamlFile, "yamlFile");
53
54 try (InputStream is = new FileInputStream(yamlFile)) {
55
56 return loadYaml(is);
57 }
58 }
59
60 public static Yaml loadYaml(final String yamlContent) throws IOException {
61
62 checkNotNull(yamlContent, "yamlContent");
63
64
65
66
67
68
69 final Map<Object, Object> map;
70
71 try (Reader reader = new StringReader(yamlContent)) {
72
73 map = new YamlLoader().load(reader);
74 }
75
76 return new YamlImpl(map);
77 }
78
79 private static final class YamlImpl implements Yaml {
80
81 private static final Yaml NULL = new YamlImpl();
82
83 @Nullable
84 private final Map<Object, Object> map;
85
86 @Nullable
87 private final List<Object> list;
88
89 @Nullable
90 private final String s;
91
92 @Nullable
93 private final Integer n;
94
95 @Nullable
96 private final Long l;
97
98 @Nullable
99 private final Boolean b;
100
101 @Nullable
102 private final Date date;
103
104 YamlImpl(@Nullable final Map<Object, Object> map) {
105
106 this.map = map;
107 this.list = null;
108 this.s = null;
109 this.n = null;
110 this.l = null;
111 this.b = null;
112 this.date = null;
113 }
114
115 YamlImpl(final List<Object> list) {
116
117 this.map = null;
118 this.list = checkNotNull(list, "list");
119 this.s = null;
120 this.n = null;
121 this.l = null;
122 this.b = null;
123 this.date = null;
124 }
125
126 YamlImpl(final String s) {
127
128 this.map = null;
129 this.list = null;
130 this.s = checkNotNull(s, "s");
131 this.n = null;
132 this.l = null;
133 this.b = null;
134 this.date = null;
135 }
136
137 YamlImpl(final int n) {
138
139 this.map = null;
140 this.list = null;
141 this.s = null;
142 this.n = n;
143 this.l = (long) n;
144 this.b = null;
145 this.date = null;
146 }
147
148 YamlImpl(final long l) {
149
150 this.map = null;
151 this.list = null;
152 this.s = null;
153 this.n = null;
154 this.l = l;
155 this.b = null;
156 this.date = null;
157 }
158
159 YamlImpl(final boolean b) {
160
161 this.map = null;
162 this.list = null;
163 this.s = null;
164 this.n = null;
165 this.l = null;
166 this.b = b;
167 this.date = null;
168 }
169
170 YamlImpl(final Date date) {
171
172 this.map = null;
173 this.list = null;
174 this.s = null;
175 this.n = null;
176 this.l = null;
177 this.b = null;
178 this.date = checkNotNull(date, "date");
179 }
180
181 private YamlImpl() {
182
183 this.map = null;
184 this.list = null;
185 this.s = null;
186 this.n = null;
187 this.l = null;
188 this.b = null;
189 this.date = null;
190 }
191
192 @Override
193 public Iterable<Object> keys() {
194
195 return map.keySet();
196 }
197
198 @Override
199 public boolean has(final Object key) {
200
201 checkNotNull(key, "key");
202
203 return map != null && map.containsKey(key);
204 }
205
206 @Override
207 public Yaml get(final Object key) {
208
209 checkNotNull(key, "key");
210
211 checkState(map != null, "Internal map should not be null");
212
213 checkArgument(map.containsKey(key), "key: %s", key);
214
215 final Object value = map.get(key);
216
217 if (value == null) {
218
219 return YamlImpl.NULL;
220
221 } else {
222
223 return toYaml(value);
224 }
225 }
226
227 private static Yaml toYaml(final Object value) {
228
229 checkNotNull(value, "value");
230
231 if (value instanceof Map) {
232
233 @SuppressWarnings("unchecked")
234 final Map<Object, Object> map = (Map<Object, Object>) value;
235
236 return new YamlImpl(map);
237
238 } else if (value instanceof List) {
239
240 @SuppressWarnings("unchecked")
241 final List<Object> list = (List<Object>) value;
242
243 return new YamlImpl(list);
244
245 } else if (value instanceof String) {
246
247 final String s = (String) value;
248
249 return new YamlImpl(s);
250
251 } else if (value instanceof Integer) {
252
253 final int n = (Integer) value;
254
255 return new YamlImpl(n);
256
257 } else if (value instanceof Long) {
258
259 final long l = (Long) value;
260
261 return new YamlImpl(l);
262
263 } else if (value instanceof Boolean) {
264
265 final boolean b = (Boolean) value;
266
267 return new YamlImpl(b);
268
269 } else if (value instanceof Date) {
270
271 final Date date = (Date) value;
272
273 return new YamlImpl(date);
274 }
275
276 throw new NotImplementedException("value.class: " + value.getClass());
277 }
278
279 @Override
280 public Iterable<String> keysAsStrings() {
281
282 return map.keySet().stream()
283 .map(key -> key.toString())
284 .sorted()
285 .collect(Collectors.toList());
286 }
287
288 @Override
289 public boolean isArray() {
290
291 return list != null;
292 }
293
294 @Override
295 public boolean isMap() {
296
297 return map != null;
298 }
299
300 @Override
301 public boolean isString() {
302
303 return s != null;
304 }
305
306 @Override
307 public boolean isInt() {
308
309 return n != null;
310 }
311
312 @Override
313 public boolean isBoolean() {
314
315 return b != null;
316 }
317
318 @Override
319 public Date asDate() {
320
321 checkState(date != null, "Internal date should not be null");
322
323 return date;
324 }
325
326 @Override
327 public String asString() {
328
329 if (date != null) {
330
331 throw new NotImplementedException("date: " + date);
332
333 } else if (n != null) {
334
335 return Integer.toString(n);
336
337 } else if (l != null) {
338
339 return Long.toString(l);
340
341 } else if (b != null) {
342
343 return Boolean.toString(b);
344 }
345
346 checkState(s != null, "Internal string should not be null");
347
348 return s;
349 }
350
351 @Override
352 public int asInt() {
353
354 if (date != null) {
355
356 throw new NotImplementedException("date: " + date);
357 }
358
359 checkState(n != null, "Internal int should not be null");
360
361 return n;
362 }
363
364 @Override
365 public long asLong() {
366
367 if (date != null) {
368
369 throw new NotImplementedException("date: " + date);
370
371 } else if (l != null) {
372
373 return l;
374
375 } else if (n != null) {
376
377 return n;
378 }
379
380 throw new IllegalStateException("Internal long should not be null");
381 }
382
383 @Override
384 public boolean asBoolean() {
385
386 if (date != null) {
387 throw new NotImplementedException("date: " + date);
388 }
389
390 if (b != null) {
391
392 return b;
393 }
394
395 if (s != null) {
396
397 if ("yes".equals(s)) {
398
399 return true;
400
401 } else if ("no".equals(s)) {
402
403 return false;
404
405 } else {
406
407 throw new NotImplementedException("Cannot parse string to boolean: " + s);
408 }
409 }
410
411 throw new IllegalStateException("Internal boolean should not be null");
412 }
413
414 @Override
415 public Iterable<Yaml> items() {
416
417 return list.stream()
418 .map(item -> toYaml(item))
419 .collect(Collectors.toList());
420 }
421
422 @Override
423 public String toString() {
424
425 final StringBuilder sb = new StringBuilder("{");
426
427 if (s != null) {
428 sb.append(sb.length() == 1 ? "" : ", ").append("s: ").append(s);
429 }
430 if (n != null) {
431 sb.append(sb.length() == 1 ? "" : ", ").append("n: ").append(n);
432 }
433 if (l != null) {
434 sb.append(sb.length() == 1 ? "" : ", ").append("l: ").append(l);
435 }
436 if (b != null) {
437 sb.append(sb.length() == 1 ? "" : ", ").append("b: ").append(b);
438 }
439 if (date != null) {
440 sb.append(sb.length() == 1 ? "" : ", ").append("date: ").append(date);
441 }
442 if (list != null) {
443 sb.append(sb.length() == 1 ? "" : ", ").append("list: ").append(list);
444 }
445 if (map != null) {
446 sb.append(sb.length() == 1 ? "" : ", ").append("map: ").append(map);
447 }
448
449 return sb.append("}").toString();
450 }
451 }
452 }