WIP
[maven-thymeleaf-skin] / src / main / java / de / juplo / jackson / SimpleMapper.java
1 package de.juplo.jackson;
2
3
4 import com.fasterxml.jackson.core.JsonFactory;
5 import com.fasterxml.jackson.core.JsonLocation;
6 import com.fasterxml.jackson.core.JsonParser;
7 import com.fasterxml.jackson.core.JsonToken;
8 import java.io.File;
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.io.Reader;
12 import java.net.URL;
13 import java.util.Iterator;
14 import java.util.LinkedHashMap;
15 import java.util.LinkedList;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.NoSuchElementException;
20 import java.util.Spliterator;
21 import static java.util.Spliterator.IMMUTABLE;
22 import java.util.Spliterators;
23 import java.util.function.Consumer;
24 import java.util.stream.Stream;
25 import java.util.stream.StreamSupport;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29
30
31 /**
32  *
33  * @author kai
34  */
35 public class SimpleMapper
36 {
37   private static final Logger LOG =
38       LoggerFactory.getLogger(SimpleMapper.class);
39
40
41   private final JsonFactory factory;
42
43
44   public SimpleMapper(JsonFactory factory)
45   {
46     this.factory = factory;
47   }
48
49
50   public Spliterator<Object> getArraySpliterator(File file)
51       throws
52         IOException
53   {
54     return getArraySpliterator(factory.createParser(file));
55   }
56
57   public Spliterator<Object> getArraySpliterator(InputStream is)
58       throws
59         IOException
60   {
61     return getArraySpliterator(factory.createParser(is));
62   }
63
64   public Spliterator<Object> getArraySpliterator(Reader r)
65       throws
66         IOException
67   {
68     return getArraySpliterator(factory.createParser(r));
69   }
70
71   public Spliterator<Object> getArraySpliterator(String content)
72       throws
73         IOException
74   {
75     return getArraySpliterator(factory.createParser(content));
76   }
77
78   public Spliterator<Object> getArraySpliterator(URL url)
79       throws
80         IOException
81   {
82     return getArraySpliterator(factory.createParser(url));
83   }
84
85   public Spliterator<Object> getArraySpliterator(byte[] data)
86       throws
87         IOException
88   {
89     return getArraySpliterator(factory.createParser(data));
90   }
91
92   public Spliterator<Object> getArraySpliterator(char[] content)
93       throws
94         IOException
95   {
96     return getArraySpliterator(factory.createParser(content));
97   }
98
99   public Spliterator<Object> getArraySpliterator(byte[] data, int offset, int len)
100       throws
101         IOException
102   {
103     return getArraySpliterator(factory.createParser(data, offset, len));
104   }
105
106   public Spliterator<Object> getArraySpliterator(char[] data, int offset, int len)
107       throws
108         IOException
109   {
110     return getArraySpliterator(factory.createParser(data, offset, len));
111   }
112
113   public Stream<Object> getArrayStream(File file)
114       throws
115         IOException
116   {
117     return getArrayStream(factory.createParser(file));
118   }
119
120   public Stream<Object> getArrayStream(InputStream is)
121       throws
122         IOException
123   {
124     return getArrayStream(factory.createParser(is));
125   }
126
127   public Stream<Object> getArrayStream(Reader r)
128       throws
129         IOException
130   {
131     return getArrayStream(factory.createParser(r));
132   }
133
134   public Stream<Object> getArrayStream(String content)
135       throws
136         IOException
137   {
138     return getArrayStream(factory.createParser(content));
139   }
140
141   public Stream<Object> getArrayStream(URL url)
142       throws
143         IOException
144   {
145     return getArrayStream(factory.createParser(url));
146   }
147
148   public Stream<Object> getArrayStream(byte[] data)
149       throws
150         IOException
151   {
152     return getArrayStream(factory.createParser(data));
153   }
154
155   public Stream<Object> getArrayStream(char[] content)
156       throws
157         IOException
158   {
159     return getArrayStream(factory.createParser(content));
160   }
161
162   public Stream<Object> getArrayStream(byte[] data, int offset, int len)
163       throws
164         IOException
165   {
166     return getArrayStream(factory.createParser(data, offset, len));
167   }
168
169   public Stream<Object> getArrayStream(char[] data, int offset, int len)
170       throws
171         IOException
172   {
173     return getArrayStream(factory.createParser(data, offset, len));
174   }
175
176   public Iterator<Object> getArrayIterator(File file)
177       throws
178         IOException
179   {
180     return getArrayIterator(factory.createParser(file));
181   }
182
183   public Iterator<Object> getArrayIterator(InputStream is)
184       throws
185         IOException
186   {
187     return getArrayIterator(factory.createParser(is));
188   }
189
190   public Iterator<Object> getArrayIterator(Reader r)
191       throws
192         IOException
193   {
194     return getArrayIterator(factory.createParser(r));
195   }
196
197   public Iterator<Object> getArrayIterator(String content)
198       throws
199         IOException
200   {
201     return getArrayIterator(factory.createParser(content));
202   }
203
204   public Iterator<Object> getArrayIterator(URL url)
205       throws
206         IOException
207   {
208     return getArrayIterator(factory.createParser(url));
209   }
210
211   public Iterator<Object> getArrayIterator(byte[] data)
212       throws
213         IOException
214   {
215     return getArrayIterator(factory.createParser(data));
216   }
217
218   public Iterator<Object> getArrayIterator(char[] content)
219       throws
220         IOException
221   {
222     return getArrayIterator(factory.createParser(content));
223   }
224
225   public Iterator<Object> getArrayIterator(byte[] data, int offset, int len)
226       throws
227         IOException
228   {
229     return getArrayIterator(factory.createParser(data, offset, len));
230   }
231
232   public Iterator<Object> getArrayIterator(char[] data, int offset, int len)
233       throws
234         IOException
235   {
236     return getArrayIterator(factory.createParser(data, offset, len));
237   }
238
239
240   public Spliterator<Entry<String, Object>> getObjectSpliterator(File file)
241       throws
242         IOException
243   {
244     return getObjectSpliterator(factory.createParser(file));
245   }
246
247   public Spliterator<Entry<String, Object>> getObjectSpliterator(InputStream is)
248       throws
249         IOException
250   {
251     return getObjectSpliterator(factory.createParser(is));
252   }
253
254   public Spliterator<Entry<String, Object>> getObjectSpliterator(Reader r)
255       throws
256         IOException
257   {
258     return getObjectSpliterator(factory.createParser(r));
259   }
260
261   public Spliterator<Entry<String, Object>> getObjectSpliterator(String content)
262       throws
263         IOException
264   {
265     return getObjectSpliterator(factory.createParser(content));
266   }
267
268   public Spliterator<Entry<String, Object>> getObjectSpliterator(URL url)
269       throws
270         IOException
271   {
272     return getObjectSpliterator(factory.createParser(url));
273   }
274
275   public Spliterator<Entry<String, Object>> getObjectSpliterator(byte[] data)
276       throws
277         IOException
278   {
279     return getObjectSpliterator(factory.createParser(data));
280   }
281
282   public Spliterator<Entry<String, Object>> getObjectSpliterator(char[] content)
283       throws
284         IOException
285   {
286     return getObjectSpliterator(factory.createParser(content));
287   }
288
289   public Spliterator<Entry<String, Object>> getObjectSpliterator(byte[] data, int offset, int len)
290       throws
291         IOException
292   {
293     return getObjectSpliterator(factory.createParser(data, offset, len));
294   }
295
296   public Spliterator<Entry<String, Object>> getObjectSpliterator(char[] data, int offset, int len)
297       throws
298         IOException
299   {
300     return getObjectSpliterator(factory.createParser(data, offset, len));
301   }
302
303   public Stream<Entry<String, Object>> getObjectStream(File file)
304       throws
305         IOException
306   {
307     return getObjectStream(factory.createParser(file));
308   }
309
310   public Stream<Entry<String, Object>> getObjectStream(InputStream is)
311       throws
312         IOException
313   {
314     return getObjectStream(factory.createParser(is));
315   }
316
317   public Stream<Entry<String, Object>> getObjectStream(Reader r)
318       throws
319         IOException
320   {
321     return getObjectStream(factory.createParser(r));
322   }
323
324   public Stream<Entry<String, Object>> getObjectStream(String content)
325       throws
326         IOException
327   {
328     return getObjectStream(factory.createParser(content));
329   }
330
331   public Stream<Entry<String, Object>> getObjectStream(URL url)
332       throws
333         IOException
334   {
335     return getObjectStream(factory.createParser(url));
336   }
337
338   public Stream<Entry<String, Object>> getObjectStream(byte[] data)
339       throws
340         IOException
341   {
342     return getObjectStream(factory.createParser(data));
343   }
344
345   public Stream<Entry<String, Object>> getObjectStream(char[] content)
346       throws
347         IOException
348   {
349     return getObjectStream(factory.createParser(content));
350   }
351
352   public Stream<Entry<String, Object>> getObjectStream(byte[] data, int offset, int len)
353       throws
354         IOException
355   {
356     return getObjectStream(factory.createParser(data, offset, len));
357   }
358
359   public Stream<Entry<String, Object>> getObjectStream(char[] data, int offset, int len)
360       throws
361         IOException
362   {
363     return getObjectStream(factory.createParser(data, offset, len));
364   }
365
366   public Iterator<Entry<String, Object>> getObjectIterator(File file)
367       throws
368         IOException
369   {
370     return getObjectIterator(factory.createParser(file));
371   }
372
373   public Iterator<Entry<String, Object>> getObjectIterator(InputStream is)
374       throws
375         IOException
376   {
377     return getObjectIterator(factory.createParser(is));
378   }
379
380   public Iterator<Entry<String, Object>> getObjectIterator(Reader r)
381       throws
382         IOException
383   {
384     return getObjectIterator(factory.createParser(r));
385   }
386
387   public Iterator<Entry<String, Object>> getObjectIterator(String content)
388       throws
389         IOException
390   {
391     return getObjectIterator(factory.createParser(content));
392   }
393
394   public Iterator<Entry<String, Object>> getObjectIterator(URL url)
395       throws
396         IOException
397   {
398     return getObjectIterator(factory.createParser(url));
399   }
400
401   public Iterator<Entry<String, Object>> getObjectIterator(byte[] data)
402       throws
403         IOException
404   {
405     return getObjectIterator(factory.createParser(data));
406   }
407
408   public Iterator<Entry<String, Object>> getObjectIterator(char[] content)
409       throws
410         IOException
411   {
412     return getObjectIterator(factory.createParser(content));
413   }
414
415   public Iterator<Entry<String, Object>> getObjectIterator(byte[] data, int offset, int len)
416       throws
417         IOException
418   {
419     return getObjectIterator(factory.createParser(data, offset, len));
420   }
421
422   public Iterator<Entry<String, Object>> getObjectIterator(char[] data, int offset, int len)
423       throws
424         IOException
425   {
426     return getObjectIterator(factory.createParser(data, offset, len));
427   }
428
429
430   public static Spliterator<Object> getArraySpliterator(final JsonParser parser)
431       throws
432         IOException
433   {
434     JsonToken token = parser.nextToken();
435
436     if (token == null)
437     {
438       LOG.warn("empty input");
439       return Spliterators.emptySpliterator();
440     }
441
442     if (!JsonToken.START_ARRAY.equals(token))
443       fail(parser, "The root-element must be an array!");
444
445     return new Spliterator<Object>()
446     {
447       @Override
448       public boolean tryAdvance(Consumer<? super Object> action)
449       {
450         try
451         {
452           JsonToken token = parser.nextToken();
453           if (token == null)
454             fail(parser, "Unexpected end of data!");
455           if (JsonToken.END_ARRAY.equals(token))
456             return false;
457           action.accept(convert(parser));
458           return true;
459         }
460         catch (IOException e)
461         {
462           throw new IllegalArgumentException(e);
463         }
464       }
465
466       @Override
467       public Spliterator<Object> trySplit()
468       {
469         return null;
470       }
471
472       @Override
473       public long estimateSize()
474       {
475         return Long.MAX_VALUE;
476       }
477
478       @Override
479       public int characteristics()
480       {
481         return IMMUTABLE;
482       }
483     };
484   }
485
486   public static Stream<Object> getArrayStream(final JsonParser parser)
487       throws
488         IOException
489   {
490     return StreamSupport.stream(getArraySpliterator(parser), false);
491   }
492
493   public static Iterator<Object> getArrayIterator(final JsonParser parser)
494       throws
495         IOException
496   {
497     Spliterator<Object> spliterator = getArraySpliterator(parser);
498     return new Iterator<Object>()
499     {
500       private Object next = null;
501
502
503       @Override
504       public boolean hasNext()
505       {
506         if (next != null)
507           return true;
508
509         return spliterator.tryAdvance(new Consumer<Object>()
510         {
511           @Override
512           public void accept(Object o)
513           {
514             next = o;
515           }
516         });
517       }
518
519       @Override
520       public Object next()
521       {
522         if (next == null && !hasNext())
523           throw new NoSuchElementException();
524         Object o = next;
525         next = null;
526         return o;
527       }
528     };
529   }
530
531
532   public static Spliterator<Entry<String, Object>> getObjectSpliterator(final JsonParser parser)
533       throws
534         IOException
535   {
536     JsonToken token = parser.nextToken();
537
538     if (token == null)
539     {
540       LOG.warn("empty input");
541       return Spliterators.emptySpliterator();
542     }
543
544     if (!JsonToken.START_OBJECT.equals(token))
545       fail(parser, "The root-element must be an array!");
546
547     return new Spliterator<Entry<String, Object>>()
548     {
549       @Override
550       public boolean tryAdvance(Consumer<? super Entry<String, Object>> action)
551       {
552         try
553         {
554           JsonToken token = parser.nextToken();
555           if (token == null)
556             fail(parser, "Unexpected end of data!");
557           if (JsonToken.END_OBJECT.equals(token))
558             return false;
559           if (!JsonToken.FIELD_NAME.equals(token))
560             fail(parser, "expected a field-name");
561           final String key = parser.getText();
562           parser.nextToken();
563           final Object value = convert(parser);
564           action.accept(new Entry<String, Object>()
565           {
566             @Override
567             public String getKey()
568             {
569               return key;
570             }
571
572             @Override
573             public Object getValue()
574             {
575               return value;
576             }
577
578             @Override
579             public Object setValue(Object value)
580             {
581               throw new UnsupportedOperationException("Not supported.");
582             }
583           });
584           return true;
585         }
586         catch (IOException e)
587         {
588           throw new IllegalArgumentException(e);
589         }
590       }
591
592       @Override
593       public Spliterator<Entry<String, Object>> trySplit()
594       {
595         return null;
596       }
597
598       @Override
599       public long estimateSize()
600       {
601         return Long.MAX_VALUE;
602       }
603
604       @Override
605       public int characteristics()
606       {
607         return IMMUTABLE;
608       }
609     };
610   }
611
612   public static Stream<Entry<String, Object>> getObjectStream(final JsonParser parser)
613       throws
614         IOException
615   {
616     return StreamSupport.stream(getObjectSpliterator(parser), false);
617   }
618
619   public static Iterator<Entry<String, Object>> getObjectIterator(
620       final JsonParser parser
621       )
622       throws
623         IOException
624   {
625     Spliterator<Entry<String, Object>> spliterator = getObjectSpliterator(parser);
626     return new Iterator<Entry<String, Object>>()
627     {
628       private Entry<String, Object> next = null;
629
630
631       @Override
632       public boolean hasNext()
633       {
634         if (next != null)
635           return true;
636
637         return spliterator.tryAdvance(new Consumer<Entry<String, Object>>()
638         {
639           @Override
640           public void accept(Entry<String, Object> e)
641           {
642             next = e;
643           }
644         });
645       }
646
647       @Override
648       public Entry<String, Object> next()
649       {
650         if (next == null && !hasNext())
651           throw new NoSuchElementException();
652         Entry<String, Object> e = next;
653         next = null;
654         return e;
655       }
656     };
657   }
658
659
660   static Object convert(JsonParser parser) throws IOException
661   {
662     JsonToken token = parser.getCurrentToken();
663     if (token == null)
664       fail(parser, "unexpected EOF");
665
666     switch (token)
667     {
668       case VALUE_STRING:       return parser.getText();
669       case VALUE_NUMBER_INT:   return parser.getIntValue();
670       case VALUE_NUMBER_FLOAT: return parser.getDoubleValue();
671       case START_OBJECT:       return convertObject(parser);
672       case START_ARRAY:        return convertArray(parser);
673       case VALUE_TRUE:         return Boolean.TRUE;
674       case VALUE_FALSE:        return Boolean.FALSE;
675       case VALUE_NULL:         return null;
676     }
677
678     fail(parser, "unexpected token " + token.toString());
679     return null; // << Will never be reached, because fail always throws an exception
680   }
681
682
683   static Map<String, Object> convertObject(JsonParser parser) throws IOException
684   {
685     JsonToken token = parser.nextToken();
686     if (token == null)
687       fail(parser, "unexpected EOF");
688
689     Map<String, Object> map = new LinkedHashMap<>();
690
691     while (!JsonToken.END_OBJECT.equals(token))
692     {
693       if (!JsonToken.FIELD_NAME.equals(token))
694         fail(parser, "expected a field-name");
695
696       String name = parser.getText();
697       parser.nextToken();
698       Object value = convert(parser);
699       map.put(name, value);
700
701       token = parser.nextToken();
702       if (token == null)
703         fail(parser, "unexpected EOF");
704     }
705
706     return map;
707   }
708
709   static List<Object> convertArray(JsonParser parser) throws IOException
710   {
711     JsonToken token = parser.nextToken();
712     if (token == null)
713       fail(parser, "unexpected EOF");
714
715     List<Object> list = new LinkedList<>();
716
717     while (!JsonToken.END_ARRAY.equals(token))
718     {
719       list.add(convert(parser));
720
721       token = parser.nextToken();
722       if (token == null)
723         fail(parser, "unexpected EOF");
724     }
725
726     return list;
727   }
728
729
730   static void fail(JsonParser parser, String message)
731   {
732     JsonLocation location = parser.getCurrentLocation();
733     LOG.error(
734         "{} at char-offset {} (line {}, column {})",
735         message,
736         location.getCharOffset(),
737         location.getLineNr(),
738         location.getColumnNr()
739         );
740     throw new IllegalArgumentException("Cannot parse JSON: " + message);
741   }
742 }