001: /*
002: * Copyright (C) 2004, 2005 Joe Walnes.
003: * Copyright (C) 2006, 2007, 2008 XStream Committers.
004: * All rights reserved.
005: *
006: * The software in this package is published under the terms of the BSD
007: * style license a copy of which has been included with this distribution in
008: * the LICENSE.txt file.
009: *
010: * Created on 07. March 2004 by Joe Walnes
011: */
012: package com.thoughtworks.xstream.converters.reflection;
013:
014: import sun.misc.Unsafe;
015: import sun.reflect.ReflectionFactory;
016:
017: import java.lang.ref.WeakReference;
018: import java.lang.reflect.Constructor;
019: import java.lang.reflect.Field;
020: import java.lang.reflect.InvocationTargetException;
021: import java.util.Collections;
022: import java.util.Map;
023: import java.util.WeakHashMap;
024:
025: /**
026: * Instantiates a new object on the Sun JVM by bypassing the constructor (meaning code in the constructor
027: * will never be executed and parameters do not have to be known). This is the same method used by the internals of
028: * standard Java serialization, but relies on internal Sun code that may not be present on all JVMs.
029: *
030: * @author Joe Walnes
031: * @author Brian Slesinsky
032: */
033: public class Sun14ReflectionProvider extends PureJavaReflectionProvider {
034:
035: private final static Unsafe unsafe;
036: private final static Exception exception;
037: static {
038: Unsafe u = null;
039: Exception ex = null;
040: try {
041: Class objectStreamClass = Class.forName("sun.misc.Unsafe");
042: Field unsafeField = objectStreamClass
043: .getDeclaredField("theUnsafe");
044: unsafeField.setAccessible(true);
045: u = (Unsafe) unsafeField.get(null);
046: } catch (ClassNotFoundException e) {
047: ex = e;
048: } catch (SecurityException e) {
049: ex = e;
050: } catch (NoSuchFieldException e) {
051: ex = e;
052: } catch (IllegalArgumentException e) {
053: ex = e;
054: } catch (IllegalAccessException e) {
055: ex = e;
056: }
057: exception = ex;
058: unsafe = u;
059: }
060:
061: private transient ReflectionFactory reflectionFactory = ReflectionFactory
062: .getReflectionFactory();
063: private transient Map constructorCache = Collections
064: .synchronizedMap(new WeakHashMap());
065:
066: public Sun14ReflectionProvider() {
067: super ();
068: }
069:
070: public Sun14ReflectionProvider(FieldDictionary dic) {
071: super (dic);
072: }
073:
074: public Object newInstance(Class type) {
075: try {
076: Constructor customConstructor = getMungedConstructor(type);
077: return customConstructor.newInstance(new Object[0]);
078: } catch (NoSuchMethodException e) {
079: throw new ObjectAccessException("Cannot construct "
080: + type.getName(), e);
081: } catch (SecurityException e) {
082: throw new ObjectAccessException("Cannot construct "
083: + type.getName(), e);
084: } catch (InstantiationException e) {
085: throw new ObjectAccessException("Cannot construct "
086: + type.getName(), e);
087: } catch (IllegalAccessException e) {
088: throw new ObjectAccessException("Cannot construct "
089: + type.getName(), e);
090: } catch (IllegalArgumentException e) {
091: throw new ObjectAccessException("Cannot construct "
092: + type.getName(), e);
093: } catch (InvocationTargetException e) {
094: throw new ObjectAccessException("Cannot construct "
095: + type.getName(), e);
096: }
097: }
098:
099: private Constructor getMungedConstructor(Class type)
100: throws NoSuchMethodException {
101: WeakReference ref = (WeakReference) constructorCache.get(type);
102: if (ref == null || ref.get() == null) {
103: Constructor javaLangObjectConstructor = Object.class
104: .getDeclaredConstructor(new Class[0]);
105: ref = new WeakReference(reflectionFactory
106: .newConstructorForSerialization(type,
107: javaLangObjectConstructor));
108: constructorCache.put(type, ref);
109: }
110: return (Constructor) ref.get();
111: }
112:
113: public void writeField(Object object, String fieldName,
114: Object value, Class definedIn) {
115: write(fieldDictionary.field(object.getClass(), fieldName,
116: definedIn), object, value);
117: }
118:
119: private void write(Field field, Object object, Object value) {
120: if (exception != null) {
121: throw new ObjectAccessException("Could not set field "
122: + object.getClass() + "." + field.getName(),
123: exception);
124: }
125: try {
126: long offset = unsafe.objectFieldOffset(field);
127: Class type = field.getType();
128: if (type.isPrimitive()) {
129: if (type.equals(Integer.TYPE)) {
130: unsafe.putInt(object, offset, ((Integer) value)
131: .intValue());
132: } else if (type.equals(Long.TYPE)) {
133: unsafe.putLong(object, offset, ((Long) value)
134: .longValue());
135: } else if (type.equals(Short.TYPE)) {
136: unsafe.putShort(object, offset, ((Short) value)
137: .shortValue());
138: } else if (type.equals(Character.TYPE)) {
139: unsafe.putChar(object, offset, ((Character) value)
140: .charValue());
141: } else if (type.equals(Byte.TYPE)) {
142: unsafe.putByte(object, offset, ((Byte) value)
143: .byteValue());
144: } else if (type.equals(Float.TYPE)) {
145: unsafe.putFloat(object, offset, ((Float) value)
146: .floatValue());
147: } else if (type.equals(Double.TYPE)) {
148: unsafe.putDouble(object, offset, ((Double) value)
149: .doubleValue());
150: } else if (type.equals(Boolean.TYPE)) {
151: unsafe.putBoolean(object, offset, ((Boolean) value)
152: .booleanValue());
153: } else {
154: throw new ObjectAccessException(
155: "Could not set field " + object.getClass()
156: + "." + field.getName()
157: + ": Unknown type " + type);
158: }
159: } else {
160: unsafe.putObject(object, offset, value);
161: }
162:
163: } catch (IllegalArgumentException e) {
164: throw new ObjectAccessException("Could not set field "
165: + object.getClass() + "." + field.getName(), e);
166: }
167: }
168:
169: protected void validateFieldAccess(Field field) {
170: // (overriden) don't mind final fields.
171: }
172:
173: protected Object readResolve() {
174: super .readResolve();
175: constructorCache = Collections
176: .synchronizedMap(new WeakHashMap());
177: reflectionFactory = ReflectionFactory.getReflectionFactory();
178: return this;
179: }
180: }
|