001/*
002 * This file is part of the JDrupes JSON utilities project.
003 * Copyright (C) 2017, 2018  Michael N. Lipp
004 *
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Lesser General Public License as published
007 * by the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
013 * License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.json;
020
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.List;
024import java.util.stream.Stream;
025
026/**
027 * A view on a `List<Object>` that provides some utility methods
028 * for accessing the data.
029 */
030public interface JsonArray  {
031        
032        JsonArray EMPTY_ARRAY = from(Collections.emptyList());
033
034        /**
035         * Creates a new instance of the {@link DefaultJsonArray}.
036         * 
037         * @return the json array
038         */
039        public static JsonArray create() {
040                return new DefaultJsonArray();
041        }
042
043        /**
044         * Creates a wrapper around an existing `List<Object>`.
045         *
046         * @param backing the backing list
047         * @return the json array
048         */
049        public static JsonArray from(List<Object> backing) {
050                return new JsonArrayWrapper(backing);
051        }
052
053        /**
054         * Overloaded to ensure that an existing {@link DefaultJsonArray}
055         * is not wrapped again.
056         * 
057         * @param backing the backing list
058         * @return the argument
059         */
060        public static JsonArray from(DefaultJsonArray backing) {
061                return backing;
062        }
063
064        List<Object> backing();
065        
066        int size();
067        
068        /**
069         * Streams the elements in the array.
070         *
071         * @return the stream
072         */
073        Stream<Object> stream();
074        
075        /**
076         * Streams the elements in the array after casting them to 
077         * {@link JsonArray}s. Useful for processing arrays of arrays.
078         *
079         * @return the stream
080         */
081        Stream<JsonArray> arrayStream();
082
083        JsonArray append(Object value);
084
085        Object get(int index);
086        
087        String asString(int index);
088
089        int asInt(int index);
090
091        long asLong(int index);
092
093        boolean asBoolean(int index);
094
095        float asFloat(int index);
096
097        double asDouble(int index);
098
099        JsonArray asArray(int index);
100        
101        /**
102         * Instances of this class are used as default representations for JSON
103         * arrays.
104         */
105        public static class DefaultJsonArray extends ArrayList<Object> implements JsonArray {
106
107                private static final long serialVersionUID = 2997178412748739135L;
108                
109                public DefaultJsonArray() {
110                }
111
112                @Override
113                public List<Object> backing() {
114                        return this;
115                }
116                
117                /* (non-Javadoc)
118                 * @see org.jdrupes.json.JsonArray#stream()
119                 */
120                @Override
121                public Stream<Object> stream() {
122                        return super.stream();
123                }
124
125                /* (non-Javadoc)
126                 * @see org.jdrupes.json.JsonArrayItf#arrayStream()
127                 */
128                @Override
129                @SuppressWarnings("unchecked")
130                public Stream<JsonArray> arrayStream() {
131                        return stream().map(
132                                        obj -> JsonArray.from((List<Object>)obj));
133                }
134                
135                /* (non-Javadoc)
136                 * @see org.jdrupes.json.JsonArrayItf#append(java.lang.Object)
137                 */
138                @Override
139                public JsonArray append(Object value) {
140                        add(value);
141                        return this;
142                }
143                
144                /* (non-Javadoc)
145                 * @see org.jdrupes.json.JsonArrayItf#asString(int)
146                 */
147                @Override
148                public String asString(int index) {
149                        return (String)get(index);
150                }
151                
152                /* (non-Javadoc)
153                 * @see org.jdrupes.json.JsonArrayItf#asInt(int)
154                 */
155                @Override
156                public int asInt(int index) {
157                        return ((Number)get(index)).intValue();
158                }
159                
160                /* (non-Javadoc)
161                 * @see org.jdrupes.json.JsonArrayItf#asLong(int)
162                 */
163                @Override
164                public long asLong(int index) {
165                        return ((Number)get(index)).longValue();
166                }
167                
168                /* (non-Javadoc)
169                 * @see org.jdrupes.json.JsonArrayItf#asBoolean(int)
170                 */
171                @Override
172                public boolean asBoolean(int index) {
173                        return (Boolean)get(index);
174                }
175                
176                /* (non-Javadoc)
177                 * @see org.jdrupes.json.JsonArrayItf#asFloat(int)
178                 */
179                @Override
180                public float asFloat(int index) {
181                        return ((Number)get(index)).floatValue();
182                }
183                
184                /* (non-Javadoc)
185                 * @see org.jdrupes.json.JsonArrayItf#asDouble(int)
186                 */
187                @Override
188                public double asDouble(int index) {
189                        return ((Number)get(index)).doubleValue();
190                }
191                
192                /* (non-Javadoc)
193                 * @see org.jdrupes.json.JsonArrayItf#asArray(int)
194                 */
195                @Override
196                @SuppressWarnings("unchecked")
197                public JsonArray asArray(int index) {
198                        Object value = get(index);
199                        if (value instanceof JsonArray) {
200                                return (JsonArray) value;
201                        }
202                        if (value instanceof List) {
203                                return JsonArray.from((List<Object>) value);                    
204                        }
205                        throw new IllegalStateException("Not an array.");
206                }
207
208        }
209        
210        /**
211         * Instances of this class are used as default representations for JSON
212         * arrays.
213         */
214        public static class JsonArrayWrapper implements JsonArray {
215
216                private List<Object> backing;
217                
218                private JsonArrayWrapper(List<Object> backing) {
219                        this.backing = backing;
220                }
221
222                @Override
223                public List<Object> backing() {
224                        return backing;
225                }
226                
227                /* (non-Javadoc)
228                 * @see org.jdrupes.json.JsonArray#size()
229                 */
230                @Override
231                public int size() {
232                        return backing.size();
233                }
234
235                /* (non-Javadoc)
236                 * @see org.jdrupes.json.JsonArray#stream()
237                 */
238                @Override
239                public Stream<Object> stream() {
240                        return backing.stream();
241                }
242
243                /* (non-Javadoc)
244                 * @see org.jdrupes.json.JsonArrayItf#arrayStream()
245                 */
246                @Override
247                @SuppressWarnings("unchecked")
248                public Stream<JsonArray> arrayStream() {
249                        return backing.stream().map(
250                                        obj -> JsonArray.from((List<Object>)obj));
251                }
252                
253                /* (non-Javadoc)
254                 * @see org.jdrupes.json.JsonArrayItf#append(java.lang.Object)
255                 */
256                @Override
257                public JsonArray append(Object value) {
258                        backing.add(value);
259                        return this;
260                }
261                
262                @Override
263                public Object get(int index) {
264                        return backing.get(index);
265                }
266
267                /* (non-Javadoc)
268                 * @see org.jdrupes.json.JsonArrayItf#asString(int)
269                 */
270                @Override
271                public String asString(int index) {
272                        return (String)backing.get(index);
273                }
274                
275                /* (non-Javadoc)
276                 * @see org.jdrupes.json.JsonArrayItf#asInt(int)
277                 */
278                @Override
279                public int asInt(int index) {
280                        return ((Number)backing.get(index)).intValue();
281                }
282                
283                /* (non-Javadoc)
284                 * @see org.jdrupes.json.JsonArrayItf#asLong(int)
285                 */
286                @Override
287                public long asLong(int index) {
288                        return ((Number)backing.get(index)).longValue();
289                }
290                
291                /* (non-Javadoc)
292                 * @see org.jdrupes.json.JsonArrayItf#asBoolean(int)
293                 */
294                @Override
295                public boolean asBoolean(int index) {
296                        return (Boolean)backing.get(index);
297                }
298                
299                /* (non-Javadoc)
300                 * @see org.jdrupes.json.JsonArrayItf#asFloat(int)
301                 */
302                @Override
303                public float asFloat(int index) {
304                        return ((Number)backing.get(index)).floatValue();
305                }
306                
307                /* (non-Javadoc)
308                 * @see org.jdrupes.json.JsonArrayItf#asDouble(int)
309                 */
310                @Override
311                public double asDouble(int index) {
312                        return ((Number)backing.get(index)).doubleValue();
313                }
314                
315                /* (non-Javadoc)
316                 * @see org.jdrupes.json.JsonArrayItf#asArray(int)
317                 */
318                @Override
319                @SuppressWarnings("unchecked")
320                public JsonArray asArray(int index) {
321                        Object value = backing.get(index);
322                        if (value instanceof JsonArray) {
323                                return (JsonArray) value;
324                        }
325                        if (value instanceof List) {
326                                return JsonArray.from((List<Object>) value);                    
327                        }
328                        throw new IllegalStateException("Not an array.");
329                }
330
331        }
332}