001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.util;
017:
018: import java.io.IOException;
019: import java.io.ObjectInput;
020: import java.io.ObjectOutput;
021: import java.io.ObjectStreamException;
022: import java.io.Serializable;
023: import java.lang.reflect.Field;
024: import java.lang.reflect.Modifier;
025: import java.security.AccessController;
026: import java.security.PrivilegedAction;
027: import java.util.ArrayList;
028: import java.util.List;
029:
030: public class PojoSerialization implements Serializable {
031: private static final byte CLASS = (byte) 50;
032: private static final byte FIELD = (byte) 51;
033: private static final byte DONE = (byte) 52;
034:
035: private Object object;
036:
037: private static final sun.misc.Unsafe unsafe;
038:
039: static {
040: unsafe = (sun.misc.Unsafe) AccessController
041: .doPrivileged(new PrivilegedAction() {
042: public Object run() {
043: try {
044: Field field = sun.misc.Unsafe.class
045: .getDeclaredField("theUnsafe");
046: field.setAccessible(true);
047: return field.get(null);
048: } catch (Exception e) {
049: throw new IllegalStateException(
050: "Cannot get sun.misc.Unsafe", e);
051: }
052: }
053: });
054: }
055:
056: /**
057: * Constructor for externalization
058: */
059: public PojoSerialization() {
060: }
061:
062: public PojoSerialization(Object object) {
063: this .object = object;
064: }
065:
066: private void writeObject(java.io.ObjectOutputStream out)
067: throws IOException {
068: write(out);
069: }
070:
071: private void readObject(java.io.ObjectInputStream in)
072: throws IOException, ClassNotFoundException {
073: read(in);
074: }
075:
076: protected Object readResolve() throws ObjectStreamException {
077: return object;
078: }
079:
080: protected void read(ObjectInput in) throws IOException,
081: ClassNotFoundException {
082: byte b = in.readByte();
083: if (b != CLASS)
084: throw new IOException("Expected 'CLASS' byte " + CLASS
085: + ", got: " + b);
086:
087: Class clazz = (Class) in.readObject();
088:
089: Object object;
090: try {
091: object = unsafe.allocateInstance(clazz);
092: } catch (Exception e) {
093: throw (IOException) new IOException("Cannot construct "
094: + clazz.getName()).initCause(e);
095: }
096:
097: while (b != DONE) {
098: b = in.readByte();
099: switch (b) {
100: case FIELD: {
101: String fieldName = in.readUTF();
102: Object value = in.readObject();
103: Field field = null;
104: try {
105: field = clazz.getDeclaredField(fieldName);
106: } catch (NoSuchFieldException e) {
107: throw (IOException) new IOException(
108: "Cannot find field " + field.getName())
109: .initCause(e);
110: }
111: setValue(field, object, value);
112: }
113: break;
114: case CLASS: {
115: clazz = (Class) in.readObject();
116: }
117: break;
118: }
119: }
120:
121: this .object = object;
122: }
123:
124: protected void write(ObjectOutput out) throws IOException {
125: List<Class> classes = new ArrayList<Class>();
126: Class c = object.getClass();
127: while (c != null && !c.equals(Object.class)) {
128: classes.add(c);
129: c = c.getSuperclass();
130: }
131:
132: for (Class clazz : classes) {
133: out.writeByte(CLASS);
134: out.writeObject(clazz);
135:
136: Field[] fields = clazz.getDeclaredFields();
137: for (Field field : fields) {
138: if (Modifier.isStatic(field.getModifiers()))
139: continue;
140: if (Modifier.isTransient(field.getModifiers()))
141: continue;
142: field.setAccessible(true);
143: out.writeByte(FIELD);
144: out.writeUTF(field.getName());
145: try {
146: out.writeObject(field.get(object));
147: } catch (IllegalAccessException e) {
148: throw (IOException) new IOException(
149: "Cannot write field " + field.getName())
150: .initCause(e);
151: }
152: }
153: }
154: out.writeByte(DONE);
155: }
156:
157: private void setValue(Field field, Object object, Object value) {
158: long offset;
159: try {
160: offset = unsafe.objectFieldOffset(field);
161: } catch (Exception e) {
162: throw new IllegalStateException(
163: "Failed getting offset for: field="
164: + field.getName() + " class="
165: + field.getDeclaringClass().getName(), e);
166: }
167:
168: Class type = field.getType();
169: if (type.isPrimitive()) {
170: if (type.equals(Integer.TYPE)) {
171: unsafe.putInt(object, offset, ((Integer) value)
172: .intValue());
173: } else if (type.equals(Long.TYPE)) {
174: unsafe.putLong(object, offset, ((Long) value)
175: .longValue());
176: } else if (type.equals(Short.TYPE)) {
177: unsafe.putShort(object, offset, ((Short) value)
178: .shortValue());
179: } else if (type.equals(Character.TYPE)) {
180: unsafe.putChar(object, offset, ((Character) value)
181: .charValue());
182: } else if (type.equals(Byte.TYPE)) {
183: unsafe.putByte(object, offset, ((Byte) value)
184: .byteValue());
185: } else if (type.equals(Float.TYPE)) {
186: unsafe.putFloat(object, offset, ((Float) value)
187: .floatValue());
188: } else if (type.equals(Double.TYPE)) {
189: unsafe.putDouble(object, offset, ((Double) value)
190: .doubleValue());
191: } else if (type.equals(Boolean.TYPE)) {
192: unsafe.putBoolean(object, offset, ((Boolean) value)
193: .booleanValue());
194: } else {
195: throw new IllegalStateException(
196: "Unknown primitive type: " + type.getName());
197: }
198: } else {
199: unsafe.putObject(object, offset, value);
200: }
201: }
202:
203: }
|