1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.io; 19 20 /** 21 * An EmulatedFields is an object that represents a set of emulated fields for 22 * an object being dumped or loaded. It allows objects to be dumped with a shape 23 * different than the fields they were declared to have. 24 * 25 * @see ObjectInputStream.GetField 26 * @see ObjectOutputStream.PutField 27 * @see EmulatedFieldsForLoading 28 * @see EmulatedFieldsForDumping 29 */ 30 class EmulatedFields { 31 32 // A slot is a field plus its value 33 static class ObjectSlot { 34 35 // Field descriptor 36 ObjectStreamField field; 37 38 // Actual value this emulated field holds 39 Object fieldValue; 40 41 // If this field has a default value (true) or something has been 42 // assigned (false) 43 boolean defaulted = true; 44 45 /** 46 * Returns the descriptor for this emulated field. 47 * 48 * @return the field descriptor 49 */ 50 public ObjectStreamField getField() { 51 return field; 52 } 53 54 /** 55 * Returns the value held by this emulated field. 56 * 57 * @return the field value 58 */ 59 public Object getFieldValue() { 60 return fieldValue; 61 } 62 } 63 64 // The collection of slots the receiver represents 65 private ObjectSlot[] slotsToSerialize; 66 67 private ObjectStreamField[] declaredFields; 68 69 /** 70 * Constructs a new instance of EmulatedFields. 71 * 72 * @param fields 73 * an array of ObjectStreamFields, which describe the fields to 74 * be emulated (names, types, etc). 75 * @param declared 76 * an array of ObjectStreamFields, which describe the declared 77 * fields. 78 */ 79 public EmulatedFields(ObjectStreamField[] fields, 80 ObjectStreamField[] declared) { 81 super(); 82 // We assume the slots are already sorted in the right shape for dumping 83 buildSlots(fields); 84 declaredFields = declared; 85 } 86 87 /** 88 * Build emulated slots that correspond to emulated fields. A slot is a 89 * field descriptor (ObjectStreamField) plus the actual value it holds. 90 * 91 * @param fields 92 * an array of ObjectStreamField, which describe the fields to be 93 * emulated (names, types, etc). 94 */ 95 private void buildSlots(ObjectStreamField[] fields) { 96 slotsToSerialize = new ObjectSlot[fields.length]; 97 for (int i = 0; i < fields.length; i++) { 98 ObjectSlot s = new ObjectSlot(); 99 slotsToSerialize[i] = s; 100 s.field = fields[i]; 101 } 102 // We assume the slots are already sorted in the right shape for dumping 103 } 104 105 /** 106 * Returns {@code true} indicating the field called {@code name} has not had 107 * a value explicitly assigned and that it still holds a default value for 108 * its type, or {@code false} indicating that the field named has been 109 * assigned a value explicitly. 110 * 111 * @param name 112 * the name of the field to test. 113 * @return {@code true} if {@code name} still holds its default value, 114 * {@code false} otherwise 115 * 116 * @throws IllegalArgumentException 117 * if {@code name} is {@code null} 118 */ 119 public boolean defaulted(String name) throws IllegalArgumentException { 120 ObjectSlot slot = findSlot(name, null); 121 if (slot == null) { 122 throw new IllegalArgumentException("no field '" + name + "'"); 123 } 124 return slot.defaulted; 125 } 126 127 /** 128 * Finds and returns an ObjectSlot that corresponds to a field named {@code 129 * fieldName} and type {@code fieldType}. If the field type {@code 130 * fieldType} corresponds to a primitive type, the field type has to match 131 * exactly or {@code null} is returned. If the field type {@code fieldType} 132 * corresponds to an object type, the field type has to be compatible in 133 * terms of assignment, or null is returned. If {@code fieldType} is {@code 134 * null}, no such compatibility checking is performed and the slot is 135 * returned. 136 * 137 * @param fieldName 138 * the name of the field to find 139 * @param fieldType 140 * the type of the field. This will be used to test 141 * compatibility. If {@code null}, no testing is done, the 142 * corresponding slot is returned. 143 * @return the object slot, or {@code null} if there is no field with that 144 * name, or no compatible field (relative to {@code fieldType}) 145 */ 146 private ObjectSlot findSlot(String fieldName, Class<?> fieldType) { 147 boolean isPrimitive = fieldType != null && fieldType.isPrimitive(); 148 149 for (int i = 0; i < slotsToSerialize.length; i++) { 150 ObjectSlot slot = slotsToSerialize[i]; 151 if (slot.field.getName().equals(fieldName)) { 152 if (isPrimitive) { 153 // Looking for a primitive type field. Types must match 154 // *exactly* 155 if (slot.field.getType() == fieldType) { 156 return slot; 157 } 158 } else { 159 // Looking for a non-primitive type field. 160 if (fieldType == null) { 161 return slot; // Null means we take anything 162 } 163 // Types must be compatible (assignment) 164 if (slot.field.getType().isAssignableFrom(fieldType)) { 165 return slot; 166 } 167 } 168 } 169 } 170 171 if (declaredFields != null) { 172 for (int i = 0; i < declaredFields.length; i++) { 173 ObjectStreamField field = declaredFields[i]; 174 if (field.getName().equals(fieldName)) { 175 if (isPrimitive ? field.getType() == fieldType 176 : fieldType == null 177 || field.getType().isAssignableFrom( 178 fieldType)) { 179 ObjectSlot slot = new ObjectSlot(); 180 slot.field = field; 181 slot.defaulted = true; 182 return slot; 183 } 184 } 185 } 186 } 187 return null; 188 } 189 190 /** 191 * Finds and returns the byte value of a given field named {@code name} 192 * in the receiver. If the field has not been assigned any value yet, the 193 * default value {@code defaultValue} is returned instead. 194 * 195 * @param name 196 * the name of the field to find. 197 * @param defaultValue 198 * return value in case the field has not been assigned to yet. 199 * @return the value of the given field if it has been assigned, the default 200 * value otherwise. 201 * 202 * @throws IllegalArgumentException 203 * if the corresponding field can not be found. 204 */ 205 public byte get(String name, byte defaultValue) 206 throws IllegalArgumentException { 207 ObjectSlot slot = findSlot(name, Byte.TYPE); 208 // if not initialized yet, we give the default value 209 if (slot == null) { 210 throw new IllegalArgumentException("no byte field '" + name + "'"); 211 } 212 return slot.defaulted ? defaultValue : ((Byte) slot.fieldValue) 213 .byteValue(); 214 } 215 216 /** 217 * Finds and returns the char value of a given field named {@code name} in the 218 * receiver. If the field has not been assigned any value yet, the default 219 * value {@code defaultValue} is returned instead. 220 * 221 * @param name 222 * the name of the field to find. 223 * @param defaultValue 224 * return value in case the field has not been assigned to yet. 225 * @return the value of the given field if it has been assigned, the default 226 * value otherwise. 227 * 228 * @throws IllegalArgumentException 229 * if the corresponding field can not be found. 230 */ 231 public char get(String name, char defaultValue) 232 throws IllegalArgumentException { 233 ObjectSlot slot = findSlot(name, Character.TYPE); 234 // if not initialized yet, we give the default value 235 if (slot == null) { 236 throw new IllegalArgumentException("no char field '" + name + "'"); 237 } 238 return slot.defaulted ? defaultValue : ((Character) slot.fieldValue) 239 .charValue(); 240 } 241 242 /** 243 * Finds and returns the double value of a given field named {@code name} 244 * in the receiver. If the field has not been assigned any value yet, the 245 * default value {@code defaultValue} is returned instead. 246 * 247 * @param name 248 * the name of the field to find. 249 * @param defaultValue 250 * return value in case the field has not been assigned to yet. 251 * @return the value of the given field if it has been assigned, the default 252 * value otherwise. 253 * 254 * @throws IllegalArgumentException 255 * if the corresponding field can not be found. 256 */ 257 public double get(String name, double defaultValue) 258 throws IllegalArgumentException { 259 ObjectSlot slot = findSlot(name, Double.TYPE); 260 // if not initialized yet, we give the default value 261 if (slot == null) { 262 throw new IllegalArgumentException("no double field '" + name + "'"); 263 } 264 return slot.defaulted ? defaultValue : ((Double) slot.fieldValue) 265 .doubleValue(); 266 } 267 268 /** 269 * Finds and returns the float value of a given field named {@code name} in 270 * the receiver. If the field has not been assigned any value yet, the 271 * default value {@code defaultValue} is returned instead. 272 * 273 * @param name 274 * the name of the field to find. 275 * @param defaultValue 276 * return value in case the field has not been assigned to yet. 277 * @return the value of the given field if it has been assigned, the default 278 * value otherwise. 279 * 280 * @throws IllegalArgumentException 281 * if the corresponding field can not be found. 282 */ 283 public float get(String name, float defaultValue) 284 throws IllegalArgumentException { 285 ObjectSlot slot = findSlot(name, Float.TYPE); 286 // if not initialized yet, we give the default value 287 if (slot == null) { 288 throw new IllegalArgumentException("no float field '" + name + "'"); 289 } 290 return slot.defaulted ? defaultValue : ((Float) slot.fieldValue) 291 .floatValue(); 292 } 293 294 /** 295 * Finds and returns the int value of a given field named {@code name} in the 296 * receiver. If the field has not been assigned any value yet, the default 297 * value {@code defaultValue} is returned instead. 298 * 299 * @param name 300 * the name of the field to find. 301 * @param defaultValue 302 * return value in case the field has not been assigned to yet. 303 * @return the value of the given field if it has been assigned, the default 304 * value otherwise. 305 * 306 * @throws IllegalArgumentException 307 * if the corresponding field can not be found. 308 */ 309 public int get(String name, int defaultValue) 310 throws IllegalArgumentException { 311 ObjectSlot slot = findSlot(name, Integer.TYPE); 312 // if not initialized yet, we give the default value 313 if (slot == null) { 314 throw new IllegalArgumentException("no int field '" + name + "'"); 315 } 316 return slot.defaulted ? defaultValue : ((Integer) slot.fieldValue) 317 .intValue(); 318 } 319 320 /** 321 * Finds and returns the long value of a given field named {@code name} in the 322 * receiver. If the field has not been assigned any value yet, the default 323 * value {@code defaultValue} is returned instead. 324 * 325 * @param name 326 * the name of the field to find. 327 * @param defaultValue 328 * return value in case the field has not been assigned to yet. 329 * @return the value of the given field if it has been assigned, the default 330 * value otherwise. 331 * 332 * @throws IllegalArgumentException 333 * if the corresponding field can not be found. 334 */ 335 public long get(String name, long defaultValue) 336 throws IllegalArgumentException { 337 ObjectSlot slot = findSlot(name, Long.TYPE); 338 // if not initialized yet, we give the default value 339 if (slot == null) { 340 throw new IllegalArgumentException("no long field '" + name + "'"); 341 } 342 return slot.defaulted ? defaultValue : ((Long) slot.fieldValue) 343 .longValue(); 344 } 345 346 /** 347 * Finds and returns the Object value of a given field named {@code name} in 348 * the receiver. If the field has not been assigned any value yet, the 349 * default value {@code defaultValue} is returned instead. 350 * 351 * @param name 352 * the name of the field to find. 353 * @param defaultValue 354 * return value in case the field has not been assigned to yet. 355 * @return the value of the given field if it has been assigned, the default 356 * value otherwise. 357 * 358 * @throws IllegalArgumentException 359 * if the corresponding field can not be found. 360 */ 361 public Object get(String name, Object defaultValue) 362 throws IllegalArgumentException { 363 ObjectSlot slot = findSlot(name, null); 364 // if not initialized yet, we give the default value 365 if (slot == null || slot.field.getType().isPrimitive()) { 366 throw new IllegalArgumentException("no Object field '" + name + "'"); 367 } 368 return slot.defaulted ? defaultValue : slot.fieldValue; 369 } 370 371 /** 372 * Finds and returns the short value of a given field named {@code name} in 373 * the receiver. If the field has not been assigned any value yet, the 374 * default value {@code defaultValue} is returned instead. 375 * 376 * @param name 377 * the name of the field to find. 378 * @param defaultValue 379 * return value in case the field has not been assigned to yet. 380 * @return the value of the given field if it has been assigned, the default 381 * value otherwise. 382 * 383 * @throws IllegalArgumentException 384 * if the corresponding field can not be found. 385 */ 386 public short get(String name, short defaultValue) 387 throws IllegalArgumentException { 388 ObjectSlot slot = findSlot(name, Short.TYPE); 389 // if not initialized yet, we give the default value 390 if (slot == null) { 391 throw new IllegalArgumentException("no short field '" + name + "'"); 392 } 393 return slot.defaulted ? defaultValue : ((Short) slot.fieldValue) 394 .shortValue(); 395 } 396 397 /** 398 * Finds and returns the boolean value of a given field named {@code name} in 399 * the receiver. If the field has not been assigned any value yet, the 400 * default value {@code defaultValue} is returned instead. 401 * 402 * @param name 403 * the name of the field to find. 404 * @param defaultValue 405 * return value in case the field has not been assigned to yet. 406 * @return the value of the given field if it has been assigned, the default 407 * value otherwise. 408 * 409 * @throws IllegalArgumentException 410 * if the corresponding field can not be found. 411 */ 412 public boolean get(String name, boolean defaultValue) 413 throws IllegalArgumentException { 414 ObjectSlot slot = findSlot(name, Boolean.TYPE); 415 // if not initialized yet, we give the default value 416 if (slot == null) { 417 throw new IllegalArgumentException("no boolean field '" + name + "'"); 418 } 419 return slot.defaulted ? defaultValue : ((Boolean) slot.fieldValue) 420 .booleanValue(); 421 } 422 423 /** 424 * Find and set the byte value of a given field named {@code name} in the 425 * receiver. 426 * 427 * @param name 428 * the name of the field to set. 429 * @param value 430 * new value for the field. 431 * 432 * @throws IllegalArgumentException 433 * if the corresponding field can not be found. 434 */ 435 public void put(String name, byte value) throws IllegalArgumentException { 436 ObjectSlot slot = findSlot(name, Byte.TYPE); 437 if (slot == null) { 438 throw new IllegalArgumentException("no byte field '" + name + "'"); 439 } 440 slot.fieldValue = Byte.valueOf(value); 441 slot.defaulted = false; // No longer default value 442 } 443 444 /** 445 * Find and set the char value of a given field named {@code name} in the 446 * receiver. 447 * 448 * @param name 449 * the name of the field to set. 450 * @param value 451 * new value for the field. 452 * 453 * @throws IllegalArgumentException 454 * if the corresponding field can not be found. 455 */ 456 public void put(String name, char value) throws IllegalArgumentException { 457 ObjectSlot slot = findSlot(name, Character.TYPE); 458 if (slot == null) { 459 throw new IllegalArgumentException("no char field '" + name + "'"); 460 } 461 slot.fieldValue = Character.valueOf(value); 462 slot.defaulted = false; // No longer default value 463 } 464 465 /** 466 * Find and set the double value of a given field named {@code name} in the 467 * receiver. 468 * 469 * @param name 470 * the name of the field to set. 471 * @param value 472 * new value for the field. 473 * 474 * @throws IllegalArgumentException 475 * if the corresponding field can not be found. 476 */ 477 public void put(String name, double value) throws IllegalArgumentException { 478 ObjectSlot slot = findSlot(name, Double.TYPE); 479 if (slot == null) { 480 throw new IllegalArgumentException("no double field '" + name + "'"); 481 } 482 slot.fieldValue = Double.valueOf(value); 483 slot.defaulted = false; // No longer default value 484 } 485 486 /** 487 * Find and set the float value of a given field named {@code name} in the 488 * receiver. 489 * 490 * @param name 491 * the name of the field to set. 492 * @param value 493 * new value for the field. 494 * 495 * @throws IllegalArgumentException 496 * if the corresponding field can not be found. 497 */ 498 public void put(String name, float value) throws IllegalArgumentException { 499 ObjectSlot slot = findSlot(name, Float.TYPE); 500 if (slot == null) { 501 throw new IllegalArgumentException("no float field '" + name + "'"); 502 } 503 slot.fieldValue = Float.valueOf(value); 504 slot.defaulted = false; // No longer default value 505 } 506 507 /** 508 * Find and set the int value of a given field named {@code name} in the 509 * receiver. 510 * 511 * @param name 512 * the name of the field to set. 513 * @param value 514 * new value for the field. 515 * 516 * @throws IllegalArgumentException 517 * if the corresponding field can not be found. 518 */ 519 public void put(String name, int value) throws IllegalArgumentException { 520 ObjectSlot slot = findSlot(name, Integer.TYPE); 521 if (slot == null) { 522 throw new IllegalArgumentException("no integer field '" + name + "'"); 523 } 524 slot.fieldValue = Integer.valueOf(value); 525 slot.defaulted = false; // No longer default value 526 } 527 528 /** 529 * Find and set the long value of a given field named {@code name} in the 530 * receiver. 531 * 532 * @param name 533 * the name of the field to set. 534 * @param value 535 * new value for the field. 536 * 537 * @throws IllegalArgumentException 538 * if the corresponding field can not be found. 539 */ 540 public void put(String name, long value) throws IllegalArgumentException { 541 ObjectSlot slot = findSlot(name, Long.TYPE); 542 if (slot == null) { 543 throw new IllegalArgumentException("no long field '" + name + "'"); 544 } 545 slot.fieldValue = Long.valueOf(value); 546 slot.defaulted = false; // No longer default value 547 } 548 549 /** 550 * Find and set the Object value of a given field named {@code name} in the 551 * receiver. 552 * 553 * @param name 554 * the name of the field to set. 555 * @param value 556 * new value for the field. 557 * 558 * @throws IllegalArgumentException 559 * if the corresponding field can not be found. 560 */ 561 public void put(String name, Object value) throws IllegalArgumentException { 562 Class<?> valueClass = null; 563 if (value != null) { 564 valueClass = value.getClass(); 565 } 566 ObjectSlot slot = findSlot(name, valueClass); 567 if (slot == null) { 568 throw new IllegalArgumentException("no Object field '" + name + "'"); 569 } 570 slot.fieldValue = value; 571 slot.defaulted = false; // No longer default value 572 } 573 574 /** 575 * Find and set the short value of a given field named {@code name} in the 576 * receiver. 577 * 578 * @param name 579 * the name of the field to set. 580 * @param value 581 * new value for the field. 582 * 583 * @throws IllegalArgumentException 584 * if the corresponding field can not be found. 585 */ 586 public void put(String name, short value) throws IllegalArgumentException { 587 ObjectSlot slot = findSlot(name, Short.TYPE); 588 if (slot == null) { 589 throw new IllegalArgumentException("no short field '" + name + "'"); 590 } 591 slot.fieldValue = Short.valueOf(value); 592 slot.defaulted = false; // No longer default value 593 } 594 595 /** 596 * Find and set the boolean value of a given field named {@code name} in the 597 * receiver. 598 * 599 * @param name 600 * the name of the field to set. 601 * @param value 602 * new value for the field. 603 * 604 * @throws IllegalArgumentException 605 * if the corresponding field can not be found. 606 */ 607 public void put(String name, boolean value) throws IllegalArgumentException { 608 ObjectSlot slot = findSlot(name, Boolean.TYPE); 609 if (slot == null) { 610 throw new IllegalArgumentException("no boolean field '" + name + "'"); 611 } 612 slot.fieldValue = Boolean.valueOf(value); 613 slot.defaulted = false; // No longer default value 614 } 615 616 /** 617 * Return the array of ObjectSlot the receiver represents. 618 * 619 * @return array of ObjectSlot the receiver represents. 620 */ 621 public ObjectSlot[] slots() { 622 return slotsToSerialize; 623 } 624 } 625