93 this(makeMap(fields));
94 }
95
96 /**
97 * <p>Construct a descriptor where the names and values of the fields
98 * are the keys and values of the given Map.</p>
99 *
100 * @param fields the field names and values
101 * @throws IllegalArgumentException if the parameter is null, or
102 * if a field name is null or empty, or if the same field name appears
103 * more than once (which can happen because field names are not case
104 * sensitive).
105 */
106 public ImmutableDescriptor(Map<String, ?> fields) {
107 if (fields == null)
108 throw new IllegalArgumentException("Null Map");
109 SortedMap<String, Object> map =
110 new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
111 for (Map.Entry<String, ?> entry : fields.entrySet()) {
112 String name = entry.getKey();
113 if (name == null || name.equals(""))
114 throw new IllegalArgumentException("Empty or null field name");
115 if (map.containsKey(name))
116 throw new IllegalArgumentException("Duplicate name: " + name);
117 map.put(name, entry.getValue());
118 }
119 int size = map.size();
120 this.names = map.keySet().toArray(new String[size]);
121 this.values = map.values().toArray(new Object[size]);
122 }
123
124 /**
125 * This method can replace a deserialized instance of this
126 * class with another instance. For example, it might replace
127 * a deserialized empty ImmutableDescriptor with
128 * {@link #EMPTY_DESCRIPTOR}.
129 *
130 * @return the replacement object, which may be {@code this}.
131 *
132 * @throws InvalidObjectException if the read object has invalid fields.
133 */
149 }
150 lastName = names[i];
151 }
152 }
153 if (bad)
154 throw new InvalidObjectException("Bad names or values");
155
156 return this;
157 }
158
159 private static SortedMap<String, ?> makeMap(String[] fieldNames,
160 Object[] fieldValues) {
161 if (fieldNames == null || fieldValues == null)
162 throw new IllegalArgumentException("Null array parameter");
163 if (fieldNames.length != fieldValues.length)
164 throw new IllegalArgumentException("Different size arrays");
165 SortedMap<String, Object> map =
166 new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
167 for (int i = 0; i < fieldNames.length; i++) {
168 String name = fieldNames[i];
169 if (name == null || name.equals(""))
170 throw new IllegalArgumentException("Empty or null field name");
171 Object old = map.put(name, fieldValues[i]);
172 if (old != null) {
173 throw new IllegalArgumentException("Duplicate field name: " +
174 name);
175 }
176 }
177 return map;
178 }
179
180 private static SortedMap<String, ?> makeMap(String[] fields) {
181 if (fields == null)
182 throw new IllegalArgumentException("Null fields parameter");
183 String[] fieldNames = new String[fields.length];
184 String[] fieldValues = new String[fields.length];
185 for (int i = 0; i < fields.length; i++) {
186 String field = fields[i];
187 int eq = field.indexOf('=');
188 if (eq < 0) {
189 throw new IllegalArgumentException("Missing = character: " +
316
317 public final String[] getFields() {
318 String[] result = new String[names.length];
319 for (int i = 0; i < result.length; i++) {
320 Object value = values[i];
321 if (value == null)
322 value = "";
323 else if (!(value instanceof String))
324 value = "(" + value + ")";
325 result[i] = names[i] + "=" + value;
326 }
327 return result;
328 }
329
330 public final Object[] getFieldValues(String... fieldNames) {
331 if (fieldNames == null)
332 return values.clone();
333 Object[] result = new Object[fieldNames.length];
334 for (int i = 0; i < fieldNames.length; i++) {
335 String name = fieldNames[i];
336 if (name != null && !name.equals(""))
337 result[i] = getFieldValue(name);
338 }
339 return result;
340 }
341
342 public final String[] getFieldNames() {
343 return names.clone();
344 }
345
346 /**
347 * Compares this descriptor to the given object. The objects are equal if
348 * the given object is also a Descriptor, and if the two Descriptors have
349 * the same field names (possibly differing in case) and the same
350 * associated values. The respective values for a field in the two
351 * Descriptors are equal if the following conditions hold:
352 *
353 * <ul>
354 * <li>If one value is null then the other must be too.</li>
355 * <li>If one value is a primitive array then the other must be a primitive
356 * array of the same type with the same elements.</li>
526 * If the field name is illegal or the field is not found,
527 * no exception is thrown.
528 *
529 * @exception RuntimeOperationsException if a field of the given name
530 * exists and the descriptor is immutable. The wrapped exception will
531 * be an {@link UnsupportedOperationException}.
532 */
533 public final void removeField(String fieldName) {
534 if (fieldName != null && fieldIndex(fieldName) >= 0)
535 unsupported();
536 }
537
538 static Descriptor nonNullDescriptor(Descriptor d) {
539 if (d == null)
540 return EMPTY_DESCRIPTOR;
541 else
542 return d;
543 }
544
545 private static void checkIllegalFieldName(String name) {
546 if (name == null || name.equals(""))
547 illegal("Null or empty field name");
548 }
549
550 private static void unsupported() {
551 UnsupportedOperationException uoe =
552 new UnsupportedOperationException("Descriptor is read-only");
553 throw new RuntimeOperationsException(uoe);
554 }
555
556 private static void illegal(String message) {
557 IllegalArgumentException iae = new IllegalArgumentException(message);
558 throw new RuntimeOperationsException(iae);
559 }
560 }
|
93 this(makeMap(fields));
94 }
95
96 /**
97 * <p>Construct a descriptor where the names and values of the fields
98 * are the keys and values of the given Map.</p>
99 *
100 * @param fields the field names and values
101 * @throws IllegalArgumentException if the parameter is null, or
102 * if a field name is null or empty, or if the same field name appears
103 * more than once (which can happen because field names are not case
104 * sensitive).
105 */
106 public ImmutableDescriptor(Map<String, ?> fields) {
107 if (fields == null)
108 throw new IllegalArgumentException("Null Map");
109 SortedMap<String, Object> map =
110 new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
111 for (Map.Entry<String, ?> entry : fields.entrySet()) {
112 String name = entry.getKey();
113 if (name == null || name.isEmpty())
114 throw new IllegalArgumentException("Empty or null field name");
115 if (map.containsKey(name))
116 throw new IllegalArgumentException("Duplicate name: " + name);
117 map.put(name, entry.getValue());
118 }
119 int size = map.size();
120 this.names = map.keySet().toArray(new String[size]);
121 this.values = map.values().toArray(new Object[size]);
122 }
123
124 /**
125 * This method can replace a deserialized instance of this
126 * class with another instance. For example, it might replace
127 * a deserialized empty ImmutableDescriptor with
128 * {@link #EMPTY_DESCRIPTOR}.
129 *
130 * @return the replacement object, which may be {@code this}.
131 *
132 * @throws InvalidObjectException if the read object has invalid fields.
133 */
149 }
150 lastName = names[i];
151 }
152 }
153 if (bad)
154 throw new InvalidObjectException("Bad names or values");
155
156 return this;
157 }
158
159 private static SortedMap<String, ?> makeMap(String[] fieldNames,
160 Object[] fieldValues) {
161 if (fieldNames == null || fieldValues == null)
162 throw new IllegalArgumentException("Null array parameter");
163 if (fieldNames.length != fieldValues.length)
164 throw new IllegalArgumentException("Different size arrays");
165 SortedMap<String, Object> map =
166 new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
167 for (int i = 0; i < fieldNames.length; i++) {
168 String name = fieldNames[i];
169 if (name == null || name.isEmpty())
170 throw new IllegalArgumentException("Empty or null field name");
171 Object old = map.put(name, fieldValues[i]);
172 if (old != null) {
173 throw new IllegalArgumentException("Duplicate field name: " +
174 name);
175 }
176 }
177 return map;
178 }
179
180 private static SortedMap<String, ?> makeMap(String[] fields) {
181 if (fields == null)
182 throw new IllegalArgumentException("Null fields parameter");
183 String[] fieldNames = new String[fields.length];
184 String[] fieldValues = new String[fields.length];
185 for (int i = 0; i < fields.length; i++) {
186 String field = fields[i];
187 int eq = field.indexOf('=');
188 if (eq < 0) {
189 throw new IllegalArgumentException("Missing = character: " +
316
317 public final String[] getFields() {
318 String[] result = new String[names.length];
319 for (int i = 0; i < result.length; i++) {
320 Object value = values[i];
321 if (value == null)
322 value = "";
323 else if (!(value instanceof String))
324 value = "(" + value + ")";
325 result[i] = names[i] + "=" + value;
326 }
327 return result;
328 }
329
330 public final Object[] getFieldValues(String... fieldNames) {
331 if (fieldNames == null)
332 return values.clone();
333 Object[] result = new Object[fieldNames.length];
334 for (int i = 0; i < fieldNames.length; i++) {
335 String name = fieldNames[i];
336 if (name != null && !name.isEmpty())
337 result[i] = getFieldValue(name);
338 }
339 return result;
340 }
341
342 public final String[] getFieldNames() {
343 return names.clone();
344 }
345
346 /**
347 * Compares this descriptor to the given object. The objects are equal if
348 * the given object is also a Descriptor, and if the two Descriptors have
349 * the same field names (possibly differing in case) and the same
350 * associated values. The respective values for a field in the two
351 * Descriptors are equal if the following conditions hold:
352 *
353 * <ul>
354 * <li>If one value is null then the other must be too.</li>
355 * <li>If one value is a primitive array then the other must be a primitive
356 * array of the same type with the same elements.</li>
526 * If the field name is illegal or the field is not found,
527 * no exception is thrown.
528 *
529 * @exception RuntimeOperationsException if a field of the given name
530 * exists and the descriptor is immutable. The wrapped exception will
531 * be an {@link UnsupportedOperationException}.
532 */
533 public final void removeField(String fieldName) {
534 if (fieldName != null && fieldIndex(fieldName) >= 0)
535 unsupported();
536 }
537
538 static Descriptor nonNullDescriptor(Descriptor d) {
539 if (d == null)
540 return EMPTY_DESCRIPTOR;
541 else
542 return d;
543 }
544
545 private static void checkIllegalFieldName(String name) {
546 if (name == null || name.isEmpty())
547 illegal("Null or empty field name");
548 }
549
550 private static void unsupported() {
551 UnsupportedOperationException uoe =
552 new UnsupportedOperationException("Descriptor is read-only");
553 throw new RuntimeOperationsException(uoe);
554 }
555
556 private static void illegal(String message) {
557 IllegalArgumentException iae = new IllegalArgumentException(message);
558 throw new RuntimeOperationsException(iae);
559 }
560 }
|