90 * data</i> instance; must not be null. |
90 * data</i> instance; must not be null. |
91 * |
91 * |
92 * @param itemNames <tt>itemNames</tt> must list, in any order, all the |
92 * @param itemNames <tt>itemNames</tt> must list, in any order, all the |
93 * item names defined in <tt>compositeType</tt>; the order in which the |
93 * item names defined in <tt>compositeType</tt>; the order in which the |
94 * names are listed, is used to match values in <tt>itemValues[]</tt>; must |
94 * names are listed, is used to match values in <tt>itemValues[]</tt>; must |
95 * not be null. |
95 * not be null or empty. |
96 * |
96 * |
97 * @param itemValues the values of the items, listed in the same order as |
97 * @param itemValues the values of the items, listed in the same order as |
98 * their respective names in <tt>itemNames</tt>; each item value can be |
98 * their respective names in <tt>itemNames</tt>; each item value can be |
99 * null, but if it is non-null it must be a valid value for the open type |
99 * null, but if it is non-null it must be a valid value for the open type |
100 * defined in <tt>compositeType</tt> for the corresponding item; must be of |
100 * defined in <tt>compositeType</tt> for the corresponding item; must be of |
101 * the same size as <tt>itemNames</tt>; must not be null. |
101 * the same size as <tt>itemNames</tt>; must not be null or empty. |
102 * |
102 * |
103 * @throws IllegalArgumentException <tt>compositeType</tt> is null, or |
103 * @throws IllegalArgumentException <tt>compositeType</tt> is null, or |
104 * <tt>itemNames[]</tt> or <tt>itemValues[]</tt> is null, or one |
104 * <tt>itemNames[]</tt> or <tt>itemValues[]</tt> is null or empty, or one |
105 * of the elements in <tt>itemNames[]</tt> is a null or empty string, or |
105 * of the elements in <tt>itemNames[]</tt> is a null or empty string, or |
106 * <tt>itemNames[]</tt> and <tt>itemValues[]</tt> are not of the same size. |
106 * <tt>itemNames[]</tt> and <tt>itemValues[]</tt> are not of the same size. |
107 * |
107 * |
108 * @throws OpenDataException <tt>itemNames[]</tt> or |
108 * @throws OpenDataException <tt>itemNames[]</tt> or |
109 * <tt>itemValues[]</tt>'s size differs from the number of items defined in |
109 * <tt>itemValues[]</tt>'s size differs from the number of items defined in |
122 String[] itemNames, Object[] itemValues) |
122 String[] itemNames, Object[] itemValues) |
123 throws OpenDataException { |
123 throws OpenDataException { |
124 |
124 |
125 if (itemNames == null || itemValues == null) |
125 if (itemNames == null || itemValues == null) |
126 throw new IllegalArgumentException("Null itemNames or itemValues"); |
126 throw new IllegalArgumentException("Null itemNames or itemValues"); |
|
127 if (itemNames.length == 0 || itemValues.length == 0) |
|
128 throw new IllegalArgumentException("Empty itemNames or itemValues"); |
127 if (itemNames.length != itemValues.length) { |
129 if (itemNames.length != itemValues.length) { |
128 throw new IllegalArgumentException( |
130 throw new IllegalArgumentException( |
129 "Different lengths: itemNames[" + itemNames.length + |
131 "Different lengths: itemNames[" + itemNames.length + |
130 "], itemValues[" + itemValues.length + "]"); |
132 "], itemValues[" + itemValues.length + "]"); |
131 } |
133 } |
152 * |
154 * |
153 * @param compositeType the <i>composite type </i> of this <i>composite data</i> instance; |
155 * @param compositeType the <i>composite type </i> of this <i>composite data</i> instance; |
154 * must not be null. |
156 * must not be null. |
155 * @param items the mappings of all the item names to their values; |
157 * @param items the mappings of all the item names to their values; |
156 * <tt>items</tt> must contain all the item names defined in <tt>compositeType</tt>; |
158 * <tt>items</tt> must contain all the item names defined in <tt>compositeType</tt>; |
157 * must not be null. |
159 * must not be null or empty. |
158 * |
160 * |
159 * @throws IllegalArgumentException <tt>compositeType</tt> is null, or |
161 * @throws IllegalArgumentException <tt>compositeType</tt> is null, or |
160 * <tt>items</tt> is null, or one of the keys in <tt>items</tt> is a null |
162 * <tt>items</tt> is null or empty, or one of the keys in <tt>items</tt> is a null |
161 * or empty string. |
163 * or empty string. |
162 * @throws OpenDataException <tt>items</tt>' size differs from the |
164 * @throws OpenDataException <tt>items</tt>' size differs from the |
163 * number of items defined in <tt>compositeType</tt>, or one of the |
165 * number of items defined in <tt>compositeType</tt>, or one of the |
164 * keys in <tt>items</tt> does not exist as an item name defined in |
166 * keys in <tt>items</tt> does not exist as an item name defined in |
165 * <tt>compositeType</tt>, or one of the values in <tt>items</tt> |
167 * <tt>compositeType</tt>, or one of the values in <tt>items</tt> |
166 * is not a valid value for the corresponding item as defined in |
168 * is not a valid value for the corresponding item as defined in |
167 * <tt>compositeType</tt>. |
169 * <tt>compositeType</tt>. |
168 * @throws ArrayStoreException one or more keys in <tt>items</tt> is not of |
170 * @throws ArrayStoreException one or more keys in <tt>items</tt> is not of |
169 * the class <tt>java.lang.String</tt>. |
171 * the class <tt>java.lang.String</tt>. |
170 * |
|
171 * @see #toMap |
|
172 */ |
172 */ |
173 public CompositeDataSupport(CompositeType compositeType, |
173 public CompositeDataSupport(CompositeType compositeType, |
174 Map<String,?> items) |
174 Map<String,?> items) |
175 throws OpenDataException { |
175 throws OpenDataException { |
176 this(makeMap(items), compositeType); |
176 this(makeMap(items), compositeType); |
177 } |
177 } |
178 |
178 |
179 private static SortedMap<String, Object> makeMap(Map<String, ?> items) { |
179 private static SortedMap<String, Object> makeMap(Map<String, ?> items) { |
180 if (items == null) |
180 if (items == null || items.isEmpty()) |
181 throw new IllegalArgumentException("Null items map"); |
181 throw new IllegalArgumentException("Null or empty items map"); |
182 if (items.containsKey(null) || items.containsKey("")) |
|
183 throw new IllegalArgumentException("Null or empty item name"); |
|
184 |
182 |
185 SortedMap<String, Object> map = new TreeMap<String, Object>(); |
183 SortedMap<String, Object> map = new TreeMap<String, Object>(); |
186 for (Object key : items.keySet()) { |
184 for (Object key : items.keySet()) { |
|
185 if (key == null || key.equals("")) |
|
186 throw new IllegalArgumentException("Null or empty item name"); |
187 if (!(key instanceof String)) { |
187 if (!(key instanceof String)) { |
188 throw new ArrayStoreException("Item name is not string: " + key); |
188 throw new ArrayStoreException("Item name is not string: " + key); |
189 // This can happen because of erasure. The particular |
189 // This can happen because of erasure. The particular |
190 // exception is a historical artifact - an implementation |
190 // exception is a historical artifact - an implementation |
191 // detail that leaked into the API. |
191 // detail that leaked into the API. |
324 * item names. |
324 * item names. |
325 */ |
325 */ |
326 public Collection<?> values() { |
326 public Collection<?> values() { |
327 |
327 |
328 return Collections.unmodifiableCollection(contents.values()); |
328 return Collections.unmodifiableCollection(contents.values()); |
329 } |
|
330 |
|
331 /** |
|
332 * <p>Returns a Map representing the contents of the given CompositeData. |
|
333 * Each item in the CompositeData is represented by an entry in the map, |
|
334 * where the name and value of the item are the key and value of the entry. |
|
335 * The returned value is modifiable but modifications to it have no effect |
|
336 * on the original CompositeData.</p> |
|
337 * |
|
338 * <p>For example, if you have a CompositeData {@code cd1} and you want |
|
339 * to produce another CompositeData {@code cd2} which is the same except |
|
340 * that the value of its {@code id} item has been changed to 253, you |
|
341 * could write:</p> |
|
342 * |
|
343 * <pre> |
|
344 * CompositeData cd1 = ...; |
|
345 * {@code Map<String, Object>} map = CompositeDataSupport.toMap(cd1); |
|
346 * assert(map.get("id") instanceof Integer); |
|
347 * map.put("id", 253); |
|
348 * CompositeData cd2 = {@link #CompositeDataSupport(CompositeType, Map) |
|
349 * new CompositeDataSupport}(cd1.getCompositeType(), map); |
|
350 * </pre> |
|
351 * |
|
352 * <p>Logically, this method would be a method in the {@link CompositeData} |
|
353 * interface, but cannot be for compatibility reasons.</p> |
|
354 * |
|
355 * @param cd the CompositeData to convert to a Map. |
|
356 * |
|
357 * @return a Map that is a copy of the contents of {@code cd}. |
|
358 * |
|
359 * @throws IllegalArgumentException if {@code cd} is null. |
|
360 * |
|
361 * @see #CompositeDataSupport(CompositeType, Map) |
|
362 */ |
|
363 public static Map<String, Object> toMap(CompositeData cd) { |
|
364 if (cd == null) |
|
365 throw new IllegalArgumentException("Null argument"); |
|
366 |
|
367 // If we really wanted, we could check whether cd is a |
|
368 // CompositeDataSupport and return a copy of cd.contents if so, |
|
369 // but I don't think that would be substantially faster. |
|
370 Map<String, Object> map = new LinkedHashMap<String, Object>(); |
|
371 CompositeType ct = cd.getCompositeType(); |
|
372 for (String key : ct.keySet()) { |
|
373 Object value = cd.get(key); |
|
374 map.put(key, value); |
|
375 } |
|
376 return map; |
|
377 } |
329 } |
378 |
330 |
379 /** |
331 /** |
380 * Compares the specified <var>obj</var> parameter with this |
332 * Compares the specified <var>obj</var> parameter with this |
381 * <code>CompositeDataSupport</code> instance for equality. |
333 * <code>CompositeDataSupport</code> instance for equality. |