-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Robert Klemme schreef:
The complete architecture is not fully clear to me, but maybe your
framework is too generic.
The only other option that comes to mind at the moment is to try to
clone the object or serialize and deserialize and use whatever succeeds.
Hm, here are some snippets from my generified JCC, they might give you
some ideas. You’ll notice that @SuppressWarnings("unchecked") is
used quite often. It is inevitable. For Javadoc, see the Jakarta website.
public interface Factory<T> {
public T create();
}
public class ConstantFactory<T> implements Factory<T>, Serializable {
/** Returns null each time */
@SuppressWarnings("unchecked")
public static final Factory NULL_INSTANCE = new ConstantFactory(null);
private final T iConstant;
@SuppressWarnings("unchecked")
public static <T> Factory<T> getInstance(T constantToReturn) {
if (constantToReturn == null) {
return NULL_INSTANCE;
}
return new ConstantFactory<T>(constantToReturn);
}
public ConstantFactory(T constantToReturn) {
super();
iConstant = constantToReturn;
}
/**
* Always return constant.
*
* @return the stored constant value
*/
public T create() {
return iConstant;
}
}
public class InstantiateFactory<T> implements Factory<T>, Serializable {
/** The class to create */
private final Class<? extends T> iClassToInstantiate;
/** The constructor parameter types */
private final Class<?>[] iParamTypes;
/** The constructor arguments */
private final Object[] iArgs;
/** The constructor */
private transient Constructor<? extends T> iConstructor = null;
/**
* Factory method that performs validation.
*
* @param classToInstantiate the class to instantiate, not null
* @param paramTypes the constructor parameter types
* @param args the constructor arguments
* @return a new instantiate factory
*/
public static <T> Factory<T> getInstance(Class<T>
classToInstantiate, Class<?>[] paramTypes, Object[] args) {
if (classToInstantiate == null) {
throw new IllegalArgumentException("Class to instantiate
must not be null");
}
if (((paramTypes == null) && (args != null))
|| ((paramTypes != null) && (args == null))
|| ((paramTypes != null) && (args != null) &&
(paramTypes.length != args.length))) {
throw new IllegalArgumentException("Parameter types must
match the arguments");
}
if (paramTypes == null || paramTypes.length == 0) {
return new InstantiateFactory<T>(classToInstantiate);
} else {
paramTypes = paramTypes.clone();
args = args.clone();
return new InstantiateFactory<T>(classToInstantiate,
paramTypes, args);
}
}
/**
* Constructor that performs no validation.
* Use <code>getInstance</code> if you want that.
*
* @param classToInstantiate the class to instantiate
*/
public InstantiateFactory(Class<? extends T> classToInstantiate) {
super();
iClassToInstantiate = classToInstantiate;
iParamTypes = null;
iArgs = null;
findConstructor();
}
/**
* Constructor that performs no validation.
* Use <code>getInstance</code> if you want that.
*
* @param classToInstantiate the class to instantiate
* @param paramTypes the constructor parameter types, not cloned
* @param args the constructor arguments, not cloned
*/
public InstantiateFactory(Class<? extends T> classToInstantiate,
Class<?>[] paramTypes, Object[] args) {
super();
iClassToInstantiate = classToInstantiate;
iParamTypes = paramTypes;
iArgs = args;
findConstructor();
}
/**
* Find the Constructor for the class specified.
*/
private void findConstructor() {
try {
iConstructor = iClassToInstantiate.getConstructor(iParamTypes);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("InstantiateFactory: The
constructor must exist and be public ");
}
}
public T create() {
// needed for post-serialization
if (iConstructor == null) {
findConstructor();
}
try {
return iConstructor.newInstance(iArgs);
} catch (InstantiationException ex) {
throw new FunctorException("InstantiateFactory:
InstantiationException", ex);
} catch (IllegalAccessException ex) {
throw new FunctorException("InstantiateFactory: Constructor
must be public", ex);
} catch (InvocationTargetException ex) {
throw new FunctorException("InstantiateFactory: Constructor
threw an exception", ex);
}
}
}
==> I guess this is probably what you want.
A more complicated approach (I got a lot of problems getting this to
compile, it does in Eclipse):
public class PrototypeFactory {
@SuppressWarnings("unchecked")
public static <T> Factory<T> getInstance(T prototype) {
if (prototype == null) {
return ConstantFactory.getInstance(null);
}
try {
Method method = prototype.getClass().getMethod("clone",
(Class[]) null);
return new PrototypeCloneFactory<T>(prototype, method);
} catch (NoSuchMethodException ex) {
try {
prototype.getClass().getConstructor(new Class[] {
prototype.getClass()});
return new InstantiateFactory<T>(
(Class<T>) prototype.getClass(), // this used to
compile without the cast??
new Class[] { prototype.getClass()},
new Object[] { prototype });
} catch (NoSuchMethodException ex2) {
if (prototype instanceof Serializable) {
return (Factory<T>) new
PrototypeSerializationFactory<Serializable>((Serializable)prototype);
}
}
}
throw new IllegalArgumentException("The prototype must be
cloneable via a public clone method");
}
private PrototypeFactory() {
super();
}
// PrototypeCloneFactory
//-----------------------------------------------------------------------
/**
* PrototypeCloneFactory creates objects by copying a prototype
using the clone method.
*/
static class PrototypeCloneFactory<T> implements Factory<T>,
Serializable {
/** The object to clone each time */
private final Object iPrototype;
/** The method used to clone */
private transient Method iCloneMethod;
private PrototypeCloneFactory(Object prototype, Method method) {
super();
iPrototype = prototype;
iCloneMethod = method;
}
/**
* Find the Clone method for the class specified.
*/
private void findCloneMethod() {
try {
iCloneMethod = iPrototype.getClass().getMethod("clone",
(Class[]) null);
} catch (NoSuchMethodException ex) {
throw new
IllegalArgumentException("PrototypeCloneFactory: The clone method must
exist and be public ");
}
}
@SuppressWarnings("unchecked")
public T create() {
// needed for post-serialization
if (iCloneMethod == null) {
findCloneMethod();
}
try {
return (T) iCloneMethod.invoke(iPrototype, (Object[])null);
} catch (IllegalAccessException ex) {
throw new FunctorException("PrototypeCloneFactory: Clone
method must be public", ex);
} catch (InvocationTargetException ex) {
throw new FunctorException("PrototypeCloneFactory: Clone
method threw an exception", ex);
}
}
}
// PrototypeSerializationFactory
//-----------------------------------------------------------------------
/**
* PrototypeSerializationFactory creates objects by cloning a
prototype using serialization.
*/
static class PrototypeSerializationFactory<T extends Serializable>
implements Factory<T>, Serializable {
/** The object to clone via serialization each time */
private final T iPrototype;
private PrototypeSerializationFactory(T prototype) {
super();
iPrototype = prototype;
}
/**
* Creates an object using serialization.
*
* @return the new object
*/
@SuppressWarnings("unchecked")
public T create() {
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
ByteArrayInputStream bais = null;
try {
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(iPrototype);
bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bais);
return (T) in.readObject();
} catch (ClassNotFoundException ex) {
throw new FunctorException(ex);
} catch (IOException ex) {
throw new FunctorException(ex);
} finally {
try {
if (bais != null) {
bais.close();
}
} catch (IOException ex) {
// ignore
}
try {
if (baos != null) {
baos.close();
}
} catch (IOException ex) {
// ignore
}
}
}
}
}
This illustrates how they are used, e.g. in a List. Similar for
LazySet, LazyMap etc. For Maps, a similar approach is used, but with
Transformers instead of Factories, e.g. they get an input:
public interface Transformer<I,O> {
public O transform(I input);
}
public class LazyList<E> extends AbstractSerializableListDecorator<E> {
protected final Factory<E> factory;
public static <E> List<E> decorate(List<E> list, Factory<E> factory) {
return new LazyList<E>(list, factory);
}
//-----------------------------------------------------------------------
protected LazyList(List<E> list, Factory<E> factory) {
super(list);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = factory;
}
//-----------------------------------------------------------------------
/**
* Decorate the get method to perform the lazy behaviour.
* <p>
* If the requested index is greater than the current size, the list
will
* grow to the new size and a new object will be returned from the
factory.
* Indexes in-between the old size and the requested size are left
with a
* placeholder that is replaced with a factory object when requested.
*
* @param index the index to retrieve
*/
@Override
public E get(int index) {
int size = getList().size();
if (index < size) {
// within bounds, get the object
E object = getList().get(index);
if (object == null) {
// item is a place holder, create new one, set and return
object = factory.create();
getList().set(index, object);
return object;
} else {
// good and ready to go
return object;
}
} else {
// we have to grow the list
for (int i = size; i < index; i++) {
getList().add(null);
}
// create our last object, set and return
E object = factory.create();
getList().add(object);
return object;
}
}
}
I hope you get some inspiration from this.
H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
iD8DBQFGJNu2e+7xMGD3itQRAui3AJ9vkD+V07dvgmQu8Yx/1F0VjEG6WQCfQTL8
Ii7wjQxkSC/pxatgNTmN5H0=
=OkBB
-----END PGP SIGNATURE-----