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.internal; 014 015import static org.apache.juneau.common.internal.StringUtils.*; 016import static org.apache.juneau.common.internal.ThrowableUtils.*; 017import static org.apache.juneau.internal.ConverterUtils.*; 018import static java.util.Collections.*; 019 020import java.lang.reflect.*; 021import java.util.*; 022 023import org.apache.juneau.collections.*; 024import org.apache.juneau.parser.*; 025 026/** 027 * Builder for lists. 028 * 029 * <h5 class='section'>See Also:</h5><ul> 030 * </ul> 031 * 032 * @param <E> Element type. 033 */ 034public final class ListBuilder<E> { 035 036 //----------------------------------------------------------------------------------------------------------------- 037 // Static 038 //----------------------------------------------------------------------------------------------------------------- 039 040 /** 041 * Static creator. 042 * 043 * @param <E> The element type. 044 * @param elementType The element type. 045 * @param elementTypeArgs Optional element type arguments. 046 * @return A new builder. 047 */ 048 public static <E> ListBuilder<E> create(Class<E> elementType, Type...elementTypeArgs) { 049 return new ListBuilder<>(elementType, elementTypeArgs); 050 } 051 052 //----------------------------------------------------------------------------------------------------------------- 053 // Instance 054 //----------------------------------------------------------------------------------------------------------------- 055 056 private List<E> list; 057 private boolean unmodifiable = false, sparse = false; 058 private Comparator<E> comparator; 059 060 private Class<E> elementType; 061 private Type[] elementTypeArgs; 062 063 /** 064 * Constructor. 065 * 066 * @param elementType The element type. 067 * @param elementTypeArgs The element type generic arguments if there are any. 068 */ 069 public ListBuilder(Class<E> elementType, Type...elementTypeArgs) { 070 this.elementType = elementType; 071 this.elementTypeArgs = elementTypeArgs; 072 } 073 074 /** 075 * Constructor. 076 * 077 * @param addTo The list to add to. 078 */ 079 public ListBuilder(List<E> addTo) { 080 this.list = addTo; 081 } 082 083 /** 084 * Builds the list. 085 * 086 * @return A list conforming to the settings on this builder. 087 */ 088 public List<E> build() { 089 if (sparse) { 090 if (list != null && list.isEmpty()) 091 list = null; 092 } else { 093 if (list == null) 094 list = new ArrayList<>(0); 095 } 096 if (list != null) { 097 if (comparator != null) 098 Collections.sort(list, comparator); 099 if (unmodifiable) 100 list = unmodifiableList(list); 101 } 102 return list; 103 } 104 105 /** 106 * When specified, the {@link #build()} method will return <jk>null</jk> if the list is empty. 107 * 108 * <p> 109 * Otherwise {@link #build()} will never return <jk>null</jk>. 110 * 111 * @return This object. 112 */ 113 public ListBuilder<E> sparse() { 114 this.sparse = true; 115 return this; 116 } 117 118 /** 119 * When specified, {@link #build()} will return an unmodifiable list. 120 * 121 * @return This object. 122 */ 123 public ListBuilder<E> unmodifiable() { 124 this.unmodifiable = true; 125 return this; 126 } 127 128 /** 129 * Forces the existing list to be copied instead of appended to. 130 * 131 * @return This object. 132 */ 133 public ListBuilder<E> copy() { 134 if (list != null) 135 list = new ArrayList<>(list); 136 return this; 137 } 138 139 /** 140 * Sorts the contents of the list. 141 * 142 * @return This object. 143 */ 144 @SuppressWarnings("unchecked") 145 public ListBuilder<E> sorted() { 146 return sorted((Comparator<E>)Comparator.naturalOrder()); 147 } 148 149 /** 150 * Sorts the contents of the list using the specified comparator. 151 * 152 * @param comparator The comparator to use for sorting. 153 * @return This object. 154 */ 155 public ListBuilder<E> sorted(Comparator<E> comparator) { 156 this.comparator = comparator; 157 return this; 158 } 159 160 /** 161 * Appends the contents of the specified collection into this list. 162 * 163 * <p> 164 * This is a no-op if the value is <jk>null</jk>. 165 * 166 * @param value The collection to add to this list. 167 * @return This object. 168 */ 169 public ListBuilder<E> addAll(Collection<E> value) { 170 if (value != null) { 171 if (list == null) 172 list = new LinkedList<>(value); 173 else 174 list.addAll(value); 175 } 176 return this; 177 } 178 179 /** 180 * Adds a single value to this list. 181 * 182 * @param value The value to add to this list. 183 * @return This object. 184 */ 185 public ListBuilder<E> add(E value) { 186 if (list == null) 187 list = new ArrayList<>(); 188 list.add(value); 189 return this; 190 } 191 192 /** 193 * Adds multiple values to this list. 194 * 195 * @param values The values to add to this list. 196 * @return This object. 197 */ 198 @SuppressWarnings("unchecked") 199 public ListBuilder<E> add(E...values) { 200 for (E v : values) 201 add(v); 202 return this; 203 } 204 205 /** 206 * Adds entries to this list via JSON array strings. 207 * 208 * @param values The JSON array strings to parse and add to this list. 209 * @return This object. 210 */ 211 public ListBuilder<E> addJson(String...values) { 212 return addAny((Object[])values); 213 } 214 215 /** 216 * Adds arbitrary values to this list. 217 * 218 * <p> 219 * Objects can be any of the following: 220 * <ul> 221 * <li>The same type or convertible to the element type of this list. 222 * <li>Collections or arrays of anything on this list. 223 * <li>JSON array strings parsed and convertible to the element type of this list. 224 * </ul> 225 * 226 * @param values The values to add. 227 * @return This object. 228 */ 229 public ListBuilder<E> addAny(Object... values) { 230 if (elementType == null) 231 throw new IllegalStateException("Unknown element type. Cannot use this method."); 232 try { 233 if (values != null) { 234 for (Object o : values) { 235 if (o != null) { 236 if (o instanceof Collection) { 237 ((Collection<?>)o).forEach(x -> addAny(x)); 238 } else if (o.getClass().isArray()) { 239 for (int i = 0; i < Array.getLength(o); i++) 240 addAny(Array.get(o, i)); 241 } else if (isJsonArray(o, false)) { 242 new JsonList(o.toString()).forEach(x -> addAny(x)); 243 } else if (elementType.isInstance(o)) { 244 add(elementType.cast(o)); 245 } else { 246 add(toType(o, elementType, elementTypeArgs)); 247 } 248 } 249 } 250 } 251 } catch (ParseException e) { 252 throw asRuntimeException(e); 253 } 254 return this; 255 } 256 257 /** 258 * Appends a value to this list of the flag is true. 259 * 260 * @param flag The flag. 261 * @param value The value. 262 * @return This object. 263 */ 264 public ListBuilder<E> addIf(boolean flag, E value) { 265 if (flag) 266 add(value); 267 return this; 268 } 269}