I try to analyze Java source code in Java6. ANTLR4 does great job in lexical analysis indeed but now I wonder if more advanced problems, such as listing inherited methods, can be managed.
My idea (according to some googling):
load source files
get system compiler by ToolProvider.getSystemJavaCompiler() and compile sources via run() into .class files
[maybe?] pack .class files to .jar and load them somehow
use Java reflection to analyze compiled classes
delete .class files
write output (e.g. inherited methods/fields etc.)
Bullets 1, 4, 5 and 6 are clean enough and well described. I belive nr. 2 can be solved using this tutorial. So my core problem is nr. 3 as I can't figure out how to load .class files and analyse them.
Any ideas? Is this even possible? If so, how? Could you recommend me either a tutorial or examples? Is my idea even correct?
I prefer not using third-party libraries as I'd like to understand in depth.
Thanks to all comments and google I finally figured it out - basically I needed an example like this:
/* Usage
--------
$ javac CompileJarLoadReflect.java
$ java CompileJarLoadReflect MyClass YourClass CompileJarLoadReflect
MyClass.java compilation is successful
YourClass.java compilation is successful
CompileJarLoadReflect.java compilation is successful
3 files successfully compiled
Class MyClass
myMethod
Class YourClass
yourMethod
Class CompileJarLoadReflect
main
compile
compile
load
jar
*/
/* Thanks to
------------
http://www.java2s.com/Code/Java/File-Input-Output/CreateJarfile.htm
http://stackoverflow.com/questions/194698/how-to-load-a-jar-file-at-runtime/673414#673414
*/
import javax.tools.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.net.URL;
import java.net.URLClassLoader;
import java.lang.reflect.Method;
/** Simple compilation, packaging and loading example */
public class CompileJarLoadReflect {
/** JAR buffer size*/
public static int BUFFER_SIZE = 10 * 1024;
/** Compile all files given (by their location) */
public void compile(String[] files) throws Exception {
for (String f : files) compile(f + ".java");
System.out.println(files.length + " files successfully compiled");
}
/** Compile one particular file */
protected void compile(String f) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int compilationResult = compiler.run(null, null, null, f);
if (compilationResult == 0) System.out.println(f + " compilation is successful");
else throw new Exception("Compilation error at file " + f);
}
/** Pack tobeJared classes into jarName */
public void jar(String jarName, String[] tobeJared) throws Exception {
File archiveFile = new File(jarName);
byte buffer[] = new byte[BUFFER_SIZE];
FileOutputStream stream = new FileOutputStream(archiveFile);
JarOutputStream out = new JarOutputStream(stream, new Manifest());
for (String name : tobeJared) {
File f = new File(name + ".class");
if (f == null || !f.exists() || f.isDirectory()) throw new Exception("Jar problem at file " + name);
JarEntry jarAdd = new JarEntry(f.getName());
jarAdd.setTime(f.lastModified());
out.putNextEntry(jarAdd);
FileInputStream in = new FileInputStream(f);
while (true) {
int nRead = in.read(buffer, 0, buffer.length);
if (nRead <= 0) break;
out.write(buffer, 0, nRead);
}
in.close();
}
out.close();
stream.close();
}
/** Load jar archive at jarName and then print methods of all classes in clazzes */
public void load(String jarName, String[] clazzes) throws Exception {
File file = new File(jarName);
URL url = file.toURL();
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
for (String c : clazzes) {
System.out.println("Class " + c);
Class cls = cl.loadClass(c);
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) System.out.println("\t" + m.getName());
}
}
/** Try everyting out, use params without .java */
public static void main(String[] args) {
String jarName = "output.jar";
try {
CompileJarLoadReflect cjlr = new CompileJarLoadReflect();
cjlr.compile(args);
cjlr.jar(jarName, args);
cjlr.load(jarName, args);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I hope it helps others.
Related
I need to create an application to get the class variables(attributes) count on a given .java file.So I developed a code using java reflection as below.So in here I create a new .java file with the same content of importing .java file in my src package because then that .java file can be accessible to the reflection purposes.But the problem is IDE is not figuring out the updates of that files automatically,which means even though the file is created already in my directory IDE doesn't figure it out instantly so I need to refresh the src package to notify the updates to the IDE.So how can I solve this issue.Therefor when you run this for first time there will be an exception of class not found exception ,because even though that .java file already there in the src folder IDE doesn't know.
I tried with eclipse, Intelij IDES.
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
importjava.util.concurrent.atomic.AtomicInteger;
public class AppInitializer {
public static void main(String args[])throws Exception{
AtomicInteger atomicInteger = new AtomicInteger();
Runtime.getRuntime().addShutdownHook(new Thread()
{
public void run()
{
try {
meth ();
} catch (ClassNotFoundException e) {
e.printStackTrace ( );
}
}
});
FileReader fr=new FileReader("C:\\Users\\User\\Desktop\\Sample.java");
int i;
StringBuffer str= new StringBuffer("");
while((i=fr.read())!=-1){
str.append ( (char)i );}
String s = String.valueOf ( str );
String replaceString=s.replaceAll ( "public class [^\\n]+", "public class filename{" );
System.out.println (replaceString );
fr.close();
try {
FileWriter myWriter = new FileWriter("src/filename.java");
myWriter.write( String.valueOf ( replaceString ) );
myWriter.close();
System.out.println("Successfully wrote to the file.");
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
}
static void meth() throws ClassNotFoundException {
Class classs= Class.forName ( "filename" );
int count = 0;
for (Field field : classs.getDeclaredFields ()){
count++;
}
System.out.println (count );
}
}
If you just add a new .java file to your program, that doesn't add a new class to it. You have to compile it at runtime in order for the Class.forName(...) method to be able to find it.
For a guide on how to do that, see this tutorial.
This question already has answers here:
How to provide an interface to JavaCompiler when compiling a source file dynamically?
(3 answers)
Closed 5 years ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
(This question is similar to many questions I have seen but most are not specific enough for what I am doing)
Background:
The purpose of my program is to make it easy for people who use my program to make custom "plugins" so to speak, then compile and load them into the program for use (vs having an incomplete, slow parser implemented in my program). My program allows users to input code into a predefined class extending a compiled class packaged with my program. They input the code into text panes then my program copies the code into the methods being overridden. It then saves this as a .java file (nearly) ready for the compiler. The program runs javac (java compiler) with the saved .java file as its input.
My question is, how do I get it so that the client can (using my compiled program) save this java file (which extends my InterfaceExample) anywhere on their computer, have my program compile it (without saying "cannot find symbol: InterfaceExample") then load it and call the doSomething() method?
I keep seeing Q&A's using reflection or ClassLoader and one that almost described how to compile it, but none are detailed enough for me/I do not understand them completely.
Take a look at JavaCompiler
The following is based on the example given in the JavaDocs
This will save a File in the testcompile directory (based on the package name requirements) and the compile the File to a Java class...
package inlinecompiler;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class InlineCompiler {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder(64);
sb.append("package testcompile;\n");
sb.append("public class HelloWorld implements inlinecompiler.InlineCompiler.DoStuff {\n");
sb.append(" public void doStuff() {\n");
sb.append(" System.out.println(\"Hello world\");\n");
sb.append(" }\n");
sb.append("}\n");
File helloWorldJava = new File("testcompile/HelloWorld.java");
if (helloWorldJava.getParentFile().exists() || helloWorldJava.getParentFile().mkdirs()) {
try {
Writer writer = null;
try {
writer = new FileWriter(helloWorldJava);
writer.write(sb.toString());
writer.flush();
} finally {
try {
writer.close();
} catch (Exception e) {
}
}
/** Compilation Requirements *********************************************************************************************/
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
// This sets up the class path that the compiler will use.
// I've added the .jar file that contains the DoStuff interface within in it...
List<String> optionList = new ArrayList<String>();
optionList.add("-classpath");
optionList.add(System.getProperty("java.class.path") + File.pathSeparator + "dist/InlineCompiler.jar");
Iterable<? extends JavaFileObject> compilationUnit
= fileManager.getJavaFileObjectsFromFiles(Arrays.asList(helloWorldJava));
JavaCompiler.CompilationTask task = compiler.getTask(
null,
fileManager,
diagnostics,
optionList,
null,
compilationUnit);
/********************************************************************************************* Compilation Requirements **/
if (task.call()) {
/** Load and execute *************************************************************************************************/
System.out.println("Yipe");
// Create a new custom class loader, pointing to the directory that contains the compiled
// classes, this should point to the top of the package structure!
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()});
// Load the class from the classloader by name....
Class<?> loadedClass = classLoader.loadClass("testcompile.HelloWorld");
// Create a new instance...
Object obj = loadedClass.newInstance();
// Santity check
if (obj instanceof DoStuff) {
// Cast to the DoStuff interface
DoStuff stuffToDo = (DoStuff)obj;
// Run it baby
stuffToDo.doStuff();
}
/************************************************************************************************* Load and execute **/
} else {
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
System.out.format("Error on line %d in %s%n",
diagnostic.getLineNumber(),
diagnostic.getSource().toUri());
}
}
fileManager.close();
} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) {
exp.printStackTrace();
}
}
}
public static interface DoStuff {
public void doStuff();
}
}
Now updated to include suppling a classpath for the compiler and loading and execution of the compiled class!
I suggest using the Java Runtime Compiler library. You can give it a String in memory and it will compile and load the class into the current class loader (or one of your choice) and return the Class loaded. Nested classes are also loaded. Note: this works entirely in memory by default.
e.g.
// dynamically you can call
String className = "mypackage.MyClass";
String javaCode = "package mypackage;\n" +
"public class MyClass implements Runnable {\n" +
" public void run() {\n" +
" System.out.println(\"Hello World\");\n" +
" }\n" +
"}\n";
Class aClass = CompilerUtils.CACHED_COMPILER.loadFromJava(className, javaCode);
Runnable runner = (Runnable) aClass.newInstance();
runner.run();
Hello I am new in Java so I would like some guidelines on how to organize files of a project in java. Currently I am building an app with GUI so I want two files one that relates to the GUI and another file that relates to any functions that are called from the first. Right now I've named the second file Utilities.java and looks like this:
package Directory;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
public class Utilities {
public class FileCopy{
private File Source;
private File Destination;
private long totalBytes=0L;
FileCopy(File source,File destination){
Source=source;
Destination=destination;
retrieveTotalBytes(source);
}
File getSource(){return Source;}
File getDestination(){return Destination;}
Long gettotalBytes(){return totalBytes;}
private void retrieveTotalBytes(File sourceFile)
{
if(sourceFile.isDirectory()==false){
totalBytes = sourceFile.length();
}
else{
File[] files = sourceFile.listFiles();
for(File file : files)
{
if(file.isDirectory()) retrieveTotalBytes(file);
else totalBytes += file.length();
}
}
System.out.print("Done retrieving");
}
}
public class Copy extends SwingWorker<Void,Integer>
{
File src,dest;
InputStream in;
OutputStream out;
JProgressBar progressBar;
JProgressBar all;
JTextArea txt;
public int progress;
//private int all_progress;
private long totalBytes = 0L;
private long copiedBytes = 0L;
boolean keepStructure=false;
boolean delete=false;
public Copy(File source,File dst,JProgressBar br,JTextArea text,boolean keep,boolean delete)
{
src=source;
dest=dst;
progressBar=br;
txt=text;
progressBar.setValue(0);
progressBar.setVisible(true);
txt.setText("Copying " + src.getName());
keepStructure=keep;
this.delete=delete;
}
#Override
public Void doInBackground() throws Exception
{
txt.setText(src.getName());
//retrieveTotalBytes(src);
copyFiles(src, dest);
return null;
}
#Override
public void process(java.util.List<Integer> chunks)
{
for(int i : chunks)
{
progressBar.setValue(i);
}
}
#Override
public void done()
{
setProgress(100);
}
public String GetParent(String input){
short pos=(short) input.lastIndexOf(File.separatorChar);
return input.substring(0, pos);
}
private void copyFiles(File sourceFile, File targetFile) throws IOException
{
if(sourceFile.isDirectory())
{
if(!targetFile.exists()) targetFile.mkdirs();
String[] filePaths = sourceFile.list();
for(String filePath : filePaths)
{
File destFile;
File srcFile = new File(sourceFile, filePath);
if(keepStructure==true)
destFile= new File(targetFile, filePath);
else{
String filepath2=GetParent(dest.toString())+File.separatorChar+srcFile.getName();
destFile=new File(filepath2);
}
System.out.print("\n\n name="+destFile.toString()+"\n");
System.out.print("dest to string =" +GetParent(dest.toString()) + " srcFile.getName()="+srcFile.getName()+"\n" );
copyFiles(srcFile, destFile);
}
}
else
{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile));
long fileBytes = sourceFile.length();
long soFar = 0L;
int theByte;
while((theByte = bis.read()) != -1)
{
bos.write(theByte);
setProgress((int) (copiedBytes++ * 100 / totalBytes));
publish((int) (soFar++ * 100 / fileBytes));
}
bis.close();
bos.close();
if(delete==true)
sourceFile.delete();
publish(100);
txt.setText("Copying " + src.getName() + "complete");
}
}
}
}
Question 1:
Notice that in that file the I have two subclasses {FileCopy,Copy} that are completely different. Is that a good way to organize the code or should a move each class on each own file?
Question 2:
Also, in my main i try to create and object from each class but I do something wrong. I've added the import of the file but when I try to create an object e.g.
Copy worker = new Copy(source,dest,progressBar,textArea, keep_Structure,false);
I receive this error:
No enclosing instance of type Utilities is accessible. Must qualify
the allocation with an enclosing instance of type Utilities (e.g.
x.new A() where x is an instance of Utilities).
In Java you should moslty (at least while you are still learning the basics) keep each class in its own file.
You have 3 (and not 2) classes in your file : Utilities, FileCopy and Copy, with the later two being inner classes of Utilities (the Utilities class does nothing on its own). This is why you can't instanciate Copy without first instantiating Utilities.
I think you should have a package named utilities, containing two files : FileCopy.java and Copy.java each containing their own class. If you want a way to differentiate between parts of your application, this is a good way to start : have a package containing all gui-related classes and another one for the rest of the application.
This should solve your error.
The official tutorials on nested classes : http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
I have a problem with a seemingly simple application.
What it should do:
-Read out the files (*.jpg) of a (hardcoded) directory
-Use the contained Metadata (gotten via implemented Libraries) of said jpgs to generate directories (./year/month/)
-copy the files into the corresponding directories.
What it doesn't:
-copy the files into the corresponding directories BECAUSE it doesn't find the original files (which it read out itself previously). I honestly have no clue why that is.
Here the sourcecode:
package fotosorter;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifIFD0Directory;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Date;
public class Fotosorter {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws JpegProcessingException, IOException {
File startdir = new File(System.getProperty("user.dir"));
FileFilter jpg = new FileFilter() {
#Override
public boolean accept(File pathname) {
return pathname.getAbsoluteFile().toString().toLowerCase().endsWith(".jpg");
}
};
File dir = new File(startdir, "bitmaps"+File.separator+"java-temp");
if (!(dir.exists() && dir.isDirectory())) {
if (!dir.mkdir()) {
throw new IOException("kann das Verzeichnis nicht erzeugen ");
}
}
File[] files = new File(startdir, "" + File.separator + "bitmaps" + File.separator + "java-fotos").listFiles(jpg);
for (File file : files) {
Metadata metadata = JpegMetadataReader.readMetadata(file);
ExifIFD0Directory directory = metadata.getDirectory(ExifIFD0Directory.class);
String[] dates = directory.getDate(ExifIFD0Directory.TAG_DATETIME).toString().split(" ");
File year = new File(dir, dates[5]);
File month = new File(year, dates[1]);
File fname = new File(month, file.getName());
if (!(month.getParentFile().exists() && month.getParentFile().isDirectory())) {
if (!month.mkdirs()) {
throw new IOException("kann die Verzeichnisse nicht erzeugen");
}
}
copyFile(file, fname);
}
}
public static void copyFile(File from, File to) throws IOException {
Files.copy(from.toPath(), to.toPath());
}
}
And here the full exception it throws:
run:
Exception in thread "main" java.nio.file.NoSuchFileException: D:\Benutzerdaten\Paul\Documents\NetBeansProjects\Fotosorter\bitmaps\java-fotos\cimg2709.jpg -> D:\Benutzerdaten\Paul\Documents\NetBeansProjects\Fotosorter\bitmaps\java-temp\2008\Sep\cimg2709.jpg
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsFileCopy.copy(WindowsFileCopy.java:205)
at sun.nio.fs.WindowsFileSystemProvider.copy(WindowsFileSystemProvider.java:277)
at java.nio.file.Files.copy(Files.java:1225)
at fotosorter.Fotosorter.copyFile(Fotosorter.java:64)
at fotosorter.Fotosorter.main(Fotosorter.java:59)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)
As you may have guessed it's not finished yet. Apart from solving my previously stated problem I still have to put it into methods.
Make sure that the input file exists.
But also make sure that the path of the destination folder does exist.
For the past couple of months I've been working on a game in java for a university project. It's coming up to the end of the project and I would like to compile the project into a single file which is easy to distribute. The game currently runs from inside the IDE and relies on the working directory being set somewhere specific (i.e. the content directory with sounds/textures etc). What's the best way to put all this together for portability? I'm hoping there is some way to compile the content into the jar file...
NB. I'm using NetBeans, so any solutions which are easy in netbeans get extra credit ;)
Addendum::
For future reference, I found a way of accessing things by directory, ythis may not be the best way but it works:
File directory = new File(ClassLoader.getSystemResource("fullprototypeone/Content/Levels/").toURI());
And now I can just use that file object as normal
You can embed resources in jar file - this is just a zip after all. The standard way to do that is to put resource files in some directory in your sources hierachy. Then you refer to them by Object.getClass().getResourceAsStream(). So you will need to change the way you retrieve them in your code.
You can read more here: Object.getClass().getResourceAsStream(). Of course instead of object you use some class from your package.
when you put those resource files in your src hierachy I believe Netbeans should jar them for you with standard build of the project.
Here is the manual for JNLP and Java Web Start. These technologies exist just for the task you've described.
Well one way is to access the resources via Class.getResourceAsStream (or Class.getResource). Then make sure that the files are in the JAR file.
Off the top of my head (and without trying it) you should be able to put the resources in with the source files which will get NetBeans to put them into the JAR file. Then change the File stuff to the getResource calls.
I would suggest making a simple program that plays a sound and trying it out before you try to convert the whole project over.
If you try and it doesn't work let me know and I'll see if I can dig into it a bit more (posting the code of the simple project would be good if it comes to that).
Here is the code I promised in another comment... it isn't quite what I remember but it might get you started.
Essentially you call: String fileName = FileUtils.getFileName(Main.class, "foo.txt");
and it goes and finds that file on disk or in a JAR file. If it is in the JAR file it extracts it to a temp directory. You can then use "new File(fileName)" to open the file which, no matter where it was before, will be on the disk.
What I would do is take a look at the getFile method and look at what you can do with the JAR file to iterate over the contents of it and find the files in a given directory.
Like I said, not exactly what you want, but does do a lot of the initial work for you.
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class FileUtils
{
public static String getFileName(final Class<?> owner,
final String name)
throws URISyntaxException,
ZipException,
IOException
{
String fileName;
final URI uri;
try
{
final String external;
final String decoded;
final int pos;
uri = getResourceAsURI(owner.getPackage().getName().replaceAll("\\.", "/") + "/" + name, owner);
external = uri.toURL().toExternalForm();
decoded = external; // URLDecoder.decode(external, "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
catch(final FileNotFoundException ex)
{
fileName = null;
}
if(fileName == null || !(new File(fileName).exists()))
{
fileName = getFileNameX(owner, name);
}
return (fileName);
}
private static String getFileNameX(final Class<?> clazz, final String name)
throws UnsupportedEncodingException
{
final URL url;
final String fileName;
url = clazz.getResource(name);
if(url == null)
{
fileName = name;
}
else
{
final String decoded;
final int pos;
decoded = URLDecoder.decode(url.toExternalForm(), "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
return (fileName);
}
private static URI getResourceAsURI(final String resourceName,
final Class<?> clazz)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI resourceURI;
uri = getJarURI(clazz);
resourceURI = getFile(uri, resourceName);
return (resourceURI);
}
private static URI getJarURI(final Class<?> clazz)
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = clazz.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
tempFile = File.createTempFile(fileName.replace("/", ""), Long.toString(System.currentTimeMillis()));
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}
Edit:
Sorry, I don't have time to work on this right now (if I get some I'll do it and post the code here). This is what I would do though:
Look at the ZipFile class and use the entries() method to find all of the files/directories in the zip file.
the ZipEntry has an isDirectory() method that you can use to figure out what it is.
I think the code I posted in this answer will give you a way to pick a temporary directory to extract the contents to.
I think the code I posted in this answer could help with copying the ZipEntry contents to the file system.
once the items are on the file system the code you already have for iterating over the directory would still work. You would add a new method to the FileUtils class in the code above and be able to find all of the files as you are doing now.
There is probably a better way to do it, but off the top of my head I think that will work.
yes ! put your compiled .class files and your resources with folders in a jar file .. you ll have to build a manifest file as well .. you can find the tutorial about making a .jar file on
google. most probably you ll be referred to java.sun.com .