diff options
Diffstat (limited to 'luni/src/main/java/java/io/ObjectStreamField.java')
-rw-r--r-- | luni/src/main/java/java/io/ObjectStreamField.java | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/luni/src/main/java/java/io/ObjectStreamField.java b/luni/src/main/java/java/io/ObjectStreamField.java new file mode 100644 index 0000000..95deb7b --- /dev/null +++ b/luni/src/main/java/java/io/ObjectStreamField.java @@ -0,0 +1,410 @@ +/* + * 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; + +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.Comparator; + +/** + * Describes a field for the purpose of serialization. Classes can define the + * collection of fields that are serialized, which may be different from the set + * of all declared fields. + * + * @see ObjectOutputStream#writeFields() + * @see ObjectInputStream#readFields() + * + * @since Android 1.0 + */ +public class ObjectStreamField implements Comparable<Object> { + + // Declared name of the field + private String name; + + // Declared type of the field + private Object type; + + // offset of this field in the object + int offset; + + // Cached version of intern'ed type String + private String typeString; + + private boolean unshared; + + private boolean isDeserialized; + + /** + * Constructs an ObjectStreamField with the specified name and type. + * + * @param name + * the name of the field. + * @param cl + * the type of the field. + * @throws NullPointerException + * if {@code name} or {@code cl} is {@code null}. + * @since Android 1.0 + */ + public ObjectStreamField(String name, Class<?> cl) { + if (name == null || cl == null) { + throw new NullPointerException(); + } + this.name = name; + this.type = new WeakReference<Class<?>>(cl); + } + + /** + * Constructs an ObjectStreamField with the specified name, type and the + * indication if it is unshared. + * + * @param name + * the name of the field. + * @param cl + * the type of the field. + * @param unshared + * {@code true} if the field is written and read unshared; + * {@code false} otherwise. + * @throws NullPointerException + * if {@code name} or {@code cl} is {@code null}. + * @see ObjectOutputStream#writeUnshared(Object) + * @since Android 1.0 + */ + public ObjectStreamField(String name, Class<?> cl, boolean unshared) { + if (name == null || cl == null) { + throw new NullPointerException(); + } + this.name = name; + this.type = (cl.getClassLoader() == null) ? cl + : new WeakReference<Class<?>>(cl); + this.unshared = unshared; + } + + /** + * Constructs an ObjectStreamField with the given name and the given type. + * The type may be null. + * + * @param signature + * A String representing the type of the field + * @param name + * a String, the name of the field, or null + */ + ObjectStreamField(String signature, String name) { + if (name == null) { + throw new NullPointerException(); + } + this.name = name; + this.typeString = signature.replace('.', '/').intern(); + this.isDeserialized = true; + } + + /** + * Compares this field descriptor to the specified one. Checks first if one + * of the compared fields has a primitive type and the other one not. If so, + * the field with the primitive type is considered to be "smaller". If both + * fields are equal, their names are compared. + * + * @param o + * the object to compare with. + * @return -1 if this field is "smaller" than field {@code o}, 0 if both + * fields are equal; 1 if this field is "greater" than field {@code + * o}. + * @since Android 1.0 + */ + public int compareTo(Object o) { + ObjectStreamField f = (ObjectStreamField) o; + boolean thisPrimitive = this.isPrimitive(); + boolean fPrimitive = f.isPrimitive(); + + // If one is primitive and the other isn't, we have enough info to + // compare + if (thisPrimitive != fPrimitive) { + return thisPrimitive ? -1 : 1; + } + + // Either both primitives or both not primitives. Compare based on name. + return this.getName().compareTo(f.getName()); + } + + // BEGIN android-removed + // There shouldn't be an implementation of these methods. + // /** + // * Indicates if this field descriptor is equal to {@code arg0}. Field + // * descriptors are equal if their name is equal. + // * + // * @param arg0 + // * the object to check equality with. + // * @return {@code true} if the name of this field descriptor is equal to the + // * name of {@code arg0}, {@code false} otherwise. + // * @since Android 1.0 + // */ + // @Override + // public boolean equals(Object arg0) { + // // BEGIN android-changed + // // copied from newer harmony version + // return (arg0 instanceof ObjectStreamField) && compareTo(arg0) == 0; + // // END android-changed + // } + // + // /** + // * Returns a hash code for this field descriptor. The hash code of this + // * field's name is returned. + // * + // * @return the field's hash code. + // * @since Android 1.0 + // */ + // @Override + // public int hashCode() { + // return getName().hashCode(); + // } + // END android-removed + + /** + * Gets the name of this field. + * + * @return the field's name. + * @since Android 1.0 + */ + public String getName() { + return name; + } + + /** + * Gets the offset of this field in the object. + * + * @return this field's offset. + * @since Android 1.0 + */ + public int getOffset() { + return offset; + } + + /** + * Return the type of the field the receiver represents, this is an internal + * method + * + * @return A Class object representing the type of the field + */ + // BEGIN android-note + // Changed from private to default visibility for usage in ObjectStreamClass + // END android-note + /* package */ Class<?> getTypeInternal() { + if (type instanceof WeakReference) { + return (Class<?>) ((WeakReference<?>) type).get(); + } + return (Class<?>) type; + } + + /** + * Gets the type of this field. + * + * @return a {@code Class} object representing the type of the field. + * @since Android 1.0 + */ + public Class<?> getType() { + Class<?> cl = getTypeInternal(); + if (isDeserialized && !cl.isPrimitive()) { + return Object.class; + } + return cl; + } + + /** + * Gets a character code for the type of this field. The following codes are + * used: + * + * <pre> + * B byte + * C char + * D double + * F float + * I int + * J long + * L class or interface + * S short + * Z boolean + * [ array + * </pre> + * + * @return the field's type code. + * @since Android 1.0 + */ + public char getTypeCode() { + Class<?> t = getTypeInternal(); + if (t == Integer.TYPE) { + return 'I'; + } + if (t == Byte.TYPE) { + return 'B'; + } + if (t == Character.TYPE) { + return 'C'; + } + if (t == Short.TYPE) { + return 'S'; + } + if (t == Boolean.TYPE) { + return 'Z'; + } + if (t == Long.TYPE) { + return 'J'; + } + if (t == Float.TYPE) { + return 'F'; + } + if (t == Double.TYPE) { + return 'D'; + } + if (t.isArray()) { + return '['; + } + return 'L'; + } + + /** + * Gets the type signature used by the VM to represent the type of this + * field. + * + * @return the signature of this field's class or {@code null} if this + * field's type is primitive. + * @since Android 1.0 + */ + public String getTypeString() { + if (isPrimitive()) { + return null; + } + if (typeString == null) { + Class<?> t = getTypeInternal(); + String typeName = t.getName().replace('.', '/'); + String str = (t.isArray()) ? typeName : ("L" + typeName + ';'); //$NON-NLS-1$ + typeString = str.intern(); + } + return typeString; + } + + /** + * Indicates whether this field's type is a primitive type. + * + * @return {@code true} if this field's type is primitive; {@code false} if + * the type of this field is a regular class. + * @since Android 1.0 + */ + public boolean isPrimitive() { + Class<?> t = getTypeInternal(); + return t != null && t.isPrimitive(); + } + + /** + * Sets this field's offset in the object. + * + * @param newValue + * the field's new offset. + * @since Android 1.0 + */ + protected void setOffset(int newValue) { + this.offset = newValue; + } + + /** + * Returns a string containing a concise, human-readable description of this + * field descriptor. + * + * @return a printable representation of this descriptor. + * @since Android 1.0 + */ + @Override + public String toString() { + return this.getClass().getName() + '(' + getName() + ':' + + getTypeInternal() + ')'; + } + + /** + * Sorts the fields for dumping. Primitive types come first, then regular + * types. + * + * @param fields + * ObjectStreamField[] fields to be sorted + */ + static void sortFields(ObjectStreamField[] fields) { + // Sort if necessary + if (fields.length > 1) { + Comparator<ObjectStreamField> fieldDescComparator = new Comparator<ObjectStreamField>() { + public int compare(ObjectStreamField f1, ObjectStreamField f2) { + return f1.compareTo(f2); + } + }; + Arrays.sort(fields, fieldDescComparator); + } + } + + void resolve(ClassLoader loader) { + if (typeString.length() == 1) { + switch (typeString.charAt(0)) { + case 'I': + type = Integer.TYPE; + return; + case 'B': + type = Byte.TYPE; + return; + case 'C': + type = Character.TYPE; + return; + case 'S': + type = Short.TYPE; + return; + case 'Z': + type = Boolean.TYPE; + return; + case 'J': + type = Long.TYPE; + return; + case 'F': + type = Float.TYPE; + return; + case 'D': + type = Double.TYPE; + return; + } + } + String className = typeString.replace('/', '.'); + if (className.charAt(0) == 'L') { + // remove L and ; + className = className.substring(1, className.length() - 1); + } + try { + Class<?> cl = Class.forName(className, false, loader); + type = (cl.getClassLoader() == null) ? cl + : new WeakReference<Class<?>>(cl); + } catch (ClassNotFoundException e) { + // Ignored + } + } + + /** + * Indicats whether this field is unshared. + * + * @return {@code true} if this field is unshared, {@code false} otherwise. + * @since Android 1.0 + */ + public boolean isUnshared() { + return unshared; + } + + void setUnshared(boolean unshared) { + this.unshared = unshared; + } +} |