|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectbcds.tools.DynLoader
public class DynLoader
Loads classes using both qualified and unqualified names and mantains an ordered list of the classes currently loaded.
This class is a wrapper on the default (system) class loader and adds a few services that facilitate dynamically loading classes, namely:
Basic example of usage. In the following (ficticious) example, a class whose name is provided as a string must be loaded. That class must implement an interface called MyInterface<T>. If successful, a new instance must be returned.
MyInterface<T> newObject(String klass) { DynLoader ld = new DynLoader(); MyInterface<T> rv = null; // ld.setNamePrefixes(...); try { Constructor<MyInterface> ctor = ld.getConstructor(klass, null, MyInterface.class); rv = Utils.silentCast(ld.createInstance(ctor)); // (*) //rv.setup(...); } catch (AnyException ex) { // Possibly not necessary (just to personalize the message). if ( ex.getCause() instance of ClassCastException ) { throw new IllegalArgumentException(String.format( "Class %s does not implement MyInterface;" +" it cannot be used for...", klass)); } else { throw new IllegalArgumentException(ex.getMessage()); } } return rv; }If only one instance per class is allowed, the following approach can be used:
try { Constructor<MyInterface> ctor = ld.getConstructor(klass, null, MyInterface.class); rv = Utils.silentCast(ld.getInstance(ctor.getDeclaringClass())); if ( rv == null ) { rv = Utils.silentCast(ld.createInstance(ctor)); ld.register(rv); } ... }A simple cast can be used at the line marked with (*) above, but the compiler might display an "unchecked cast" warning. The function
Utils.silentCast(Object)
just uses annotation to
suppress that warning. The cast is safe because
ld.getConstructor() already checked that
the class implements the required interface.
Constructor Summary | |
---|---|
DynLoader()
Instantiates a new DynLoader with the name
prefix set to the empty string. |
Method Summary | ||
---|---|---|
java.lang.Object |
createInstance(java.lang.reflect.Constructor ctor,
java.lang.Object... args)
Creates a new instance via ctor.newInstance(). |
|
|
getConstructor(java.lang.String className,
java.lang.Class[] ctor_args,
java.lang.Class<T> required_type,
java.lang.Class... other_types)
Load a class and returns a reference to one of its constructors. |
|
|
getInstance(java.lang.Class<? extends T> cls)
Returns a reference to the instance corresponding to class cls ,
or null if cls is not registered. |
|
java.util.List<java.lang.Object> |
getInstances()
Returns the list of classes, in the order in which they have been registered. |
|
java.lang.String |
getNamePrefixes()
Returns the current name prefixes. |
|
java.lang.Object |
load(java.lang.String className)
Loads a class named className , registers it and returns a new
instance of that class. |
|
|
load(java.lang.String className,
java.lang.Class<T> required_type,
java.lang.Class... other_types)
Loads a class named className , makes sure it implements
certain types, creates a new instance and registers it. |
|
void |
register(java.lang.Object instance)
Puts the object instance at the end of the objects list
and registers it as the instance for the
class instance.getClass() . |
|
void |
setNamePrefixes(java.lang.String prefixes)
Sets the name prefixes. |
|
void |
unregister(java.lang.Object instance)
Unregisters the given object and class. |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructor Detail |
---|
public DynLoader()
DynLoader
with the name
prefix set to the empty string.
Method Detail |
---|
public void setNamePrefixes(java.lang.String prefixes)
prefixes
- is a colon-separated list of "package names"
that are tried during loadClass()
. If it is null, an
empty string is used instead.
bcds.phison.sim:org.some.name
The empty prefix is always prepended to prefixes
(unless
it already starts with the character :) so that the first
name that is tried when loading a class is directly its name
without any prefix.public java.lang.String getNamePrefixes()
public <T> T load(java.lang.String className, java.lang.Class<T> required_type, java.lang.Class... other_types)
className
, makes sure it implements
certain types, creates a new instance and registers it.
The class registration is performed by calling
register(Object)
with the newly instantiated object
as parameter. This means that the class is registered for the
concrete class of this object,
not for the class given in required_type
.
Class loading is tried prepending each prefix (including the
emtpy prefix) to className
until one succeeds.
Example of use:
DynLoader ld = new DynLoader(); MyClass b = ld.load("MySuBlass", MyClass.class); MyClass x = ld.load("MyOtherSubClass", MyClass.class, ThisInterface.class, ThatInterface.class);
className
- the name of the class to be loaded, either a simple
name (for example "MyClass"), a partially qualified
name (for example "subpackage.MyClass") or a fully
qualified name.required_type
- the class to be loaded must implement
this interface, or be of that class or one of its
descendants.
That is, required_type
need not
be the specific class of className
;
it simply establishes a "minimum" type requirement.other_types
- just like required_type
; there can be
zero or more additional types. The difference between
these additional types and required_type
is that
the latter helps define the return type.
AnyException
- wrapping an ClassCastException
if the class found does not fulfill all the type requirements.
AnyException
- wrapping other exceptions. See
getConstructor(java.lang.String, java.lang.Class[], java.lang.Class, java.lang.Class...)
and createInstance(java.lang.reflect.Constructor, java.lang.Object...)
.public java.lang.Object load(java.lang.String className)
className
, registers it and returns a new
instance of that class.
This method throws the same exceptions as
load(String, Class, Class...)
,
excluding the wrapped ClassCastException.
See load(String, Class, Class...)
for further details.
public <T> java.lang.reflect.Constructor<T> getConstructor(java.lang.String className, java.lang.Class[] ctor_args, java.lang.Class<T> required_type, java.lang.Class... other_types)
load(String, Class, Class...)
,
without the instatiation and registration steps.
public java.lang.Object createInstance(java.lang.reflect.Constructor ctor, java.lang.Object... args)
public java.util.List<java.lang.Object> getInstances()
public <T> T getInstance(java.lang.Class<? extends T> cls)
cls
,
or null if cls
is not registered.
In principle, it should not be possible to circumvent the
type checking performed by the compiler, so that no type
error should ever result from a call to this method.
Nevertheless, an explicit check is performed to assert that
the object registered for cls
is an instance
of that class.
AnyException
- wrapping a ClassCastException if
the object registered for
class cls
is not an instace of that type.public void register(java.lang.Object instance)
instance
at the end of the objects list
and registers it as the instance for the
class instance.getClass()
.
If a class has already been claimed by another object,
that object is replaced by this one.
java.lang.IllegalArgumentException
- if instance
is null.public void unregister(java.lang.Object instance)
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |