I'm not going to say too much, this does the trick... no grantees...
/**
* An object that archives files and folders.
*
* @author TacB0sS
*/
public class Archiver {
/**
* The file to save the archive to.
*/
private File archiveFile;
/**
* The archive manifest.
*/
private Manifest manifest;
/**
* The collection of files and folders to archive.
*/
private Vector<File> files = new Vector<File>();
/**
* Inner management file to represent the common parent file of the file collection to archive.
*/
private File parentFile;
/**
* Adds a file to the files list for archiving.
*
* @param file The file to add.
*/
public void addFile(File file) {
if (parentFile != null)
if (!file.getParentFile().equals(parentFile))
throw new IllegalArgumentException("Multiple files with multiple parents is not allowed!");
files.add(file);
if (files.size() == 1)
parentFile = file.getParentFile();
}
/**
* @param files An array of files to add to the archive.
*/
public void addFiles(File[] files) {
for (File file : files)
addFile(file);
}
/**
* Performs the archiving process.
*
* @return The file object with the specified file path.
* @throws IOException If an IOException has occurred while archiving
*/
public File archiveToFile()
throws IOException {
archiveFile.createNewFile();
JarOutputStream jos;
if (manifest == null)
jos = new JarOutputStream(new FileOutputStream(archiveFile));
else
jos = new JarOutputStream(new FileOutputStream(archiveFile), manifest);
writeFilesIntoArchive(files.toArray(new File[files.size()]), jos);
jos.finish();
jos.close();
return archiveFile;
}
public File getFilePath() {
return archiveFile;
}
public Manifest getManifest() {
return manifest;
}
/**
* Removes a file from the files list for archiving.
*
* @param file The file to remove.
*/
public void removeFile(File file) {
files.remove(file);
if (files.size() == 0)
parentFile = null;
}
/**
* @param files An array of files to remove from the archive.
*/
public void removeFiles(File[] files) {
for (File file : files)
removeFile(file);
}
/**
* The file path to save the archive to.
*
* @param archiveFile The file to save the archive to.
*/
public void setArchiveFile(File archiveFile) {
this.archiveFile = archiveFile;
}
/**
* If there is a need for manifest, set it up.
*
* @param manifest The archive manifest.
*/
public void setManifest(Manifest manifest) {
this.manifest = manifest;
}
private void writeFilesIntoArchive(File[] files, JarOutputStream jos)
throws IOException {
for (File file : files) {
if (file.isDirectory()) {
writeFilesIntoArchive(file.listFiles(), jos);
continue;
}
writeIntoJar(file, jos);
}
}
private void writeIntoJar(File toArchive, JarOutputStream jos)
throws IOException {
byte[] buf = new byte[1024];
String relativePath = toArchive.getAbsolutePath().replace(parentFile.getAbsolutePath(), "").replace(File.separator, "/");
relativePath = relativePath.substring(1);
jos.putNextEntry(new JarEntry(relativePath));
FileInputStream fis = new FileInputStream(toArchive);
int anz;
while ((anz = fis.read(buf)) != -1)
jos.write(buf, 0, anz);
jos.closeEntry();
}
}
A few of my tips and tricks on software development and architecture, and why to do things as I see them.
Tuesday, November 15, 2011
Instantiating Class via Reflection
These are snippets from an old object I use from time to time, the "InstanceType" is a generic type of the enclosing class, you may replace it with Object or '?' respectively.
First we find the desired constructor:
/**
* Searches for the constructor with the specified parameters in the supplied class object.
*
* @param _class The class which contains the constructor with the specified parameters.
* @param parameterTypes The constructor parameters types.
* @return The constructor instance of the supplied class.
* @throws ConstructorNotFoundException if a constructor with the supplied specifications was not found.
*/
@SuppressWarnings("unchecked")
private Constructor<InstanceType> findAConstructor(Class<InstanceType> _class, Class<?>[] parameterTypes)
throws ConstructorNotFoundException {
Constructor<?>[] constructors = _class.getConstructors();
for (Constructor<?> constructor2 : constructors)
if (compareConstructorParametersTypes(parameterTypes, constructor2.getParameterTypes()))
return (Constructor<InstanceType>) constructor2;
throw new ConstructorNotFoundException("There was no match for Constructor: \n " + _class.getSimpleName() + "("
+ ReflectiveTools.parseParametersType(parameterTypes) + "); \n In the specified class object: " + _class.getName());
}
Later just to invoke it to get the object:
public final InstanceType newInstance(Object... parameters)
throws ClassInstantiationException {
try {
checkParameters(parameters);
return constructor.newInstance(parameters);
} catch (IllegalArgumentException e) {
throw new ClassInstantiationException(this, parameters, e);
} catch (IllegalAccessException e) {
throw new ClassInstantiationException(this, parameters, e);
} catch (InvocationTargetException e) {
throw new ClassInstantiationException(this, parameters, e);
} catch (InstantiationException e) {
throw new ClassInstantiationException(this, parameters, e);
} catch (WrongParameterType e) {
throw new ClassInstantiationException(this, parameters, e);
}
}
Knock yourself out...
First we find the desired constructor:
/**
* Searches for the constructor with the specified parameters in the supplied class object.
*
* @param _class The class which contains the constructor with the specified parameters.
* @param parameterTypes The constructor parameters types.
* @return The constructor instance of the supplied class.
* @throws ConstructorNotFoundException if a constructor with the supplied specifications was not found.
*/
@SuppressWarnings("unchecked")
private Constructor<InstanceType> findAConstructor(Class<InstanceType> _class, Class<?>[] parameterTypes)
throws ConstructorNotFoundException {
Constructor<?>[] constructors = _class.getConstructors();
for (Constructor<?> constructor2 : constructors)
if (compareConstructorParametersTypes(parameterTypes, constructor2.getParameterTypes()))
return (Constructor<InstanceType>) constructor2;
throw new ConstructorNotFoundException("There was no match for Constructor: \n " + _class.getSimpleName() + "("
+ ReflectiveTools.parseParametersType(parameterTypes) + "); \n In the specified class object: " + _class.getName());
}
Later just to invoke it to get the object:
public final InstanceType newInstance(Object... parameters)
throws ClassInstantiationException {
try {
checkParameters(parameters);
return constructor.newInstance(parameters);
} catch (IllegalArgumentException e) {
throw new ClassInstantiationException(this, parameters, e);
} catch (IllegalAccessException e) {
throw new ClassInstantiationException(this, parameters, e);
} catch (InvocationTargetException e) {
throw new ClassInstantiationException(this, parameters, e);
} catch (InstantiationException e) {
throw new ClassInstantiationException(this, parameters, e);
} catch (WrongParameterType e) {
throw new ClassInstantiationException(this, parameters, e);
}
}
Knock yourself out...
Invoking Method via Reflection
These are snippets from an old object I use from time to time, the "InstanceType" is a generic type of the enclosing class, you may replace it with Object or '?' respectively
First of all we need to get the method instance:
/**
* Searches for the method with the specified parameters in the supplied class object.
*
* @param _class The class which contains the method with the specified parameters.
* @param methodName The method name to search for.
* @param parameterTypes The method parameters types.
* @return The method instance of the supplied class.
* @throws MethodNotFoundException if a method with the supplied specifications was not found.
*/
private Method findAMethod(Class<InstanceType> _class, String methodName, Class<?>... parameterTypes)
throws MethodNotFoundException {
Method[] methods = _class.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (!methods[i].getName().equals(methodName))
continue;
if (compareMethodParametersTypes(parameterTypes, methods[i].getParameterTypes()))
return methods[i];
}
throw new MethodNotFoundException("There was no match for method: \n " + methodName + "("
+ ReflectiveTools.parseParametersType(parameterTypes) + "); \n In the specified class object: " + _class.getName());
}
notifyer.handleException(e);
First of all we need to get the method instance:
/**
* Searches for the method with the specified parameters in the supplied class object.
*
* @param _class The class which contains the method with the specified parameters.
* @param methodName The method name to search for.
* @param parameterTypes The method parameters types.
* @return The method instance of the supplied class.
* @throws MethodNotFoundException if a method with the supplied specifications was not found.
*/
private Method findAMethod(Class<InstanceType> _class, String methodName, Class<?>... parameterTypes)
throws MethodNotFoundException {
Method[] methods = _class.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (!methods[i].getName().equals(methodName))
continue;
if (compareMethodParametersTypes(parameterTypes, methods[i].getParameterTypes()))
return methods[i];
}
throw new MethodNotFoundException("There was no match for method: \n " + methodName + "("
+ ReflectiveTools.parseParametersType(parameterTypes) + "); \n In the specified class object: " + _class.getName());
}
Next we need to invoke the method, with its parameters, which may be called synchronously,or asynchronously:
public final Object invokeMethod(InstanceType instance, Object... parameters)
throws MethodInvocationException {
try {
checkParameters(parameters);
return method.invoke(instance, parameters);
} catch (IllegalArgumentException e) {
throw new MethodInvocationException(method, instance, parameters, e);
} catch (IllegalAccessException e) {
throw new MethodInvocationException(method, instance, parameters, e);
} catch (InvocationTargetException e) {
throw new MethodInvocationException(method, instance, parameters, e);
} catch (WrongParameterType e) {
throw new MethodInvocationException(method, instance, parameters, e);
}
}
public final <ReturnType> void invokeMethodAsynch(final InstanceType instance, final MethodInvocationCompleted<ReturnType> notifyer, final Object... parameters) {
Runnable methodInvocationRun = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
try {
Object returnValue = invokeMethod(instance, parameters);
if (notifyer != null)
notifyer.methodInvocationCompleted((ReturnType) returnValue);
} catch (MethodInvocationException e) {
if (notifyer != null)
}
}
};
Thread t = new Thread(methodInvocationRun, "Invocation of method: " + ReflectiveTools.getMethodAsString(method));
t.start();
}
The Notifier interface should be implemented when called asynchronously:
public interface MethodInvocationCompleted<ReturnType> {
void handleException(MethodInvocationException e);
void methodInvocationCompleted(ReturnType returnValue);
}
Have Fun.
Tuesday, November 8, 2011
Creating an Array from a Generic class type
Well, I didn't figure this out quick enough but it is as simple as:
@SuppressWarnings("unchecked")
protected final <ArrayType> ArrayType[] getArray(Class<ArrayType> arrayType, int size) {
return (ArrayType[]) Array.newInstance(arrayType, size);
}
@SuppressWarnings("unchecked")
protected final <ArrayType> ArrayType[] getArray(Class<ArrayType> arrayType, int size) {
return (ArrayType[]) Array.newInstance(arrayType, size);
}
Ridicules isn't it...?
My architecture for a long time was lacking because I was missing this info, and in combination with this post, it makes Generics the most useful feature while designing an application architecture.
Monday, November 7, 2011
Getting Java generic parameter types in runtime
For the long while I was using Java Generic types, in Methods, Fields and Classes, and I used to transfer the Class type instance as a parameter to the constructor or method respectively. Lately I've learned how Java's Generic types, can be determine in runtime.
To get the generic types of a Class:
To make this work:
To get the generic types of a Class:
abstract class ClassWithGenericParameterType<ItemType> {
private Class<ItemType> itemType;
ClassWithGenericParameterType() {
ParameterizedType classType = (ParameterizedType) getClass().getGenericSuperclass();
Type[] types = classType.getActualTypeArguments();
itemType= (Class<ItemType>) types[0];
}
}
To make this work:
class ExtendingParameterizedGenericClass extends ClassWithGenericParameterType<String> {...}Thing is about this trick, is that the class you are analyzing must be abstract, and that a new Class would extend that abstract class specifying a valid Class as the Generic argument and not something like <ItemType2 extends Number>, this would result in getting Number.class!
Subscribe to:
Posts (Atom)