All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.pfl.dynamic.copyobject.impl.ClassCopierOrdinaryImpl Maven / Gradle / Ivy

There is a newer version: 5.0.0
Show newest version
/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.glassfish.pfl.dynamic.copyobject.impl;

import org.glassfish.pfl.basic.reflection.Bridge;
import org.glassfish.pfl.dynamic.copyobject.spi.Copy;
import org.glassfish.pfl.dynamic.copyobject.spi.CopyInterceptor;
import org.glassfish.pfl.dynamic.copyobject.spi.LibraryClassLoader;
import org.glassfish.pfl.dynamic.copyobject.spi.ReflectiveCopyException;

import java.io.Externalizable;
import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.Map;
import java.util.WeakHashMap;

// General Object: use proper constructor, iterate over fields,
// get/set fields using Unsafe or reflection.  This also handles readResolve,
// but I don't think writeReplace is needed.
// XXX Add proper handling for custom marshalled classes.
public class ClassCopierOrdinaryImpl extends ClassCopierBase {

//******************************************************************************
// Static utilities 
//******************************************************************************

    /**
     * Bridge is used to access unsafe methods used to read and write
     * arbitrary data members in objects.
     * This is very fast, and completely ignores access
     * protections including final on fields.
     * NOTE WELL: Unsafe is capable of causing severe damage to the
     * VM, including causing the VM to dump core.  get and put calls
     * must only be made with offsets obtained from objectFieldOffset
     * calls.  Because of the dangerous nature of Unsafe, its use
     * must be carefully protected.
     */
    private static final Bridge BRIDGE_REF = AccessController.doPrivileged(
            new PrivilegedAction() {
                @Override
                public Bridge run() {
                    return Bridge.get();
                }
            }
    );


//******************************************************************************
// Method access utilities
//******************************************************************************

    private Object resolve(Object obj) {
        if (readResolveMethod != null) {
            try {
                return readResolveMethod.invoke(obj);
            } catch (Throwable t) {
                throw Exceptions.self.exceptionInReadResolve(obj, t);
            }
        } else {
            return obj;
        }
    }

//******************************************************************************
// Constructor access class
//******************************************************************************

    /**
     * Class used as a factory for the appropriate Serialization constructors.
     * Note that this cannot be exposed in another class (even package private),
     * because this would provide access to a constructor in some cases that
     * can never be used outside of special serialization or copy support.
     */
    private abstract static class ConstructorFactory {
        private ConstructorFactory() {
        }

        /**
         * Returns public no-arg constructor of given class, or null if none
         * found.  Access checks are disabled on the returned constructor
         * (if any), since the defining class may still be non-public.
         * 

*/ private static Constructor getExternalizableConstructor(Class cl) { return BRIDGE_REF.newConstructorForExternalization(cl); } /** * Returns subclass-accessible no-arg constructor of first * non-serializable superclass, or null if none found. * Access checks are disabled on the * returned constructor (if any). *

*/ private static Constructor getSerializableConstructor(Class clazz) { return BRIDGE_REF.newConstructorForSerialization(clazz); } /** * Returns a constructor based on the first no-args constructor in * the super class chain. This allows us to construct an instance * of any class at all, serializable or not. */ private static Constructor getDefaultConstructor(Class clazz) { Constructor constructor = null; Class cl = clazz; while (cl != null) { try { constructor = cl.getDeclaredConstructor(); break; } catch (NoSuchMethodException ex) { cl = cl.getSuperclass(); } } if (constructor == null) return null; return BRIDGE_REF.newConstructorForSerialization(clazz, constructor); } /** * Analyze the class to determine the correct constructor type. * Returns the appropriate constructor. */ private static Constructor makeConstructor(final Class cls) { return AccessController.doPrivileged( new PrivilegedAction>() { @Override public Constructor run() { Constructor constructor; // We must check for Externalizable first, since Externalizable // extends Serializable. if (Externalizable.class.isAssignableFrom(cls)) { constructor = getExternalizableConstructor(cls); } else if (Serializable.class.isAssignableFrom(cls)) { constructor = getSerializableConstructor(cls); } else { constructor = getDefaultConstructor(cls); } return constructor; } } ); } } //****************************************************************************** // ClassFieldCopiers and all their associated bits //****************************************************************************** // The first implementation of ClassFieldCopiers supported both reflective // and unsafe copiers. However, the ORB now only runs on JDK implementations // that fully support the unsafe approach, so the old reflective code has been // removed. // // Unfortunately, we always need 9 field copier // classes: Object plus the 8 primitive type wrappers. Otherwise every // getObject call would create a new primitive type wrapper, needlessly // creating lots of garbage objects. // // Note that if a super class is copied in some other way, we must not attempt // to build a ClassFieldCopier for the derived class. We should just // throw a ReflectiveCopyException and fallback in that case. public interface ClassFieldCopier { /** * Copy all fields from src to dest, using * oldToNew as usual to preserve aliasing. This copies * all fields declared in the class, as well as in the * super class. */ void copy(Map oldToNew, Object src, Object dest) throws ReflectiveCopyException; } // Utilities for ClassFieldCopier instances. // Maps classes to ClassFieldCopier instances. private static Map, ClassFieldCopier> classToClassFieldCopier = DefaultClassCopierFactories.USE_FAST_CACHE ? new FastCache, ClassFieldCopier>(new WeakHashMap, ClassFieldCopier>()) : new WeakHashMap, ClassFieldCopier>(); private static boolean useCodegenCopier() { return Boolean.getBoolean( "org.glassfish.dynamic.codegen.UseCodegenReflectiveCopyobject"); } private static final Package CODEGEN_SPI = org.glassfish.pfl.dynamic.codegen.spi.Type.class.getPackage(); private static final Package CODEGEN_IMPL = org.glassfish.pfl.dynamic.codegen.impl.Node.class.getPackage(); private static ThreadLocal isCodegenCopierAllowed = new ThreadLocal() { @Override public Boolean initialValue() { return Boolean.TRUE; } }; // ONLY for use in spi.orbutil.codegen.Wrapper! public static void setCodegenCopierAllowed(boolean flag) { isCodegenCopierAllowed.set(flag); } private static synchronized ClassFieldCopier getClassFieldCopier( final Class cls, final PipelineClassCopierFactory classCopierFactory) throws ReflectiveCopyException { ClassFieldCopier copier = classToClassFieldCopier.get(cls); if (copier == null) { try { copier = AccessController.doPrivileged( new PrivilegedExceptionAction() { @Override public ClassFieldCopier run() throws ReflectiveCopyException { // Note that we can NOT generate a copier for // classes used in codegen! If we try, generating // the copier uses codegen which calls the copier, // which generates a copier using codegen, which... // Just don't do this for anything that is in the // codegen packages. if (useCodegenCopier() && isCodegenCopierAllowed.get()) { return makeClassFieldCopierUnsafeCodegenImpl( cls, classCopierFactory); } else { return new ClassFieldCopierUnsafeImpl(cls, classCopierFactory); } } } ); } catch (PrivilegedActionException exc) { throw (ReflectiveCopyException) exc.getException(); } classToClassFieldCopier.put(cls, copier); } return copier; } // Get the superclass ClassFieldCopier, or return null if this is the end of the // chain. private static synchronized ClassFieldCopier getSuperCopier( PipelineClassCopierFactory ccf, Class cls) throws ReflectiveCopyException { Class superClass = cls.getSuperclass(); ClassFieldCopier superCopier = null; if ((superClass != java.lang.Object.class) && (superClass != null)) { ClassCopier cachedCopier = ccf.lookupInCache(superClass); // If there is a cached ClassCopier, and it is not reflective, then cls // should not be copied by reflection. if ((cachedCopier != null) && (!cachedCopier.isReflectiveClassCopier())) { throw Exceptions.self.noClassCopierForSuperclass(superClass); } // Return an error immediately, rather than waiting until the // superClass copier is invoked. if (!ccf.reflectivelyCopyable(superClass)) { throw new ReflectiveCopyException( "Cannot create ClassFieldCopier for superclass " + superClass.getName() + ": This class cannot be copied."); } superCopier = getClassFieldCopier(superClass, ccf); } return superCopier; } //****************************************************************************** //****************************************************************************** /** * Use bridge to copy objects. Now that we are on JDK 5, this has not * been known to fail on any VM (unlike on JDK 1.4.1). Note that the * reflective copier should work now on JDK 5, due to the change in * suppressAccessChecks that supports writing to final fields. * This copier also supports @Copy annotations on fields. */ private static class ClassFieldCopierUnsafeImpl implements ClassFieldCopier { private Class myClass; // Note that fieldOffsets and fieldCopiers must always be the // same length. private long[] fieldOffsets; // The field offsets of all // fields in this class, not // including inherited fields. private UnsafeFieldCopier[] fieldCopiers; // The FieldCopier instances for // this class. // The ClassCopierFactory needed inside objectUnsafeFieldCopier. private PipelineClassCopierFactory classCopierFactory; // ClassFieldCopier for the immediate super class, if any. private ClassFieldCopier superCopier; // Note that most instances of UnsafeFieldCopier are stateless, in that // all needed info is passed in the copy call. This means that // we only need instances of UnsafeFieldCopier for the primitive types // and Object. // Note: accessing to the static bridge is done through compiler synthesized // methods, which is noticeably slow given the number of times bridge is // accessed. I think making bridge public or protected would avoid this, // but we can't expose an instance of Bridge, so we'll only pay for // access to bridge while constructing copiers, instead of while running them. private abstract static class UnsafeFieldCopier { protected Bridge bridge; public UnsafeFieldCopier(Bridge bridge) { this.bridge = bridge; } abstract void copy(Map oldToNew, long offset, Object src, Object dest) throws ReflectiveCopyException; } // All of the XXXInitializer instances simply set the field to 0 or null private static UnsafeFieldCopier byteUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putByte(dest, offset, (byte) 0); } @Override public String toString() { return "byteUnsafeFieldInitializer"; } }; private static UnsafeFieldCopier charUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putChar(dest, offset, (char) 0); } @Override public String toString() { return "charUnsafeFieldInitializer"; } }; private static UnsafeFieldCopier shortUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putShort(dest, offset, (short) 0); } @Override public String toString() { return "shortUnsafeFieldInitializer"; } }; private static UnsafeFieldCopier intUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putInt(dest, offset, 0); } @Override public String toString() { return "intUnsafeFieldInitializer"; } }; private static UnsafeFieldCopier longUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putLong(dest, offset, 0); } @Override public String toString() { return "longUnsafeFieldInitializer"; } }; private static UnsafeFieldCopier booleanUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putBoolean(dest, offset, false); } @Override public String toString() { return "booleanUnsafeFieldInitializer"; } }; private static UnsafeFieldCopier floatUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putFloat(dest, offset, 0); } @Override public String toString() { return "floatUnsafeFieldInitializer"; } }; private static UnsafeFieldCopier doubleUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putDouble(dest, offset, 0); } @Override public String toString() { return "doubleUnsafeFieldInitializer"; } }; private UnsafeFieldCopier getPrimitiveFieldInitializer(Class cls) { if (cls.equals(byte.class)) { return byteUnsafeFieldInitializer; } else if (cls.equals(char.class)) { return charUnsafeFieldInitializer; } else if (cls.equals(short.class)) { return shortUnsafeFieldInitializer; } else if (cls.equals(int.class)) { return intUnsafeFieldInitializer; } else if (cls.equals(long.class)) { return longUnsafeFieldInitializer; } else if (cls.equals(boolean.class)) { return booleanUnsafeFieldInitializer; } else if (cls.equals(float.class)) { return floatUnsafeFieldInitializer; } else if (cls.equals(double.class)) { return doubleUnsafeFieldInitializer; } else { // XXX use Exceptions throw new IllegalArgumentException( "cls must be a primitive type"); } } // The YYYUnsafeFieldCopier instances copy a field from source // to destination private static UnsafeFieldCopier byteUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { byte value = bridge.getByte(src, offset); bridge.putByte(dest, offset, value); } @Override public String toString() { return "byteUnsafeFieldCopier"; } }; private static UnsafeFieldCopier charUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { char value = bridge.getChar(src, offset); bridge.putChar(dest, offset, value); } @Override public String toString() { return "charUnsafeFieldCopier"; } }; private static UnsafeFieldCopier shortUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { short value = bridge.getShort(src, offset); bridge.putShort(dest, offset, value); } @Override public String toString() { return "shortUnsafeFieldCopier"; } }; private static UnsafeFieldCopier intUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { int value = bridge.getInt(src, offset); bridge.putInt(dest, offset, value); } @Override public String toString() { return "intUnsafeFieldCopier"; } }; private static UnsafeFieldCopier longUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { long value = bridge.getLong(src, offset); bridge.putLong(dest, offset, value); } @Override public String toString() { return "longUnsafeFieldCopier"; } }; private static UnsafeFieldCopier booleanUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { boolean value = bridge.getBoolean(src, offset); bridge.putBoolean(dest, offset, value); } @Override public String toString() { return "booleanUnsafeFieldCopier"; } }; private static UnsafeFieldCopier floatUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { float value = bridge.getFloat(src, offset); bridge.putFloat(dest, offset, value); } @Override public String toString() { return "floatUnsafeFieldCopier"; } }; private static UnsafeFieldCopier doubleUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { double value = bridge.getDouble(src, offset); bridge.putDouble(dest, offset, value); } @Override public String toString() { return "doubleUnsafeFieldCopier"; } }; private UnsafeFieldCopier getPrimitiveFieldCopier(Class cls) { if (cls.equals(byte.class)) { return byteUnsafeFieldCopier; } if (cls.equals(char.class)) { return charUnsafeFieldCopier; } if (cls.equals(short.class)) { return shortUnsafeFieldCopier; } if (cls.equals(int.class)) { return intUnsafeFieldCopier; } if (cls.equals(long.class)) { return longUnsafeFieldCopier; } if (cls.equals(boolean.class)) { return booleanUnsafeFieldCopier; } if (cls.equals(float.class)) { return floatUnsafeFieldCopier; } if (cls.equals(double.class)) { return doubleUnsafeFieldCopier; } // XXX use Exceptions throw new IllegalArgumentException("cls must be a primitive type"); } // Various kinds of Object copiers // // The objectUnsafeFieldCopier is not stateless, as it requires access to the // ClassCopierFactory, so it cannot be static. private UnsafeFieldCopier objectUnsafeFieldCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) throws ReflectiveCopyException { Object obj = bridge.getObject(src, offset); Object result = null; if (obj != null) { // This lookup must be based on the actual type, not the // declared type to allow for polymorphism. ClassCopier copier = classCopierFactory.getClassCopier( obj.getClass()); result = copier.copy(oldToNew, obj); } bridge.putObject(dest, offset, result); } @Override public String toString() { return "objectUnsafeFieldCopier"; } }; private static UnsafeFieldCopier objectUnsafeFieldInitializer = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putObject(dest, offset, null); } @Override public String toString() { return "objectUnsafeFieldInitializer"; } }; private static UnsafeFieldCopier objectUnsafeFieldSourceCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putObject(dest, offset, src); } @Override public String toString() { return "objectUnsafeFieldSourceCopier"; } }; private static UnsafeFieldCopier objectUnsafeFieldResultCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { bridge.putObject(dest, offset, src); } @Override public String toString() { return "objectUnsafeFieldResultCopier"; } }; private static UnsafeFieldCopier objectUnsafeFieldIdentityCopier = new UnsafeFieldCopier(BRIDGE_REF) { @Override public void copy(Map oldToNew, long offset, Object src, Object dest) { Object value = bridge.getObject(src, offset); bridge.putObject(dest, offset, value); } @Override public String toString() { return "objectUnsafeFieldIdentityCopier"; } }; private UnsafeFieldCopier getUnsafeFieldCopier(Field fld) { Class defType = fld.getDeclaringClass(); Class fldType = fld.getType(); Copy copyAnnotation = fld.getAnnotation(Copy.class); if (copyAnnotation == null) { if (fldType.isPrimitive()) { return getPrimitiveFieldCopier(fldType); } else { return objectUnsafeFieldCopier; } } else { switch (copyAnnotation.value()) { case RECURSE: if (fldType.isPrimitive()) { return getPrimitiveFieldCopier(fldType); } else { return objectUnsafeFieldCopier; } case IDENTITY: if (fldType.isPrimitive()) { return getPrimitiveFieldCopier(fldType); } else { return objectUnsafeFieldIdentityCopier; } case NULL: if (fldType.isPrimitive()) { return getPrimitiveFieldInitializer(fldType); } else { return objectUnsafeFieldInitializer; } case SOURCE: if (fldType.isAssignableFrom(defType)) { return objectUnsafeFieldSourceCopier; } else { throw new IllegalArgumentException( "Cannot assign field to source object: " + "incompatible types\n" + "Field type is " + fldType + " Class type is " + defType); } case RESULT: if (fldType.isAssignableFrom(defType)) { return objectUnsafeFieldResultCopier; } else { throw new IllegalArgumentException( "Cannot assign field to result object: " + "incompatible types\n" + "Field type is " + fldType + " Class type is " + defType); } default: throw new IllegalArgumentException( "Unhandled case " + copyAnnotation.value() + " for field " + fld); } } } private boolean fieldIsCopyable(Field field) { int modifiers = field.getModifiers(); boolean result = !Modifier.isStatic(modifiers); return result; } public ClassFieldCopierUnsafeImpl(Class cls, PipelineClassCopierFactory ccf) throws ReflectiveCopyException { myClass = cls; classCopierFactory = ccf; superCopier = getSuperCopier(ccf, cls); // Count the number of non-static fields. These are the // ones we must copy. Field[] fields = cls.getDeclaredFields(); int numFields = 0; for (int ctr = 0; ctr < fields.length; ctr++) { if (fieldIsCopyable(fields[ctr])) { numFields++; } } fieldOffsets = new long[numFields]; fieldCopiers = new UnsafeFieldCopier[numFields]; // Initialze offsets and field copiers for non-static // fields. int pos = 0; for (int ctr = 0; ctr < fields.length; ctr++) { Field fld = fields[ctr]; if (fieldIsCopyable(fld)) { fieldOffsets[pos] = BRIDGE_REF.objectFieldOffset(fld); fieldCopiers[pos] = getUnsafeFieldCopier(fld); pos++; } } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("ClassFieldCopierUnsafeImpl["); sb.append(myClass.getName()); for (int ctr = 0; ctr < fieldOffsets.length; ctr++) { sb.append("\n\t"); sb.append(fieldOffsets[ctr]); sb.append(':'); sb.append(fieldCopiers[ctr].toString()); } sb.append("\n]"); return sb.toString(); } @Override public void copy(Map oldToNew, Object source, Object result) throws ReflectiveCopyException { if (superCopier != null) { ((ClassFieldCopierUnsafeImpl) superCopier).copy( oldToNew, source, result); } for (int ctr = 0; ctr < fieldOffsets.length; ctr++) { fieldCopiers[ctr].copy(oldToNew, fieldOffsets[ctr], source, result); } } } //****************************************************************************** //****************************************************************************** private static Map, Constructor> classToConstructor = DefaultClassCopierFactories.USE_FAST_CACHE ? new FastCache, Constructor>( new WeakHashMap, Constructor>()) : new WeakHashMap, Constructor>(); /** * Use bridge with code generated by codegen to copy objects. * This method must be invoked * from inside a doPrivileged call. */ private static synchronized ClassFieldCopier makeClassFieldCopierUnsafeCodegenImpl( final Class cls, final PipelineClassCopierFactory classCopierFactory) throws ReflectiveCopyException { Constructor cons = classToConstructor.get(cls); if (cons == null) { final String className = "org.glassfish.dynamic.codegen.impl.generated.copiers." + cls.getName() + "Copier"; final CodegenCopierGenerator generator = new CodegenCopierGenerator(className, cls); final ProtectionDomain pd = cls.getProtectionDomain(); final Class copierClass = generator.create(pd, LibraryClassLoader.getClassLoader()); try { cons = copierClass.getDeclaredConstructor( PipelineClassCopierFactory.class, ClassFieldCopier.class); } catch (Exception exc) { // XXX use Exceptions throw new ReflectiveCopyException( "Could not access unsafe codegen copier constructor", exc); } classToConstructor.put(cls, cons); } ClassFieldCopier copier = null; try { ClassFieldCopier superCopier = getSuperCopier(classCopierFactory, cls); Object[] args = new Object[]{classCopierFactory, superCopier}; copier = (ClassFieldCopier) cons.newInstance(args); } catch (Exception exc) { // XXX use Exceptions throw new ReflectiveCopyException( "Could not create unsafe codegen copier", exc); } return copier; } //****************************************************************************** // private data of ClassCopierOrdinaryImpl //****************************************************************************** // Actually copies the declared fields in this class. private ClassFieldCopier classFieldCopier; // The appropriate constructor for this class, as defined by Java // serialization, or the default constructor if the class is not serializable. private Constructor constructor; // Null unless the class defines a readResolve() method. private MethodHandle readResolveMethod; //****************************************************************************** // Implementation //****************************************************************************** public ClassCopierOrdinaryImpl(PipelineClassCopierFactory ccf, Class cls) throws ReflectiveCopyException { super(cls.getName(), true); classFieldCopier = getClassFieldCopier(cls, ccf); constructor = ConstructorFactory.makeConstructor(cls); readResolveMethod = BRIDGE_REF.readResolveForSerialization(cls); // XXX handle custom marshalled objects. } @Override public Object createCopy(Object source) throws ReflectiveCopyException { try { return constructor.newInstance(); } catch (Exception exc) { // XXX log this throw new ReflectiveCopyException( "Failure in newInstance for constructor " + constructor, exc); } } // Copy all of the non-static fields from source to dest, starting with // java.lang.Object. @Override public Object doCopy(Map oldToNew, Object source, Object result) throws ReflectiveCopyException { if (source instanceof CopyInterceptor) { // Note that result will also be an instance of CopyInterceptor in this case. ((CopyInterceptor) source).preCopy(); classFieldCopier.copy(oldToNew, source, result); ((CopyInterceptor) result).postCopy(); return resolve(result); } else { classFieldCopier.copy(oldToNew, source, result); return resolve(result); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy