Initial implementation of SimpleMapper
[simple-mapper] / 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.Collections;
14 import java.util.Iterator;
15 import java.util.LinkedHashMap;
16 import java.util.LinkedList;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.NoSuchElementException;
21 import java.util.Spliterator;
22 import static java.util.Spliterator.IMMUTABLE;
23 import java.util.Spliterators;
24 import java.util.function.Consumer;
25 import java.util.stream.Stream;
26 import java.util.stream.StreamSupport;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30
31
32 /**
33  *
34  * @author kai
35  */
36 public class SimpleMapper
37 {
38   private static final Logger LOG =
39       LoggerFactory.getLogger(SimpleMapper.class);
40
41
42   private final JsonFactory factory;
43
44
45   public SimpleMapper(JsonFactory factory)
46   {
47     this.factory = factory;
48   }
49
50
51   public Spliterator<Object> getArraySpliterator(File file)
52       throws
53         IOException
54   {
55     return getArraySpliterator(factory.createParser(file));
56   }
57
58   public Spliterator<Object> getArraySpliterator(InputStream is)
59       throws
60         IOException
61   {
62     return getArraySpliterator(factory.createParser(is));
63   }
64
65   public Spliterator<Object> getArraySpliterator(Reader r)
66       throws
67         IOException
68   {
69     return getArraySpliterator(factory.createParser(r));
70   }
71
72   public Spliterator<Object> getArraySpliterator(String content)
73       throws
74         IOException
75   {
76     return getArraySpliterator(factory.createParser(content));
77   }
78
79   public Spliterator<Object> getArraySpliterator(URL url)
80       throws
81         IOException
82   {
83     return getArraySpliterator(factory.createParser(url));
84   }
85
86   public Spliterator<Object> getArraySpliterator(byte[] data)
87       throws
88         IOException
89   {
90     return getArraySpliterator(factory.createParser(data));
91   }
92
93   public Spliterator<Object> getArraySpliterator(char[] content)
94       throws
95         IOException
96   {
97     return getArraySpliterator(factory.createParser(content));
98   }
99
100   public Spliterator<Object> getArraySpliterator(byte[] data, int offset, int len)
101       throws
102         IOException
103   {
104     return getArraySpliterator(factory.createParser(data, offset, len));
105   }
106
107   public Spliterator<Object> getArraySpliterator(char[] data, int offset, int len)
108       throws
109         IOException
110   {
111     return getArraySpliterator(factory.createParser(data, offset, len));
112   }
113
114   public Stream<Object> getArrayStream(File file)
115       throws
116         IOException
117   {
118     return getArrayStream(factory.createParser(file));
119   }
120
121   public Stream<Object> getArrayStream(InputStream is)
122       throws
123         IOException
124   {
125     return getArrayStream(factory.createParser(is));
126   }
127
128   public Stream<Object> getArrayStream(Reader r)
129       throws
130         IOException
131   {
132     return getArrayStream(factory.createParser(r));
133   }
134
135   public Stream<Object> getArrayStream(String content)
136       throws
137         IOException
138   {
139     return getArrayStream(factory.createParser(content));
140   }
141
142   public Stream<Object> getArrayStream(URL url)
143       throws
144         IOException
145   {
146     return getArrayStream(factory.createParser(url));
147   }
148
149   public Stream<Object> getArrayStream(byte[] data)
150       throws
151         IOException
152   {
153     return getArrayStream(factory.createParser(data));
154   }
155
156   public Stream<Object> getArrayStream(char[] content)
157       throws
158         IOException
159   {
160     return getArrayStream(factory.createParser(content));
161   }
162
163   public Stream<Object> getArrayStream(byte[] data, int offset, int len)
164       throws
165         IOException
166   {
167     return getArrayStream(factory.createParser(data, offset, len));
168   }
169
170   public Stream<Object> getArrayStream(char[] data, int offset, int len)
171       throws
172         IOException
173   {
174     return getArrayStream(factory.createParser(data, offset, len));
175   }
176
177   public Iterator<Object> getArrayIterator(File file)
178       throws
179         IOException
180   {
181     return getArrayIterator(factory.createParser(file));
182   }
183
184   public Iterator<Object> getArrayIterator(InputStream is)
185       throws
186         IOException
187   {
188     return getArrayIterator(factory.createParser(is));
189   }
190
191   public Iterator<Object> getArrayIterator(Reader r)
192       throws
193         IOException
194   {
195     return getArrayIterator(factory.createParser(r));
196   }
197
198   public Iterator<Object> getArrayIterator(String content)
199       throws
200         IOException
201   {
202     return getArrayIterator(factory.createParser(content));
203   }
204
205   public Iterator<Object> getArrayIterator(URL url)
206       throws
207         IOException
208   {
209     return getArrayIterator(factory.createParser(url));
210   }
211
212   public Iterator<Object> getArrayIterator(byte[] data)
213       throws
214         IOException
215   {
216     return getArrayIterator(factory.createParser(data));
217   }
218
219   public Iterator<Object> getArrayIterator(char[] content)
220       throws
221         IOException
222   {
223     return getArrayIterator(factory.createParser(content));
224   }
225
226   public Iterator<Object> getArrayIterator(byte[] data, int offset, int len)
227       throws
228         IOException
229   {
230     return getArrayIterator(factory.createParser(data, offset, len));
231   }
232
233   public Iterator<Object> getArrayIterator(char[] data, int offset, int len)
234       throws
235         IOException
236   {
237     return getArrayIterator(factory.createParser(data, offset, len));
238   }
239
240
241   public Spliterator<Entry<String, Object>> getObjectSpliterator(File file)
242       throws
243         IOException
244   {
245     return getObjectSpliterator(factory.createParser(file));
246   }
247
248   public Spliterator<Entry<String, Object>> getObjectSpliterator(InputStream is)
249       throws
250         IOException
251   {
252     return getObjectSpliterator(factory.createParser(is));
253   }
254
255   public Spliterator<Entry<String, Object>> getObjectSpliterator(Reader r)
256       throws
257         IOException
258   {
259     return getObjectSpliterator(factory.createParser(r));
260   }
261
262   public Spliterator<Entry<String, Object>> getObjectSpliterator(String content)
263       throws
264         IOException
265   {
266     return getObjectSpliterator(factory.createParser(content));
267   }
268
269   public Spliterator<Entry<String, Object>> getObjectSpliterator(URL url)
270       throws
271         IOException
272   {
273     return getObjectSpliterator(factory.createParser(url));
274   }
275
276   public Spliterator<Entry<String, Object>> getObjectSpliterator(byte[] data)
277       throws
278         IOException
279   {
280     return getObjectSpliterator(factory.createParser(data));
281   }
282
283   public Spliterator<Entry<String, Object>> getObjectSpliterator(char[] content)
284       throws
285         IOException
286   {
287     return getObjectSpliterator(factory.createParser(content));
288   }
289
290   public Spliterator<Entry<String, Object>> getObjectSpliterator(byte[] data, int offset, int len)
291       throws
292         IOException
293   {
294     return getObjectSpliterator(factory.createParser(data, offset, len));
295   }
296
297   public Spliterator<Entry<String, Object>> getObjectSpliterator(char[] data, int offset, int len)
298       throws
299         IOException
300   {
301     return getObjectSpliterator(factory.createParser(data, offset, len));
302   }
303
304   public Stream<Entry<String, Object>> getObjectStream(File file)
305       throws
306         IOException
307   {
308     return getObjectStream(factory.createParser(file));
309   }
310
311   public Stream<Entry<String, Object>> getObjectStream(InputStream is)
312       throws
313         IOException
314   {
315     return getObjectStream(factory.createParser(is));
316   }
317
318   public Stream<Entry<String, Object>> getObjectStream(Reader r)
319       throws
320         IOException
321   {
322     return getObjectStream(factory.createParser(r));
323   }
324
325   public Stream<Entry<String, Object>> getObjectStream(String content)
326       throws
327         IOException
328   {
329     return getObjectStream(factory.createParser(content));
330   }
331
332   public Stream<Entry<String, Object>> getObjectStream(URL url)
333       throws
334         IOException
335   {
336     return getObjectStream(factory.createParser(url));
337   }
338
339   public Stream<Entry<String, Object>> getObjectStream(byte[] data)
340       throws
341         IOException
342   {
343     return getObjectStream(factory.createParser(data));
344   }
345
346   public Stream<Entry<String, Object>> getObjectStream(char[] content)
347       throws
348         IOException
349   {
350     return getObjectStream(factory.createParser(content));
351   }
352
353   public Stream<Entry<String, Object>> getObjectStream(byte[] data, int offset, int len)
354       throws
355         IOException
356   {
357     return getObjectStream(factory.createParser(data, offset, len));
358   }
359
360   public Stream<Entry<String, Object>> getObjectStream(char[] data, int offset, int len)
361       throws
362         IOException
363   {
364     return getObjectStream(factory.createParser(data, offset, len));
365   }
366
367   public Iterator<Entry<String, Object>> getObjectIterator(File file)
368       throws
369         IOException
370   {
371     return getObjectIterator(factory.createParser(file));
372   }
373
374   public Iterator<Entry<String, Object>> getObjectIterator(InputStream is)
375       throws
376         IOException
377   {
378     return getObjectIterator(factory.createParser(is));
379   }
380
381   public Iterator<Entry<String, Object>> getObjectIterator(Reader r)
382       throws
383         IOException
384   {
385     return getObjectIterator(factory.createParser(r));
386   }
387
388   public Iterator<Entry<String, Object>> getObjectIterator(String content)
389       throws
390         IOException
391   {
392     return getObjectIterator(factory.createParser(content));
393   }
394
395   public Iterator<Entry<String, Object>> getObjectIterator(URL url)
396       throws
397         IOException
398   {
399     return getObjectIterator(factory.createParser(url));
400   }
401
402   public Iterator<Entry<String, Object>> getObjectIterator(byte[] data)
403       throws
404         IOException
405   {
406     return getObjectIterator(factory.createParser(data));
407   }
408
409   public Iterator<Entry<String, Object>> getObjectIterator(char[] content)
410       throws
411         IOException
412   {
413     return getObjectIterator(factory.createParser(content));
414   }
415
416   public Iterator<Entry<String, Object>> getObjectIterator(byte[] data, int offset, int len)
417       throws
418         IOException
419   {
420     return getObjectIterator(factory.createParser(data, offset, len));
421   }
422
423   public Iterator<Entry<String, Object>> getObjectIterator(char[] data, int offset, int len)
424       throws
425         IOException
426   {
427     return getObjectIterator(factory.createParser(data, offset, len));
428   }
429
430
431   public static Spliterator<Object> getArraySpliterator(final JsonParser parser)
432       throws
433         IOException
434   {
435     JsonToken token = parser.nextToken();
436
437     if (token == null)
438     {
439       LOG.warn("empty input");
440       return Spliterators.emptySpliterator();
441     }
442
443     if (!JsonToken.START_ARRAY.equals(token))
444       fail(parser, "The root-element must be an array!");
445
446     return new Spliterator<Object>()
447     {
448       @Override
449       public boolean tryAdvance(Consumer<? super Object> action)
450       {
451         try
452         {
453           JsonToken token = parser.nextToken();
454           if (token == null)
455             fail(parser, "Unexpected end of data!");
456           if (JsonToken.END_ARRAY.equals(token))
457           {
458             if (parser.nextToken() != null)
459               fail(parser, "unexpected data after parsed array");
460             return false;
461           }
462           action.accept(convertInternal(parser));
463           return true;
464         }
465         catch (IOException e)
466         {
467           throw new IllegalArgumentException(e);
468         }
469       }
470
471       @Override
472       public Spliterator<Object> trySplit()
473       {
474         return null;
475       }
476
477       @Override
478       public long estimateSize()
479       {
480         return Long.MAX_VALUE;
481       }
482
483       @Override
484       public int characteristics()
485       {
486         return IMMUTABLE;
487       }
488     };
489   }
490
491   public static Stream<Object> getArrayStream(final JsonParser parser)
492       throws
493         IOException
494   {
495     return StreamSupport.stream(getArraySpliterator(parser), false);
496   }
497
498   public static Iterator<Object> getArrayIterator(final JsonParser parser)
499       throws
500         IOException
501   {
502     Spliterator<Object> spliterator = getArraySpliterator(parser);
503     return new Iterator<Object>()
504     {
505       private Object next = null;
506
507
508       @Override
509       public boolean hasNext()
510       {
511         if (next != null)
512           return true;
513
514         return spliterator.tryAdvance(new Consumer<Object>()
515         {
516           @Override
517           public void accept(Object o)
518           {
519             next = o;
520           }
521         });
522       }
523
524       @Override
525       public Object next()
526       {
527         if (next == null && !hasNext())
528           throw new NoSuchElementException();
529         Object o = next;
530         next = null;
531         return o;
532       }
533     };
534   }
535
536
537   public static Spliterator<Entry<String, Object>> getObjectSpliterator(final JsonParser parser)
538       throws
539         IOException
540   {
541     JsonToken token = parser.nextToken();
542
543     if (token == null)
544     {
545       LOG.warn("empty input");
546       return Spliterators.emptySpliterator();
547     }
548
549     if (!JsonToken.START_OBJECT.equals(token))
550       fail(parser, "The root-element must be an object!");
551
552     return new Spliterator<Entry<String, Object>>()
553     {
554       @Override
555       public boolean tryAdvance(Consumer<? super Entry<String, Object>> action)
556       {
557         try
558         {
559           JsonToken token = parser.nextToken();
560           if (token == null)
561             fail(parser, "Unexpected end of data!");
562           if (JsonToken.END_OBJECT.equals(token))
563           {
564             if (parser.nextToken() != null)
565               fail(parser, "unexpected data after parsed object");
566             return false;
567           }
568           if (!JsonToken.FIELD_NAME.equals(token))
569             fail(parser, "expected a field-name");
570           final String key = parser.getText();
571           parser.nextToken();
572           final Object value = convertInternal(parser);
573           action.accept(new Entry<String, Object>()
574           {
575             @Override
576             public String getKey()
577             {
578               return key;
579             }
580
581             @Override
582             public Object getValue()
583             {
584               return value;
585             }
586
587             @Override
588             public Object setValue(Object value)
589             {
590               throw new UnsupportedOperationException("Not supported.");
591             }
592           });
593           return true;
594         }
595         catch (IOException e)
596         {
597           throw new IllegalArgumentException(e);
598         }
599       }
600
601       @Override
602       public Spliterator<Entry<String, Object>> trySplit()
603       {
604         return null;
605       }
606
607       @Override
608       public long estimateSize()
609       {
610         return Long.MAX_VALUE;
611       }
612
613       @Override
614       public int characteristics()
615       {
616         return IMMUTABLE;
617       }
618     };
619   }
620
621   public static Stream<Entry<String, Object>> getObjectStream(final JsonParser parser)
622       throws
623         IOException
624   {
625     return StreamSupport.stream(getObjectSpliterator(parser), false);
626   }
627
628   public static Iterator<Entry<String, Object>> getObjectIterator(
629       final JsonParser parser
630       )
631       throws
632         IOException
633   {
634     Spliterator<Entry<String, Object>> spliterator = getObjectSpliterator(parser);
635     return new Iterator<Entry<String, Object>>()
636     {
637       private Entry<String, Object> next = null;
638
639
640       @Override
641       public boolean hasNext()
642       {
643         if (next != null)
644           return true;
645
646         return spliterator.tryAdvance(new Consumer<Entry<String, Object>>()
647         {
648           @Override
649           public void accept(Entry<String, Object> e)
650           {
651             next = e;
652           }
653         });
654       }
655
656       @Override
657       public Entry<String, Object> next()
658       {
659         if (next == null && !hasNext())
660           throw new NoSuchElementException();
661         Entry<String, Object> e = next;
662         next = null;
663         return e;
664       }
665     };
666   }
667
668
669   public List<Object> convertArray(File file) throws Exception
670   {
671     return convertArray(factory.createParser(file));
672   }
673
674   public List<Object> convertArray(InputStream is) throws Exception
675   {
676     return convertArray(factory.createParser(is));
677   }
678
679   public List<Object> convertArray(Reader r) throws Exception
680   {
681     return convertArray(factory.createParser(r));
682   }
683
684   public List<Object> convertArray(String content) throws Exception
685   {
686     return convertArray(factory.createParser(content));
687   }
688
689   public List<Object> convertArray(URL url) throws Exception
690   {
691     return convertArray(factory.createParser(url));
692   }
693
694   public List<Object> convertArray(byte[] data) throws Exception
695   {
696     return convertArray(factory.createParser(data));
697   }
698
699   public List<Object> convertArray(char[] content) throws Exception
700   {
701     return convertArray(factory.createParser(content));
702   }
703
704   public List<Object> convertArray(byte[] data, int offset, int len)
705       throws
706         Exception
707   {
708     return convertArray(factory.createParser(data, offset, len));
709   }
710
711   public List<Object> convertArray(char[] content, int offset, int len)
712       throws
713         Exception
714   {
715     return convertArray(factory.createParser(content, offset, len));
716   }
717
718   public Map<String, Object> convertObject(File file) throws Exception
719   {
720     return convertObject(factory.createParser(file));
721   }
722
723   public Map<String, Object> convertObject(InputStream is) throws Exception
724   {
725     return convertObject(factory.createParser(is));
726   }
727
728   public Map<String, Object> convertObject(Reader r) throws Exception
729   {
730     return convertObject(factory.createParser(r));
731   }
732
733   public Map<String, Object> convertObject(String content) throws Exception
734   {
735     return convertObject(factory.createParser(content));
736   }
737
738   public Map<String, Object> convertObject(URL url) throws Exception
739   {
740     return convertObject(factory.createParser(url));
741   }
742
743   public Map<String, Object> convertObject(byte[] data) throws Exception
744   {
745     return convertObject(factory.createParser(data));
746   }
747
748   public Map<String, Object> convertObject(char[] content) throws Exception
749   {
750     return convertObject(factory.createParser(content));
751   }
752
753   public Map<String, Object> convertObject(byte[] data, int offset, int len)
754       throws
755         Exception
756   {
757     return convertObject(factory.createParser(data, offset, len));
758   }
759
760   public Map<String, Object> convertObject(char[] content, int offset, int len)
761       throws
762         Exception
763   {
764     return convertObject(factory.createParser(content, offset, len));
765   }
766
767   public Object convert(File file) throws Exception
768   {
769     return convert(factory.createParser(file));
770   }
771
772   public Object convert(InputStream is) throws Exception
773   {
774     return convert(factory.createParser(is));
775   }
776
777   public Object convert(Reader r) throws Exception
778   {
779     return convert(factory.createParser(r));
780   }
781
782   public Object convert(String content) throws Exception
783   {
784     return convert(factory.createParser(content));
785   }
786
787   public Object convert(URL url) throws Exception
788   {
789     return convert(factory.createParser(url));
790   }
791
792   public Object convert(byte[] data) throws Exception
793   {
794     return convert(factory.createParser(data));
795   }
796
797   public Object convert(char[] content) throws Exception
798   {
799     return convert(factory.createParser(content));
800   }
801
802   public Object convert(byte[] data, int offset, int len)
803       throws
804         Exception
805   {
806     return convert(factory.createParser(data, offset, len));
807   }
808
809   public Object convert(char[] content, int offset, int len)
810       throws
811         Exception
812   {
813     return convert(factory.createParser(content, offset, len));
814   }
815
816
817   static List<Object> convertArray(JsonParser parser) throws IOException
818   {
819     JsonToken token = parser.nextToken();
820
821     if (token == null)
822     {
823       LOG.warn("empty input");
824       return Collections.EMPTY_LIST;
825     }
826
827     if (!JsonToken.START_ARRAY.equals(token))
828       fail(parser, "The root-element must be an array!");
829
830     List<Object> array = convertArrayInternal(parser);
831
832     if (parser.nextToken() != null)
833       fail(parser, "unexpected data after parsed array");
834
835     return array;
836   }
837
838   static Map<String, Object> convertObject(JsonParser parser) throws IOException
839   {
840     JsonToken token = parser.nextToken();
841
842     if (token == null)
843     {
844       LOG.warn("empty input");
845       return Collections.EMPTY_MAP;
846     }
847
848     if (!JsonToken.START_OBJECT.equals(token))
849       fail(parser, "The root-element must be an object!");
850
851     Map<String, Object> object = convertObjectInternal(parser);
852
853     if (parser.nextToken() != null)
854       fail(parser, "unexpected data after parsed object");
855
856     return object;
857   }
858
859   static Object convert(JsonParser parser) throws IOException
860   {
861     JsonToken token = parser.nextToken();
862
863     if (token == null)
864     {
865       LOG.warn("empty input");
866       return null;
867     }
868
869     switch (token)
870     {
871       case START_ARRAY:
872       case START_OBJECT:
873         break;
874       default:
875         fail(parser, "The root-element must be either an object or an array!");
876     }
877
878     Object object = convertInternal(parser);
879
880     if (parser.nextToken() != null)
881       fail(parser, "unexpected data after parsed object");
882
883     return object;
884   }
885
886
887   static Object convertInternal(JsonParser parser) throws IOException
888   {
889     JsonToken token = parser.getCurrentToken();
890     if (token == null)
891       fail(parser, "unexpected EOF");
892
893     switch (token)
894     {
895       case VALUE_STRING:       return parser.getText();
896       case VALUE_NUMBER_INT:   return parser.getIntValue();
897       case VALUE_NUMBER_FLOAT: return parser.getDoubleValue();
898       case START_OBJECT:       return convertObjectInternal(parser);
899       case START_ARRAY:        return convertArrayInternal(parser);
900       case VALUE_TRUE:         return Boolean.TRUE;
901       case VALUE_FALSE:        return Boolean.FALSE;
902       case VALUE_NULL:         return null;
903     }
904
905     fail(parser, "unexpected token " + token.toString());
906     return null; // << Will never be reached, because fail always throws an exception
907   }
908
909
910   static Map<String, Object> convertObjectInternal(JsonParser parser)
911       throws
912         IOException
913   {
914     JsonToken token = parser.nextToken();
915     if (token == null)
916       fail(parser, "unexpected EOF");
917
918     Map<String, Object> map = new LinkedHashMap<>();
919
920     while (!JsonToken.END_OBJECT.equals(token))
921     {
922       if (!JsonToken.FIELD_NAME.equals(token))
923         fail(parser, "expected a field-name");
924
925       String name = parser.getText();
926       parser.nextToken();
927       Object value = convertInternal(parser);
928       map.put(name, value);
929
930       token = parser.nextToken();
931       if (token == null)
932         fail(parser, "unexpected EOF");
933     }
934
935     return map;
936   }
937
938   static List<Object> convertArrayInternal(JsonParser parser) throws IOException
939   {
940     JsonToken token = parser.nextToken();
941     if (token == null)
942       fail(parser, "unexpected EOF");
943
944     List<Object> list = new LinkedList<>();
945
946     while (!JsonToken.END_ARRAY.equals(token))
947     {
948       list.add(convertInternal(parser));
949
950       token = parser.nextToken();
951       if (token == null)
952         fail(parser, "unexpected EOF");
953     }
954
955     return list;
956   }
957
958
959   static void fail(JsonParser parser, String message)
960   {
961     JsonLocation location = parser.getCurrentLocation();
962     LOG.error(
963         "{} at char-offset {} (line {}, column {})",
964         message,
965         location.getCharOffset(),
966         location.getLineNr(),
967         location.getColumnNr()
968         );
969     throw new IllegalArgumentException("Cannot parse JSON: " + message);
970   }
971 }