Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "EclipseLink/Development/Dynamic/Design DynamicClassCreation"
(→Background) |
|||
Line 7: | Line 7: | ||
* Ability to create dynamic persistent entities using EclipseLink Instantiation policies - during reading, creating, cloning | * Ability to create dynamic persistent entities using EclipseLink Instantiation policies - during reading, creating, cloning | ||
* Ability to retrieve values from and store values into dynamic persistent entities using a custom <code>AttributeAccessor</code> | * Ability to retrieve values from and store values into dynamic persistent entities using a custom <code>AttributeAccessor</code> | ||
− | * Ability to do type conversions to align the value coming from the data store w.r.t the value stored in the | + | * Ability to do type conversions to align the value coming from the data store w.r.t the value stored in the entity. It uses the mapping's attribute classification info for this purpose. |
− | EclipseLink requires only minor 'tweaks' to deal with the above requirements, generally treating dynamic persistent entity classes no differently than a 'regular' class. | + | EclipseLink requires only minor 'tweaks' to deal with the above requirements, generally treating dynamic persistent entity classes no differently than a 'regular' class. |
== Design == | == Design == |
Revision as of 13:13, 17 September 2009
Dynamic Persistence Design: Class Creation
This page describes the design for the creation of dynamic persistent entity classes without having source.
Background
EclipseLink requires a Java class with the following capabilities to be a persistent entity:
- Ability to be uniquely identified by class:
entity.getClass()
must be unique (compared using==
) for a ClassDescriptor in a given Project/Session - Ability to create dynamic persistent entities using EclipseLink Instantiation policies - during reading, creating, cloning
- Ability to retrieve values from and store values into dynamic persistent entities using a custom
AttributeAccessor
- Ability to do type conversions to align the value coming from the data store w.r.t the value stored in the entity. It uses the mapping's attribute classification info for this purpose.
EclipseLink requires only minor 'tweaks' to deal with the above requirements, generally treating dynamic persistent entity classes no differently than a 'regular' class.
Design
In order to create a Java class at runtime without Java source code, the use of a custom ClassLoader is required, along with a bytecode manipulation framework (such as ASM or some other library).
Java classloaders form an instance-hierarchy at run-time, with the system (Bootstrap, Extension and System) class loaders
strictly controlled by the JVM. Once an application is launched (via an Application loader), a new loader MyCustomClassLoader
can
be added to the chain.
The basic implementation pattern is as follows - in the constructor, the new instance of MyCustomClassLoader
is added to the
runtime instance-hierarchy by calling super
with the parent loader.
public class MyCustomClassLoader extends ClassLoader { public MyCustomClassLoader (ClassLoader parent) { super(parent); } @Override protected Class<?> findClass(String className) throws ClassNotFoundException { if (className_is_registered_for_dynamic_generation) { try { byte[] bytes = use_framework_to_generate_bytecode(); return defineClass(className, bytes, 0, bytes.length); } catch (ClassFormatError cfe) { throw new ClassNotFoundException(className, cfe); } } return super.findClass(className); } }
The findClass
method is overridden so that if some condition is met - say for example the className has been previously registered for dynamice generation - the bytecode for the Class className
is generated; otherwise, the call is delegated up the instance-hierarchy to search for the class. The implementation hierarchy is responsible for maintaining a cache of classes, as well as any resources that have been loaded (XML descriptor files, image files, etc). Thus, an instance of MyCustomClassLoader
behaves as a 'proper' class loader in all cases, with the additional capability that non-existent classes can be built/found without their corresponding .class files being on the JVM's classpath.
NB: it is important to note that two separate instances of MyCustomClassLoader
can generate two classes
for className
. Even though the bytecode is identical, the classes are distinct. When running under a Java EE™ container
(or an OSGi environment), the class loader hierarchy may be much more complicated, but the point remains - a custom classloader is
required to build classes at runtime; the custom classloader is part of a chain of loaders and each dynamic class is distinct.
It is thus incumbent upon the designer to ensure that the correct loader is used throughout the lifecycle of the application.