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}