/* * 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; } }