001 package ezvcard.io.json; 002 003 import java.util.ArrayList; 004 import java.util.Arrays; 005 import java.util.Collections; 006 import java.util.List; 007 008 import ezvcard.property.Categories; 009 import ezvcard.property.Note; 010 import ezvcard.property.StructuredName; 011 012 /* 013 Copyright (c) 2013, Michael Angstadt 014 All rights reserved. 015 016 Redistribution and use in source and binary forms, with or without 017 modification, are permitted provided that the following conditions are met: 018 019 1. Redistributions of source code must retain the above copyright notice, this 020 list of conditions and the following disclaimer. 021 2. Redistributions in binary form must reproduce the above copyright notice, 022 this list of conditions and the following disclaimer in the documentation 023 and/or other materials provided with the distribution. 024 025 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 026 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 027 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 028 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 029 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 030 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 031 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 032 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 033 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 034 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 035 036 The views and conclusions contained in the software and documentation are those 037 of the authors and should not be interpreted as representing official policies, 038 either expressed or implied, of the FreeBSD Project. 039 */ 040 041 /** 042 * Holds the data type and value of a jCard property. 043 * @author Michael Angstadt 044 */ 045 public class JCardValue { 046 private final List<JsonValue> values; 047 048 /** 049 * Creates a new jCard value. 050 * @param values the values 051 */ 052 public JCardValue(List<JsonValue> values) { 053 this.values = Collections.unmodifiableList(values); 054 } 055 056 /** 057 * Creates a new jCard value. 058 * @param values the values 059 */ 060 public JCardValue(JsonValue... values) { 061 this.values = Arrays.asList(values); //unmodifiable 062 } 063 064 /** 065 * Creates a single-valued value. 066 * @param value the value 067 * @return the jCard value 068 */ 069 public static JCardValue single(Object value) { 070 return new JCardValue(new JsonValue(value)); 071 } 072 073 /** 074 * Creates a multi-valued value. 075 * @param values the values 076 * @return the jCard value 077 */ 078 public static JCardValue multi(Object... values) { 079 return multi(Arrays.asList(values)); 080 } 081 082 /** 083 * Creates a multi-valued value. 084 * @param values the values 085 * @return the jCard value 086 */ 087 public static JCardValue multi(List<?> values) { 088 List<JsonValue> multiValues = new ArrayList<JsonValue>(values.size()); 089 for (Object value : values) { 090 multiValues.add(new JsonValue(value)); 091 } 092 return new JCardValue(multiValues); 093 } 094 095 /** 096 * <p> 097 * Creates a structured value. 098 * </p> 099 * <p> 100 * This method accepts a vararg of {@link Object} instances. {@link List} 101 * objects will be treated as multi-valued components. Null objects will be 102 * treated as empty components. 103 * </p> 104 * @param values the values 105 * @return the jCard value 106 */ 107 public static JCardValue structured(Object... values) { 108 List<List<?>> valuesList = new ArrayList<List<?>>(values.length); 109 for (Object value : values) { 110 List<?> list = (value instanceof List) ? (List<?>) value : Arrays.asList(value); 111 valuesList.add(list); 112 } 113 return structured(valuesList); 114 } 115 116 /** 117 * Creates a structured value. 118 * @param values the values 119 * @return the jCard value 120 */ 121 public static JCardValue structured(List<List<?>> values) { 122 List<JsonValue> array = new ArrayList<JsonValue>(values.size()); 123 124 for (List<?> list : values) { 125 if (list.isEmpty()) { 126 array.add(new JsonValue("")); 127 continue; 128 } 129 130 if (list.size() == 1) { 131 Object value = list.get(0); 132 if (value == null) { 133 value = ""; 134 } 135 array.add(new JsonValue(value)); 136 continue; 137 } 138 139 List<JsonValue> subArray = new ArrayList<JsonValue>(list.size()); 140 for (Object value : list) { 141 if (value == null) { 142 value = ""; 143 } 144 subArray.add(new JsonValue(value)); 145 } 146 array.add(new JsonValue(subArray)); 147 } 148 149 return new JCardValue(new JsonValue(array)); 150 } 151 152 /** 153 * Gets all the JSON values. 154 * @return the JSON values 155 */ 156 public List<JsonValue> getValues() { 157 return values; 158 } 159 160 /** 161 * Gets the value of a single-valued property (such as {@link Note}). 162 * @return the value or empty string if not found 163 */ 164 public String asSingle() { 165 if (values.isEmpty()) { 166 return ""; 167 } 168 169 JsonValue first = values.get(0); 170 if (first.isNull()) { 171 return ""; 172 } 173 174 Object obj = first.getValue(); 175 if (obj != null) { 176 return obj.toString(); 177 } 178 179 //get the first element of the array 180 List<JsonValue> array = first.getArray(); 181 if (array != null && !array.isEmpty()) { 182 obj = array.get(0).getValue(); 183 if (obj != null) { 184 return obj.toString(); 185 } 186 } 187 188 return ""; 189 } 190 191 /** 192 * Gets the value of a structured property (such as 193 * {@link StructuredName}). 194 * @return the values or empty list if not found 195 */ 196 public List<List<String>> asStructured() { 197 if (values.isEmpty()) { 198 return Collections.emptyList(); 199 } 200 201 JsonValue first = values.get(0); 202 203 //["gender", {}, "text", ["M", "text"] ] 204 List<JsonValue> array = first.getArray(); 205 if (array != null) { 206 List<List<String>> valuesStr = new ArrayList<List<String>>(array.size()); 207 for (JsonValue value : array) { 208 if (value.isNull()) { 209 valuesStr.add(Arrays.asList("")); 210 continue; 211 } 212 213 Object obj = value.getValue(); 214 if (obj != null) { 215 valuesStr.add(Arrays.asList(obj.toString())); 216 continue; 217 } 218 219 List<JsonValue> subArray = value.getArray(); 220 if (subArray != null) { 221 List<String> subValuesStr = new ArrayList<String>(subArray.size()); 222 for (JsonValue subArrayValue : subArray) { 223 if (subArrayValue.isNull()) { 224 subValuesStr.add(""); 225 continue; 226 } 227 228 obj = subArrayValue.getValue(); 229 if (obj != null) { 230 subValuesStr.add(obj.toString()); 231 continue; 232 } 233 } 234 valuesStr.add(subValuesStr); 235 } 236 } 237 return valuesStr; 238 } 239 240 //get the first value if it's not enclosed in an array 241 //["gender", {}, "text", "M"] 242 Object obj = first.getValue(); 243 if (obj != null) { 244 List<List<String>> values = new ArrayList<List<String>>(1); 245 values.add(Arrays.asList(obj.toString())); 246 return values; 247 } 248 249 //["gender", {}, "text", null] 250 if (first.isNull()) { 251 List<List<String>> values = new ArrayList<List<String>>(1); 252 values.add(Arrays.asList("")); 253 return values; 254 } 255 256 return Collections.emptyList(); 257 } 258 259 /** 260 * Gets the value of a multi-valued property (such as {@link Categories} 261 * ). 262 * @return the values or empty list if not found 263 */ 264 public List<String> asMulti() { 265 if (values.isEmpty()) { 266 return Collections.emptyList(); 267 } 268 269 List<String> multi = new ArrayList<String>(values.size()); 270 for (JsonValue value : values) { 271 if (value.isNull()) { 272 multi.add(""); 273 continue; 274 } 275 276 Object obj = value.getValue(); 277 if (obj != null) { 278 multi.add(obj.toString()); 279 continue; 280 } 281 } 282 return multi; 283 } 284 }