
org.glassfish.pfl.dynamic.copyobject.impl.Notes2.txt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pfl-dynamic Show documentation
Show all versions of pfl-dynamic Show documentation
Functionality that may include class generation
#
# 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
#
Note on improving the reflective copy object architecture.
Basic abstractions:
/** Creates an instance of an ObjectCopier to be used for a single session.
*/
ObjectCopierFactory {
ObjectCopier make() ;
}
/** Used to copy objects in a single session: multiple calls to the
* same ObjectCopier instance will share all aliases.
ObjectCopier {
Object copy( Object obj ) throws ReflectiveCopyException ;
}
------------------------
New Reflective case:
/** Used to copy an Object of a particular type. Preserves aliasing through
* oldToNew.
*/
interface ClassCopier {
Object copy( IdentityHashMap oldToNew, Object source ) throws ReflectiveCopyException ;
}
/** Create a ClassCopier for a particular type.
*/
ClassCopierFactory {
ClassCopier get( Class cls ) throws ReflectiveCopyException ;
}
Use filter pattern: use a chain of ClassCopierFactory instances, take first non-null result.
Special ClassCopier instances:
DefaultClassCopiers
ClassCopier makeMapCopier( ClassCopierFactory ccf )
ClassCopier getIdentityCopier()
ClassCopier getErrorCopier()
ClassCopierFactory instances:
- A client may create a special ClassCopierFactory with arbitrary behavior.
- An ArrayClassCopierFactory that returns a ClassCopier for an array, and
null for non-array
- A OrdinaryClassCopierFactory that returns a ClassCopier for any Class,
and throws ReflectiveCopyException if it cannot create a ClassCopier.
- An ImmutableClassCopierFactory that returns an IdentityClassCopier if
the class is immutable (also has registration API).
- A CachingClassCopierFactory that maintains a cache of know ClassCopier
instances for particular classes (also has a registration API).
- PipelineCopierFactory:
- Does Caching -> Special (if present) -> Array -> Ordinary
- Updates cache if needed
- Provides API for:
- registration of know ClassCopier instances
- registration of immutable classes (go straight to cache)
- registration of optional special ClassCopierFactory
- passes itself to Array and Ordinary ClassCopierFactory instances
DefaultClassCopierFactories:
ClassCopierFactory makeCachingClassCopierFactory()
ClassCopierFactory makeArrayClassCopierFactory( ClassCopierFactory )
ClassCopierFactory makeOrdinaryClassCopierFactory( ClassCopierFactory )
The "Ordinary" ClassCopier
The basic idea of the ordinary ClassCopier is to create a new instance according
to the serialization rules, then somehow copy all of the non-static fields from
the old object to the new one. The field copying is done through an instance
of the ClassFieldCopier interface.
There are two approaches to copying the fields: reflection and unsafe.
The reflection approach works fine on all 1.4.x JVMs. However, it cannot copy
non-static final fields. It may also be slightly slower than the unsafe
version.
The unsafe approach does not work on 1.4.1_03 (it crashes the VM!). But it
can copy non-static final fields, giving it somewhat greater applicability.
The appropriate ClassFieldCopier is chosen dynamically based on the JVM type.
The intent is that the copyObject code will work correctly on any 1.4.x
JDK (at least if we know from testing which ones have problems).
It is also cached to avoid recalculation. But this needs some further explanation.
Another interesting problem here is the interaction between copying using ClassFieldCopier
and the special classes that are pre-populated in the cache (the ClassCopier cache in this
case). The problem here is that these ClassCopiers only work (generally) if they
construct the result. In the case of a class A (say CustomHashMap) derived from B
(say HashMap), A is not in the cache, so we just use the Ordinary
copier, and analyze the CustomHashMap class in order to create a ClassFieldCopier.
The analysis will then look for a copier for B. However, this must result in using
a ClassFieldCopier (which is NOT a ClassCopier, because it does not create the result,
which in this case has already been created). Since B is copied specially, this is at
best inconsistent. So, we must not reflectively copy class B in this situation.
We also need to keep in mind that some classes simply cannot be copied by reflection
(e.g. IdentityHashMap). The only way to recognize such classes is that they define
both readObject and writeObject. But many classes that can be reflectively copied also
define both readObject and writeObject (such as ArrayList). So, we will define two
additional mechanisms:
1. An exclude list that defines custom marshalled classes that can be reflectively copied.
2. Special ClassCopiers for some special classes. This is achieved simply by
initializing the cache with the special copiers.
This leads to different choices depending on whether the JDK supports the unsafe
ClassFieldCopier or not:
1. JDK supports unsafe: here we can just avoid registering special handlers for things
like HashMap and Hashtable, as they can be copied just fine (non-static finals, non-
serializable classes are copied). However, the special copiers MAY (unknown at present)
be faster in the common cases. In any case, this choice gives broader coverage, and
can correctly handle Properties.
2. JDK does not support unsafe (meaning the VM crashes with the ClassFieldCopier code):
Here we must register special copiers in any case.
© 2015 - 2025 Weber Informatics LLC | Privacy Policy