001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.collections;
014
015import static org.apache.juneau.internal.StringUtils.*;
016
017import java.io.*;
018import java.lang.reflect.*;
019import java.util.*;
020import java.util.function.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.json.*;
024import org.apache.juneau.marshall.*;
025import org.apache.juneau.parser.*;
026import org.apache.juneau.serializer.*;
027import org.apache.juneau.utils.*;
028
029/**
030 * Java implementation of a JSON array.
031 *
032 * <p>
033 * An extension of {@link LinkedList}, so all methods available to in that class are also available to this class.
034 *
035 * <p>
036 * Note that the use of this class is optional for generating JSON.  The serializers will accept any objects that implement the
037 * {@link Collection} interface.  But this class provides some useful additional functionality when working with JSON
038 * models constructed from Java Collections Framework objects.  For example, a constructor is provided for converting a
039 * JSON array string directly into a {@link List}.  It also contains accessor methods for to avoid common typecasting
040 * when accessing elements in a list.
041 *
042 * <h5 class='section'>Example:</h5>
043 * <p class='bcode w800'>
044 *    <jc>// Construct an empty List</jc>
045 *    OList l = OList.<jsm>of</jsm>();
046 *
047 *    <jc>// Construct a list of objects using various methods</jc>
048 *    l = OList.<jsm>of</jsm>().a(<js>"foo"</js>).a(123).a(<jk>true</jk>);
049 *    l = OList.<jsm>of</jsm>().a(<js>"foo"</js>, 123, <jk>true</jk>);  <jc>// Equivalent</jc>
050 *    l = OList.<jsm>of</jsm>(<js>"foo"</js>, 123, <jk>true</jk>);  <jc>// Equivalent</jc>
051 *
052 *    <jc>// Construct a list of integers from JSON</jc>
053 *    l = OList.<jsm>ofJson</jsm>(<js>"[1,2,3]"</js>);
054 *
055 *    <jc>// Construct a list of generic OMap objects from JSON</jc>
056 *    l = OList.<jsm>ofJson</jsm>(<js>"[{foo:'bar'},{baz:'bing'}]"</js>);
057 *
058 *    <jc>// Construct a list of integers from XML</jc>
059 *    String xml = <js>"&lt;array&gt;&lt;number&gt;1&lt;/number&gt;&lt;number&gt;2&lt;/number&gt;&lt;number&gt;3&lt;/number&gt;&lt;/array&gt;"</js>;
060 *    l = OList.<jsm>of</jsm>(xml, XmlParser.<jsf>DEFAULT</jsf>);
061 *    l = (List)XmlParser.<jsf>DEFAULT</jsf>.parse(xml);  <jc>// Equivalent</jc>
062 *    l = (List)XmlParser.<jsf>DEFAULT</jsf>.parse(Object.<jk>class</jk>, xml);  <jc>// Equivalent</jc>
063 *    l = XmlParser.<jsf>DEFAULT</jsf>.parse(List.<jk>class</jk>, xml);  <jc>// Equivalent</jc>
064 *    l = XmlParser.<jsf>DEFAULT</jsf>.parse(OList.<jk>class</jk>, xml);  <jc>// Equivalent</jc>
065 *
066 *    <jc>// Construct JSON from OList</jc>
067 *    l = OList.<jsm>ofJson</jsm>(<js>"[{foo:'bar'},{baz:'bing'}]"</js>);
068 *    String json = l.toString();  <jc>// Produces "[{foo:'bar'},{baz:'bing'}]"</jc>
069 *    json = l.toString(JsonSerializer.<jsf>DEFAULT</jsf>);  <jc>// Equivalent</jc>
070 *    json = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(l);  <jc>// Equivalent</jc>
071 *
072 *    <jc>// Get one of the entries in the list as an Integer</jc>
073 *    l = OList.<jsm>ofJson</jsm>(<js>"[1,2,3]"</js>);
074 *    Integer i = l.getInt(1);
075 *    i = l.get(Integer.<jk>class</jk>, 1);  <jc>// Equivalent</jc>
076 *
077 *    <jc>// Get one of the entries in the list as an Float</jc>
078 *    l = OList.<jsm>ofJson</jsm>(<js>"[1,2,3]"</js>);
079 *    Float f = l.getFloat(1); <jc>// Returns 2f </jc>
080 *    f = l.get(Float.<jk>class</jk>, 1);  <jc>// Equivalent</jc>
081 *
082 *    <jc>// Same as above, except converted to a String</jc>
083 *    l = OList.<jsm>ofJson</jsm>(<js>"[1,2,3]"</js>);
084 *    String s = l.getString(1); <jc>// Returns "2" </jc>
085 *    s = l.get(String.<jk>class</jk>, 1);  <jc>// Equivalent</jc>
086 *
087 *    <jc>// Get one of the entries in the list as a bean (converted to a bean if it isn't already one)</jc>
088 *    l = OList.<jsm>ofJson</jsm>(<js>"[{name:'John Smith',age:45}]"</js>);
089 *    Person p = l.get(Person.<jk>class</jk>, 0);
090 *
091 *    <jc>// Iterate over a list of beans using the elements() method</jc>
092 *    OList l = OList.<jsm>ofJson</jsm>(<js>"[{name:'John Smith',age:45}]"</js>);
093 *    <jk>for</jk> (Person p : l.elements(Person.<jk>class</jk>) {
094 *       <jc>// Do something with p</jc>
095 *    }
096 * </p>
097 *
098 * <p>
099 * This class is not thread safe.
100 */
101public class OList extends ObjectList /* In 9.0 - LinkedList<Object> */ {
102   private static final long serialVersionUID = 1L;
103
104   transient BeanSession session = null;
105   private transient PojoRest pojoRest;
106
107   /**
108    * An empty read-only OList.
109    */
110   public static final OList EMPTY_LIST = new OList() {
111      private static final long serialVersionUID = 1L;
112
113      @Override /* List */
114      public void add(int location, Object object) {
115         throw new UnsupportedOperationException();
116      }
117
118      @Override /* List */
119      public ListIterator<Object> listIterator(final int location) {
120         return Collections.emptyList().listIterator(location);
121      }
122
123      @Override /* List */
124      public Object remove(int location) {
125         throw new UnsupportedOperationException();
126      }
127
128      @Override /* List */
129      public Object set(int location, Object object) {
130         throw new UnsupportedOperationException();
131      }
132
133      @Override /* List */
134      public List<Object> subList(int start, int end) {
135         return Collections.emptyList().subList(start, end);
136      }
137   };
138
139   //------------------------------------------------------------------------------------------------------------------
140   // Constructors.
141   //------------------------------------------------------------------------------------------------------------------
142
143   /**
144    * Construct an empty list.
145    */
146   public OList() {}
147
148   /**
149    * Construct an empty list with the specified bean context.
150    *
151    * @param session The bean session to use for creating beans.
152    */
153   public OList(BeanSession session) {
154      super();
155      this.session = session;
156   }
157
158   /**
159    * Construct a list initialized with the specified list.
160    *
161    * @param copyFrom
162    *    The list to copy.
163    *    <br>Can be <jk>null</jk>.
164    */
165   public OList(Collection<?> copyFrom) {
166      super(copyFrom);
167   }
168
169   /**
170    * Construct a list initialized with the specified JSON.
171    *
172    * @param json
173    *    The JSON text to parse.
174    *    <br>Can be normal or simplified JSON.
175    * @throws ParseException Malformed input encountered.
176    */
177   public OList(CharSequence json) throws ParseException {
178      this(json, JsonParser.DEFAULT);
179   }
180
181   /**
182    * Construct a list initialized with the specified string.
183    *
184    * @param in
185    *    The input being parsed.
186    *    <br>Can be <jk>null</jk>.
187    * @param p
188    *    The parser to use to parse the input.
189    *    <br>If <jk>null</jk>, uses {@link JsonParser}.
190    * @throws ParseException Malformed input encountered.
191    */
192   public OList(CharSequence in, Parser p) throws ParseException {
193      this(p == null ? null : p.createBeanSession());
194      if (p == null)
195         p = JsonParser.DEFAULT;
196      if (in != null)
197         p.parseIntoCollection(in, this, bs().object());
198   }
199
200   /**
201    * Construct a list initialized with the specified reader containing JSON.
202    *
203    * @param json
204    *    The reader containing JSON text to parse.
205    *    <br>Can contain normal or simplified JSON.
206    * @throws ParseException Malformed input encountered.
207    */
208   public OList(Reader json) throws ParseException {
209      parse(json, JsonParser.DEFAULT);
210   }
211
212   /**
213    * Construct a list initialized with the specified string.
214    *
215    * @param in
216    *    The reader containing the input being parsed.
217    *    <br>Can contain normal or simplified JSON.
218    * @param p
219    *    The parser to use to parse the input.
220    *    <br>If <jk>null</jk>, uses {@link JsonParser}.
221    * @throws ParseException Malformed input encountered.
222    */
223   public OList(Reader in, Parser p) throws ParseException {
224      this(p == null ? null : p.createBeanSession());
225      parse(in, p);
226   }
227
228   /**
229    * Construct a list initialized with the contents.
230    *
231    * @param entries The entries to add to this list.
232    */
233   public OList(Object... entries) {
234      super();
235      Collections.addAll(this, entries);
236   }
237
238   //------------------------------------------------------------------------------------------------------------------
239   // Creators.
240   //------------------------------------------------------------------------------------------------------------------
241
242   /**
243    * Construct an empty list.
244    *
245    * @return An empty list.
246    */
247   public static OList of() {
248      return new OList();
249   }
250
251   /**
252    * Construct a list initialized with the specified list.
253    *
254    * @param in
255    *    The list to copy.
256    *    <br>Can be <jk>null</jk>.
257    * @return A new list or <jk>null</jk> if the list was <jk>null</jk>.
258    */
259   public static OList ofAll(Collection<?> in) {
260      return in == null ? null : new OList(in);
261   }
262
263   /**
264    * Construct a list initialized with the specified JSON string.
265    *
266    * @param json
267    *    The JSON text to parse.
268    *    <br>Can be normal or simplified JSON.
269    * @return A new list or <jk>null</jk> if the string was null.
270    * @throws ParseException Malformed input encountered.
271    */
272   public static OList ofJson(CharSequence json) throws ParseException {
273      return json == null ? null : new OList(json);
274   }
275
276   /**
277    * Construct a list initialized with the specified string.
278    *
279    * @param in
280    *    The input being parsed.
281    *    <br>Can be <jk>null</jk>.
282    * @param p
283    *    The parser to use to parse the input.
284    *    <br>If <jk>null</jk>, uses {@link JsonParser}.
285    * @return A new list or <jk>null</jk> if the input was <jk>null</jk>.
286    * @throws ParseException Malformed input encountered.
287    */
288   public static OList ofText(CharSequence in, Parser p) throws ParseException {
289      return in == null ? null : new OList(in, p);
290   }
291
292   /**
293    * Construct a list initialized with the specified reader containing JSON.
294    *
295    * @param json
296    *    The reader containing JSON text to parse.
297    *    <br>Can contain normal or simplified JSON.
298    * @return A new list or <jk>null</jk> if the input was <jk>null</jk>.
299    * @throws ParseException Malformed input encountered.
300    */
301   public static OList ofJson(Reader json) throws ParseException {
302      return json == null ? null : new OList(json);
303   }
304
305   /**
306    * Construct a list initialized with the specified string.
307    *
308    * @param in
309    *    The reader containing the input being parsed.
310    *    <br>Can contain normal or simplified JSON.
311    * @param p
312    *    The parser to use to parse the input.
313    *    <br>If <jk>null</jk>, uses {@link JsonParser}.
314    * @return A new list or <jk>null</jk> if the input was <jk>null</jk>.
315    * @throws ParseException Malformed input encountered.
316    */
317   public static OList ofText(Reader in, Parser p) throws ParseException {
318      return in == null ? null : new OList(in);
319   }
320
321   /**
322    * Construct a list initialized with the specified key/value pairs.
323    *
324    * @param entries The entries to add to this list.
325    * @return A new map, never <jk>null</jk>.
326    */
327   public static OList of(Object... entries) {
328      return new OList(entries);
329   }
330
331   //------------------------------------------------------------------------------------------------------------------
332   // Initializers.
333   //------------------------------------------------------------------------------------------------------------------
334
335   /**
336    * Override the default bean session used for converting POJOs.
337    *
338    * <p>
339    * Default is {@link BeanContext#DEFAULT}, which is sufficient in most cases.
340    *
341    * <p>
342    * Useful if you're serializing/parsing beans with transforms defined.
343    *
344    * @param session The new bean session.
345    * @return This object (for method chaining).
346    */
347   public OList session(BeanSession session) {
348      this.session = session;
349      return this;
350   }
351
352   //------------------------------------------------------------------------------------------------------------------
353   // Appenders.
354   //------------------------------------------------------------------------------------------------------------------
355
356   /**
357    * Add.
358    *
359    * <p>
360    * Adds an entry to this list.
361    *
362    * @param o The entry to add to this list.
363    * @return This object (for method chaining).
364    */
365   public OList a(Object o) {
366      add(o);
367      return this;
368   }
369
370   /**
371    * Add.
372    *
373    * <p>
374    * Same as {@link #a(Object)}
375    *
376    * @param o The entry to add to this list.
377    * @return This object (for method chaining).
378    */
379   public OList append(Object o) {
380      add(o);
381      return this;
382   }
383
384   /**
385    * Add.
386    *
387    * <p>
388    * Adds multiple entries to this list.
389    *
390    * @param o The entries to add to this list.
391    * @return This object (for method chaining).
392    */
393   public OList a(Object...o) {
394      for (Object o2 : o)
395         add(o2);
396      return this;
397   }
398
399   /**
400    * Add.
401    *
402    * <p>
403    * Same as {@link #a(Object...)}
404    *
405    * @param o The entries to add to this list.
406    * @return This object (for method chaining).
407    */
408   @Override
409   public OList append(Object...o) {
410      for (Object o2 : o)
411         add(o2);
412      return this;
413   }
414
415   /**
416    * Add all.
417    *
418    * <p>
419    * Adds all the entries in the specified collection to this list.
420    *
421    * @param c The collection to add to this list.  Can be <jk>null</jk>.
422    * @return This object (for method chaining).
423    */
424   public OList aa(Collection<?> c) {
425      if (c != null)
426         addAll(c);
427      return this;
428   }
429
430   /**
431    * Add all.
432    *
433    * <p>
434    * Same as {@link #aa(Collection)}.
435    *
436    * @param c The collection to add to this list.  Can be <jk>null</jk>.
437    * @return This object (for method chaining).
438    */
439   public OList appendAll(Collection<?> c) {
440      if (c != null)
441         addAll(c);
442      return this;
443   }
444
445   /**
446    * Add if.
447    *
448    * <p>
449    * Adds an entry to this list if the boolean flag is <jk>true</jk>.
450    *
451    * @param b The boolean flag.
452    * @param val The value to add.
453    * @return This object (for method chaining).
454    */
455   public OList aif(boolean b, Object val) {
456      if (b)
457         a(val);
458      return this;
459   }
460
461   /**
462    * Add if.
463    *
464    * <p>
465    * Same as {@link #aif(boolean, Object)}.
466    *
467    * @param b The boolean flag.
468    * @param val The value to add.
469    * @return This object (for method chaining).
470    */
471   public OList appendIf(boolean b, Object val) {
472      return aif(b, val);
473   }
474
475   /**
476    * Add if not empty.
477    *
478    * <p>
479    * Adds entries to this list skipping any empty or <jk>null</jk> values.
480    *
481    * @param o The objects to add to the list.
482    * @return This object (for method chaining).
483    */
484   public OList aifne(String...o) {
485      for (String s : o)
486         if (isNotEmpty(s))
487            add(s);
488      return this;
489   }
490
491   /**
492    * Add if not empty.
493    *
494    * <p>
495    * Same as {@link #aifne(String...)}.
496    *
497    * @param o The objects to add to the list.
498    * @return This object (for method chaining).
499    */
500   @Override
501   public OList appendIfNotEmpty(String...o) {
502      return aifne(o);
503   }
504
505   /**
506    * Add if not null.
507    *
508    * <p>
509    * Adds entries to this list skipping <jk>null</jk> values.
510    *
511    * @param o The objects to add to the list.
512    * @return This object (for method chaining).
513    */
514   public OList aifnn(Object...o) {
515      for (Object o2 : o)
516         if (o2 != null)
517            add(o2);
518      return this;
519   }
520   /**
521    * Add if not null.
522    *
523    * <p>
524    * Same as {@link #aifnn(Object...)}.
525    *
526    * @param o The objects to add to the list.
527    * @return This object (for method chaining).
528    */
529   @Override
530   public OList appendIfNotNull(Object...o) {
531      return aifnn(o);
532   }
533
534   /**
535    * Add if predicate matches.
536    *
537    * @param p The predicate to match against.
538    * @param val The value to add if the predicate matches.
539    * @return This object (for method chaining).
540    */
541   public OList aif(Predicate<Object> p, Object val) {
542      if (p.test(val))
543         a(val);
544      return this;
545   }
546
547   /**
548    * Add if predicate matches.
549    *
550    * <p>
551    * Same as {@link #aif(Predicate, Object)}.
552    *
553    * @param p The predicate to match against.
554    * @param val The value to add if the predicate matches.
555    * @return This object (for method chaining).
556    */
557   public OList appendIf(Predicate<Object> p, Object val) {
558      return aif(p, val);
559   }
560
561   //------------------------------------------------------------------------------------------------------------------
562   // Retrievers.
563   //------------------------------------------------------------------------------------------------------------------
564
565   /**
566    * Get the entry at the specified index, converted to the specified type.
567    *
568    * <p>
569    * This is the preferred get method for simple types.
570    *
571    * <h5 class='section'>Examples:</h5>
572    * <p class='bcode w800'>
573    *    OList l = OList.<jsm>ofJson</jsm>(<js>"..."</js>);
574    *
575    *    <jc>// Value converted to a string.</jc>
576    *    String s = l.get(1, String.<jk>class</jk>);
577    *
578    *    <jc>// Value converted to a bean.</jc>
579    *    MyBean b = l.get(2, MyBean.<jk>class</jk>);
580    *
581    *    <jc>// Value converted to a bean array.</jc>
582    *    MyBean[] ba = l.get(3, MyBean[].<jk>class</jk>);
583    *
584    *    <jc>// Value converted to a linked-list of objects.</jc>
585    *    List l1 = l.get(4, LinkedList.<jk>class</jk>);
586    *
587    *    <jc>// Value converted to a map of object keys/values.</jc>
588    *    Map m1 = l.get(5, TreeMap.<jk>class</jk>);
589    * </p>
590    *
591    * <p>
592    * See {@link BeanSession#convertToType(Object, ClassMeta)} for the list of valid data conversions.
593    *
594    * @param index The index into this list.
595    * @param type The type of object to convert the entry to.
596    * @param <T> The type of object to convert the entry to.
597    * @return The converted entry.
598    */
599   @Override
600   public <T> T get(int index, Class<T> type) {
601      return bs().convertToType(get(index), type);
602   }
603
604   /**
605    * Get the entry at the specified index, converted to the specified type.
606    *
607    * <p>
608    * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
609    *
610    * <h5 class='section'>Examples:</h5>
611    * <p class='bcode w800'>
612    *    OList l = OList.<jsm>ofJson</jsm>(<js>"..."</js>);
613    *
614    *    <jc>// Value converted to a linked-list of strings.</jc>
615    *    List&lt;String&gt; l1 = l.get(1, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
616    *
617    *    <jc>// Value converted to a linked-list of beans.</jc>
618    *    List&lt;MyBean&gt; l2 = l.get(2, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
619    *
620    *    <jc>// Value converted to a linked-list of linked-lists of strings.</jc>
621    *    List&lt;List&lt;String&gt;&gt; l3 = l.get(3, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
622    *
623    *    <jc>// Value converted to a map of string keys/values.</jc>
624    *    Map&lt;String,String&gt; m1 = l.get(4, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
625    *
626    *    <jc>// Value converted to a map containing string keys and values of lists containing beans.</jc>
627    *    Map&lt;String,List&lt;MyBean&gt;&gt; m2 = l.get(5, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
628    * </p>
629    *
630    * <p>
631    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
632    *
633    * <p>
634    * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
635    *
636    * <p>
637    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
638    *
639    * <p>
640    * See {@link BeanSession#convertToType(Object, ClassMeta)} for the list of valid data conversions.
641    *
642    * @param index The index into this list.
643    * @param type The type of object to convert the entry to.
644    * @param args The type arguments of the type to convert the entry to.
645    * @param <T> The type of object to convert the entry to.
646    * @return The converted entry.
647    */
648   @Override
649   public <T> T get(int index, Type type, Type...args) {
650      return bs().convertToType(get(index), type, args);
651   }
652
653   /**
654    * Shortcut for calling <code>get(index, String.<jk>class</jk>)</code>.
655    *
656    * @param index The index.
657    * @return The converted value.
658    */
659   @Override
660   public String getString(int index) {
661      return get(index, String.class);
662   }
663
664   /**
665    * Shortcut for calling <code>get(index, Integer.<jk>class</jk>)</code>.
666    *
667    * @param index The index.
668    * @return The converted value.
669    * @throws InvalidDataConversionException If value cannot be converted.
670    */
671   @Override
672   public Integer getInt(int index) {
673      return get(index, Integer.class);
674   }
675
676   /**
677    * Shortcut for calling <code>get(index, Boolean.<jk>class</jk>)</code>.
678    *
679    * @param index The index.
680    * @return The converted value.
681    * @throws InvalidDataConversionException If value cannot be converted.
682    */
683   @Override
684   public Boolean getBoolean(int index) {
685      return get(index, Boolean.class);
686   }
687
688   /**
689    * Shortcut for calling <code>get(index, Long.<jk>class</jk>)</code>.
690    *
691    * @param index The index.
692    * @return The converted value.
693    * @throws InvalidDataConversionException If value cannot be converted.
694    */
695   @Override
696   public Long getLong(int index) {
697      return get(index, Long.class);
698   }
699
700   /**
701    * Shortcut for calling <code>get(index, OMap.<jk>class</jk>)</code>.
702    *
703    * @param index The index.
704    * @return The converted value.
705    * @throws InvalidDataConversionException If value cannot be converted.
706    */
707   @Override
708   public OMap getMap(int index) {
709      return get(index, OMap.class);
710   }
711
712   /**
713    * Shortcut for calling <code>get(index, OList.<jk>class</jk>)</code>.
714    *
715    * @param index The index.
716    * @return The converted value.
717    * @throws InvalidDataConversionException If value cannot be converted.
718    */
719   @Override
720   public OList getList(int index) {
721      return get(index, OList.class);
722   }
723
724   //------------------------------------------------------------------------------------------------------------------
725   // POJO REST methods.
726   //------------------------------------------------------------------------------------------------------------------
727
728   /**
729    * Same as {@link #get(int,Class) get(int,Class)}, but the key is a slash-delimited path used to traverse entries in
730    * this POJO.
731    *
732    * <p>
733    * For example, the following code is equivalent:
734    * </p>
735    * <p class='bcode w800'>
736    *    OList ol = OList.<jsm>ofJson</jsm>(<js>"..."</js>);
737    *
738    *    <jc>// Long way</jc>
739    *    <jk>long</jk> l = ol.getMap(<js>"0"</js>).getLong(<js>"baz"</js>);
740    *
741    *    <jc>// Using this method</jc>
742    *    <jk>long</jk> l = ol.getAt(<js>"0/baz"</js>, <jk>long</jk>.<jk>class</jk>);
743    * </p>
744    *
745    * <p>
746    * This method uses the {@link PojoRest} class to perform the lookup, so the map can contain any of the various
747    * class types that the {@link PojoRest} class supports (e.g. beans, collections, arrays).
748    *
749    * @param path The path to the entry.
750    * @param type The class type.
751    *
752    * @param <T> The class type.
753    * @return The value, or <jk>null</jk> if the entry doesn't exist.
754    */
755   @Override
756   public <T> T getAt(String path, Class<T> type) {
757      return getPojoRest().get(path, type);
758   }
759
760   /**
761    * Same as {@link #getAt(String,Class)}, but allows for conversion to complex maps and collections.
762    *
763    * @param path The path to the entry.
764    * @param type The class type.
765    * @param args The class parameter types.
766    *
767    * @param <T> The class type.
768    * @return The value, or <jk>null</jk> if the entry doesn't exist.
769    */
770   @Override
771   public <T> T getAt(String path, Type type, Type...args) {
772      return getPojoRest().get(path, type, args);
773   }
774
775   /**
776    * Same as {@link #set(int,Object) set(int,Object)}, but the key is a slash-delimited path used to traverse entries
777    * in this POJO.
778    *
779    * <p>
780    * For example, the following code is equivalent:
781    * </p>
782    * <p class='bcode w800'>
783    *    OList ol = OList.<jsm>ofJson</jsm>(<js>"..."</js>);
784    *
785    *    <jc>// Long way</jc>
786    *    ol.getMap(<js>"0"</js>).put(<js>"baz"</js>, 123);
787    *
788    *    <jc>// Using this method</jc>
789    *    ol.putAt(<js>"0/baz"</js>, 123);
790    * </p>
791    *
792    * <p>
793    * This method uses the {@link PojoRest} class to perform the lookup, so the map can contain any of the various
794    * class types that the {@link PojoRest} class supports (e.g. beans, collections, arrays).
795    *
796    * @param path The path to the entry.
797    * @param o The new value.
798    * @return The previous value, or <jk>null</jk> if the entry doesn't exist.
799    */
800   @Override
801   public Object putAt(String path, Object o) {
802      return getPojoRest().put(path, o);
803   }
804
805   /**
806    * Similar to {@link #putAt(String,Object) putAt(String,Object)}, but used to append to collections and arrays.
807    *
808    * <p>
809    * For example, the following code is equivalent:
810    * </p>
811    * <p class='bcode w800'>
812    *    OList ol = OList.<jsm>ofJson</jsm>(<js>"..."</js>);
813    *
814    *    <jc>// Long way</jc>
815    *    ol.getMap(0).getList(<js>"bar"</js>).append(123);
816    *
817    *    <jc>// Using this method</jc>
818    *    ol.postAt(<js>"0/bar"</js>, 123);
819    * </p>
820    *
821    * <p>
822    * This method uses the {@link PojoRest} class to perform the lookup, so the map can contain any of the various
823    * class types that the {@link PojoRest} class supports (e.g. beans, collections, arrays).
824    *
825    * @param path The path to the entry.
826    * @param o The new value.
827    * @return The previous value, or <jk>null</jk> if the entry doesn't exist.
828    */
829   @Override
830   public Object postAt(String path, Object o) {
831      return getPojoRest().post(path, o);
832   }
833
834   /**
835    * Similar to {@link #remove(int) remove(int)},but the key is a slash-delimited path used to traverse entries in
836    * this POJO.
837    *
838    * <p>
839    * For example, the following code is equivalent:
840    * </p>
841    * <p class='bcode w800'>
842    *    OList ol = OList.<jsm>ofJson</jsm>(<js>"..."</js>);
843    *
844    *    <jc>// Long way</jc>
845    *    ol.getMap(0).getList(<js>"bar"</js>).delete(0);
846    *
847    *    <jc>// Using this method</jc>
848    *    m.deleteAt(<js>"0/bar/0"</js>);
849    * </p>
850    *
851    * <p>
852    * This method uses the {@link PojoRest} class to perform the lookup, so the map can contain any of the various
853    * class types that the {@link PojoRest} class supports (e.g. beans, collections, arrays).
854    *
855    * @param path The path to the entry.
856    * @return The previous value, or <jk>null</jk> if the entry doesn't exist.
857    */
858   @Override
859   public Object deleteAt(String path) {
860      return getPojoRest().delete(path);
861   }
862
863   //------------------------------------------------------------------------------------------------------------------
864   // Other methods.
865   //------------------------------------------------------------------------------------------------------------------
866
867   /**
868    * Returns the {@link BeanSession} currently associated with this list.
869    *
870    * @return The {@link BeanSession} currently associated with this list.
871    */
872   @Override
873   public BeanSession getBeanSession() {
874      return session;
875   }
876
877   /**
878    * Creates an {@link Iterable} with elements of the specified child type.
879    *
880    * <p>
881    * Attempts to convert the child objects to the correct type if they aren't already the correct type.
882    *
883    * <p>
884    * The <c>next()</c> method on the returned iterator may throw a {@link InvalidDataConversionException} if
885    * the next element cannot be converted to the specified type.
886    *
887    * <p>
888    * See {@link BeanSession#convertToType(Object, ClassMeta)} for a description of valid conversions.
889    *
890    * <h5 class='section'>Example:</h5>
891    * <p class='bcode w800'>
892    *    <jc>// Iterate over a list of OMaps.</jc>
893    *    OList l = OList.<jsm>ofJson</jsm>(<js>"[{foo:'bar'},{baz:123}]"</js>);
894    *    for (OMap m : l.elements(OMap.<jk>class</jk>)) {
895    *       <jc>// Do something with m.</jc>
896    *    }
897    *
898    *    <jc>// Iterate over a list of ints.</jc>
899    *    OList l = OList.<jsm>ofJson</jsm>(<js>"[1,2,3]"</js>);
900    *    for (Integer i : l.elements(Integer.<jk>class</jk>)) {
901    *       <jc>// Do something with i.</jc>
902    *    }
903    *
904    *    <jc>// Iterate over a list of beans.</jc>
905    *    <jc>// Automatically converts to beans.</jc>
906    *    OList l = OList.<jsm>ofJson</jsm>(<js>"[{name:'John Smith',age:45}]"</js>);
907    *    for (Person p : l.elements(Person.<jk>class</jk>)) {
908    *       <jc>// Do something with p.</jc>
909    *    }
910    * </p>
911    *
912    * @param <E> The child object type.
913    * @param childType The child object type.
914    * @return A new <c>Iterable</c> object over this list.
915    */
916   @Override
917   public <E> Iterable<E> elements(final Class<E> childType) {
918      final Iterator<?> i = iterator();
919      return new Iterable<E>() {
920
921         @Override /* Iterable */
922         public Iterator<E> iterator() {
923            return new Iterator<E>() {
924
925               @Override /* Iterator */
926               public boolean hasNext() {
927                  return i.hasNext();
928               }
929
930               @Override /* Iterator */
931               public E next() {
932                  return bs().convertToType(i.next(), childType);
933               }
934
935               @Override /* Iterator */
936               public void remove() {
937                  i.remove();
938               }
939
940            };
941         }
942      };
943   }
944
945   /**
946    * Returns the {@link ClassMeta} of the class of the object at the specified index.
947    *
948    * @param index An index into this list, zero-based.
949    * @return The data type of the object at the specified index, or <jk>null</jk> if the value is null.
950    */
951   @Override
952   public ClassMeta<?> getClassMeta(int index) {
953      return bs().getClassMetaForObject(get(index));
954   }
955
956   /**
957    * Serialize this array to a string using the specified serializer.
958    *
959    * @param serializer The serializer to use to convert this object to a string.
960    * @return This object as a serialized string.
961    */
962   public String asString(WriterSerializer serializer) {
963      return serializer.toString(this);
964   }
965
966   /**
967    * Serialize this array to Simplified JSON.
968    *
969    * @return This object as a serialized string.
970    */
971   public String asString() {
972      return SimpleJsonSerializer.DEFAULT.toString(this);
973   }
974
975   /**
976    * Returns <jk>true</jk> if this list is unmodifiable.
977    *
978    * @return <jk>true</jk> if this list is unmodifiable.
979    */
980   @Override
981   public boolean isUnmodifiable() {
982      return false;
983   }
984
985   /**
986    * Returns a modifiable copy of this list if it's unmodifiable.
987    *
988    * @return A modifiable copy of this list if it's unmodifiable, or this list if it is already modifiable.
989    */
990   @Override
991   public OList modifiable() {
992      if (isUnmodifiable())
993         return new OList(this);
994      return this;
995   }
996
997   /**
998    * Returns an unmodifiable copy of this list if it's modifiable.
999    *
1000    * @return An unmodifiable copy of this list if it's modifiable, or this list if it is already unmodifiable.
1001    */
1002   @Override
1003   public OList unmodifiable() {
1004      if (this instanceof UnmodifiableOList)
1005         return this;
1006      return new UnmodifiableOList(this);
1007   }
1008
1009   /**
1010    * Convenience method for serializing this OList to the specified Writer using the JsonSerializer.DEFAULT
1011    * serializer.
1012    *
1013    * @param w The writer to send the serialized contents of this object.
1014    * @return This object (for method chaining).
1015    * @throws IOException If a problem occurred trying to write to the writer.
1016    * @throws SerializeException If a problem occurred trying to convert the output.
1017    */
1018   public OList writeTo(Writer w) throws IOException, SerializeException {
1019      JsonSerializer.DEFAULT.serialize(this, w);
1020      return this;
1021   }
1022
1023   /**
1024    * Converts this object into the specified class type.
1025    *
1026    * <p>
1027    * TODO - The current implementation is very inefficient.
1028    *
1029    * @param cm The class type to convert this object to.
1030    * @return A converted object.
1031    */
1032   @Override
1033   public Object cast(ClassMeta<?> cm) {
1034      try {
1035         return JsonParser.DEFAULT.parse(SimpleJsonSerializer.DEFAULT.serialize(this), cm);
1036      } catch (ParseException | SerializeException e) {
1037         throw new RuntimeException(e);
1038      }
1039   }
1040
1041   //------------------------------------------------------------------------------------------------------------------
1042   // Utility methods.
1043   //------------------------------------------------------------------------------------------------------------------
1044
1045   private void parse(Reader r, Parser p) throws ParseException {
1046      if (p == null)
1047         p = JsonParser.DEFAULT;
1048      p.parseIntoCollection(r, this, bs().object());
1049   }
1050
1051   private PojoRest getPojoRest() {
1052      if (pojoRest == null)
1053         pojoRest = new PojoRest(this);
1054      return pojoRest;
1055   }
1056
1057   BeanSession bs() {
1058      if (session == null)
1059         session = BeanContext.DEFAULT.createBeanSession();
1060      return session;
1061   }
1062
1063   private static final class UnmodifiableOList extends OList {
1064      private static final long serialVersionUID = 1L;
1065
1066      UnmodifiableOList(OList contents) {
1067         super();
1068         if (contents != null) {
1069            for (Object e : this) {
1070               super.add(e);
1071            }
1072         }
1073      }
1074
1075      @Override /* List */
1076      public void add(int location, Object object) {
1077         throw new UnsupportedOperationException("OList is read-only.");
1078      }
1079
1080      @Override /* List */
1081      public Object remove(int location) {
1082         throw new UnsupportedOperationException("OList is read-only.");
1083      }
1084
1085      @Override /* List */
1086      public Object set(int location, Object object) {
1087         throw new UnsupportedOperationException("OList is read-only.");
1088      }
1089
1090      @Override
1091      public final boolean isUnmodifiable() {
1092         return true;
1093      }
1094   }
1095
1096   //------------------------------------------------------------------------------------------------------------------
1097   // Overridden methods.
1098   //------------------------------------------------------------------------------------------------------------------
1099
1100   @Override /* Object */
1101   public String toString() {
1102      return SimpleJson.DEFAULT.toString(this);
1103   }
1104}