| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.io; |
| |
| /** |
| * An EmulatedFields is an object that represents a set of emulated fields for |
| * an object being dumped or loaded. It allows objects to be dumped with a shape |
| * different than the fields they were declared to have. |
| * |
| * @see ObjectInputStream.GetField |
| * @see ObjectOutputStream.PutField |
| * @see EmulatedFieldsForLoading |
| * @see EmulatedFieldsForDumping |
| */ |
| class EmulatedFields { |
| |
| // A slot is a field plus its value |
| static class ObjectSlot { |
| |
| // Field descriptor |
| ObjectStreamField field; |
| |
| // Actual value this emulated field holds |
| Object fieldValue; |
| |
| // If this field has a default value (true) or something has been |
| // assigned (false) |
| boolean defaulted = true; |
| |
| /** |
| * Returns the descriptor for this emulated field. |
| * |
| * @return the field descriptor |
| */ |
| public ObjectStreamField getField() { |
| return field; |
| } |
| |
| /** |
| * Returns the value held by this emulated field. |
| * |
| * @return the field value |
| */ |
| public Object getFieldValue() { |
| return fieldValue; |
| } |
| } |
| |
| // The collection of slots the receiver represents |
| private ObjectSlot[] slotsToSerialize; |
| |
| private ObjectStreamField[] declaredFields; |
| |
| /** |
| * Constructs a new instance of EmulatedFields. |
| * |
| * @param fields |
| * an array of ObjectStreamFields, which describe the fields to |
| * be emulated (names, types, etc). |
| * @param declared |
| * an array of ObjectStreamFields, which describe the declared |
| * fields. |
| */ |
| public EmulatedFields(ObjectStreamField[] fields, ObjectStreamField[] declared) { |
| // We assume the slots are already sorted in the right shape for dumping |
| buildSlots(fields); |
| declaredFields = declared; |
| } |
| |
| /** |
| * Build emulated slots that correspond to emulated fields. A slot is a |
| * field descriptor (ObjectStreamField) plus the actual value it holds. |
| * |
| * @param fields |
| * an array of ObjectStreamField, which describe the fields to be |
| * emulated (names, types, etc). |
| */ |
| private void buildSlots(ObjectStreamField[] fields) { |
| slotsToSerialize = new ObjectSlot[fields.length]; |
| for (int i = 0; i < fields.length; i++) { |
| ObjectSlot s = new ObjectSlot(); |
| slotsToSerialize[i] = s; |
| s.field = fields[i]; |
| } |
| // We assume the slots are already sorted in the right shape for dumping |
| } |
| |
| /** |
| * Returns {@code true} indicating the field called {@code name} has not had |
| * a value explicitly assigned and that it still holds a default value for |
| * its type, or {@code false} indicating that the field named has been |
| * assigned a value explicitly. |
| * |
| * @param name |
| * the name of the field to test. |
| * @return {@code true} if {@code name} still holds its default value, |
| * {@code false} otherwise |
| * |
| * @throws IllegalArgumentException |
| * if {@code name} is {@code null} |
| */ |
| public boolean defaulted(String name) throws IllegalArgumentException { |
| ObjectSlot slot = findSlot(name, null); |
| if (slot == null) { |
| throw new IllegalArgumentException("no field '" + name + "'"); |
| } |
| return slot.defaulted; |
| } |
| |
| /** |
| * Finds and returns an ObjectSlot that corresponds to a field named {@code |
| * fieldName} and type {@code fieldType}. If the field type {@code |
| * fieldType} corresponds to a primitive type, the field type has to match |
| * exactly or {@code null} is returned. If the field type {@code fieldType} |
| * corresponds to an object type, the field type has to be compatible in |
| * terms of assignment, or null is returned. If {@code fieldType} is {@code |
| * null}, no such compatibility checking is performed and the slot is |
| * returned. |
| * |
| * @param fieldName |
| * the name of the field to find |
| * @param fieldType |
| * the type of the field. This will be used to test |
| * compatibility. If {@code null}, no testing is done, the |
| * corresponding slot is returned. |
| * @return the object slot, or {@code null} if there is no field with that |
| * name, or no compatible field (relative to {@code fieldType}) |
| */ |
| private ObjectSlot findSlot(String fieldName, Class<?> fieldType) { |
| boolean isPrimitive = fieldType != null && fieldType.isPrimitive(); |
| for (int i = 0; i < slotsToSerialize.length; i++) { |
| ObjectSlot slot = slotsToSerialize[i]; |
| if (slot.field.getName().equals(fieldName)) { |
| if (isPrimitive) { |
| // Looking for a primitive type field. Types must match |
| // *exactly* |
| if (slot.field.getType() == fieldType) { |
| return slot; |
| } |
| } else { |
| // Looking for a non-primitive type field. |
| if (fieldType == null) { |
| return slot; // Null means we take anything |
| } |
| // Types must be compatible (assignment) |
| if (slot.field.getType().isAssignableFrom(fieldType)) { |
| return slot; |
| } |
| } |
| } |
| } |
| |
| if (declaredFields != null) { |
| for (int i = 0; i < declaredFields.length; i++) { |
| ObjectStreamField field = declaredFields[i]; |
| if (field.getName().equals(fieldName)) { |
| if (isPrimitive ? fieldType == field.getType() : fieldType == null || |
| field.getType().isAssignableFrom(fieldType)) { |
| ObjectSlot slot = new ObjectSlot(); |
| slot.field = field; |
| slot.defaulted = true; |
| return slot; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private ObjectSlot findMandatorySlot(String name, Class<?> type) { |
| ObjectSlot slot = findSlot(name, type); |
| if (slot == null || (type == null && slot.field.getType().isPrimitive())) { |
| throw new IllegalArgumentException("no field '" + name + "' of type " + type); |
| } |
| return slot; |
| } |
| |
| /** |
| * Finds and returns the byte value of a given field named {@code name} |
| * in the receiver. If the field has not been assigned any value yet, the |
| * default value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public byte get(String name, byte defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, byte.class); |
| return slot.defaulted ? defaultValue : ((Byte) slot.fieldValue).byteValue(); |
| } |
| |
| /** |
| * Finds and returns the char value of a given field named {@code name} in the |
| * receiver. If the field has not been assigned any value yet, the default |
| * value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public char get(String name, char defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, char.class); |
| return slot.defaulted ? defaultValue : ((Character) slot.fieldValue).charValue(); |
| } |
| |
| /** |
| * Finds and returns the double value of a given field named {@code name} |
| * in the receiver. If the field has not been assigned any value yet, the |
| * default value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public double get(String name, double defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, double.class); |
| return slot.defaulted ? defaultValue : ((Double) slot.fieldValue).doubleValue(); |
| } |
| |
| /** |
| * Finds and returns the float value of a given field named {@code name} in |
| * the receiver. If the field has not been assigned any value yet, the |
| * default value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public float get(String name, float defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, float.class); |
| return slot.defaulted ? defaultValue : ((Float) slot.fieldValue).floatValue(); |
| } |
| |
| /** |
| * Finds and returns the int value of a given field named {@code name} in the |
| * receiver. If the field has not been assigned any value yet, the default |
| * value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public int get(String name, int defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, int.class); |
| return slot.defaulted ? defaultValue : ((Integer) slot.fieldValue).intValue(); |
| } |
| |
| /** |
| * Finds and returns the long value of a given field named {@code name} in the |
| * receiver. If the field has not been assigned any value yet, the default |
| * value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public long get(String name, long defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, long.class); |
| return slot.defaulted ? defaultValue : ((Long) slot.fieldValue).longValue(); |
| } |
| |
| /** |
| * Finds and returns the Object value of a given field named {@code name} in |
| * the receiver. If the field has not been assigned any value yet, the |
| * default value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public Object get(String name, Object defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, null); |
| return slot.defaulted ? defaultValue : slot.fieldValue; |
| } |
| |
| /** |
| * Finds and returns the short value of a given field named {@code name} in |
| * the receiver. If the field has not been assigned any value yet, the |
| * default value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public short get(String name, short defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, short.class); |
| return slot.defaulted ? defaultValue : ((Short) slot.fieldValue).shortValue(); |
| } |
| |
| /** |
| * Finds and returns the boolean value of a given field named {@code name} in |
| * the receiver. If the field has not been assigned any value yet, the |
| * default value {@code defaultValue} is returned instead. |
| * |
| * @param name |
| * the name of the field to find. |
| * @param defaultValue |
| * return value in case the field has not been assigned to yet. |
| * @return the value of the given field if it has been assigned, the default |
| * value otherwise. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public boolean get(String name, boolean defaultValue) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, boolean.class); |
| return slot.defaulted ? defaultValue : ((Boolean) slot.fieldValue).booleanValue(); |
| } |
| |
| /** |
| * Find and set the byte value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, byte value) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, byte.class); |
| slot.fieldValue = Byte.valueOf(value); |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Find and set the char value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, char value) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, char.class); |
| slot.fieldValue = Character.valueOf(value); |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Find and set the double value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, double value) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, double.class); |
| slot.fieldValue = Double.valueOf(value); |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Find and set the float value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, float value) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, float.class); |
| slot.fieldValue = Float.valueOf(value); |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Find and set the int value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, int value) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, int.class); |
| slot.fieldValue = Integer.valueOf(value); |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Find and set the long value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, long value) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, long.class); |
| slot.fieldValue = Long.valueOf(value); |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Find and set the Object value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, Object value) throws IllegalArgumentException { |
| Class<?> valueClass = null; |
| if (value != null) { |
| valueClass = value.getClass(); |
| } |
| ObjectSlot slot = findMandatorySlot(name, valueClass); |
| slot.fieldValue = value; |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Find and set the short value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, short value) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, short.class); |
| slot.fieldValue = Short.valueOf(value); |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Find and set the boolean value of a given field named {@code name} in the |
| * receiver. |
| * |
| * @param name |
| * the name of the field to set. |
| * @param value |
| * new value for the field. |
| * |
| * @throws IllegalArgumentException |
| * if the corresponding field can not be found. |
| */ |
| public void put(String name, boolean value) throws IllegalArgumentException { |
| ObjectSlot slot = findMandatorySlot(name, boolean.class); |
| slot.fieldValue = Boolean.valueOf(value); |
| slot.defaulted = false; // No longer default value |
| } |
| |
| /** |
| * Return the array of ObjectSlot the receiver represents. |
| * |
| * @return array of ObjectSlot the receiver represents. |
| */ |
| public ObjectSlot[] slots() { |
| return slotsToSerialize; |
| } |
| } |