I want to unit test my code which will have to create a .java file compile it and then the corresponding .class file should be created.
How can I create the test to see if the ".class" file is created? I have added test already for its existence, now I'm trying to test the file is a valid class file.
I tried
try {
Class.forName("Hello");
throw AssertError();
} catch( ClassNotFoundException e ) {
}
program.createClass();
Class.forName("Hello");
But I don't really know how to dynamically add the path where the file is created to the classpath.
EDIT
URL Class loaded does the work.
This is how my test looks like now.
#Test
void testHello() throws MalformedURLException, ClassNotFoundException {
URL[] url = {
new URL("file:/home/oreyes/testwork/")
};
try {
new URLClassLoader(url).loadClass("Hello");
throw new AssertionError("Should've thrown ClassNotFoundException");
} catch ( ClassNotFoundException cnfe ){
}
c.process();
new URLClassLoader(url).loadClass("Hello");
}
Use a new instance of an URLClassLoader, pointing to the root folder where you created the target class file. Then, use the Class.forName(String,ClassLoader); method with the dynamically created URLClassLoader to load the new class.
To show that it works, the following test case will create a source file, write some Java code in there and compile it using the Java 6 ToolProvider interfaces. Then, it will dynamically load the class using an URLClassLoader and invoke a reflective call to its class name to verify it's really this class which has been generated on the fly.
#Test
public void testUrlClassLoader() throws Exception {
Random random = new Random();
String newClassName = "Foo" + random.nextInt(1000);
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
List<File> files = new ArrayList<File>();
File sourceFolder = new File(".");
File sourceFile = new File(sourceFolder, newClassName + ".java");
FileWriter fileWriter = new FileWriter(sourceFile);
fileWriter.write("public class " + newClassName + " { { System.out.println(\""
+ newClassName + " loaded\"); }}");
fileWriter.close();
files.add(sourceFile);
Iterable<? extends JavaFileObject> compilationUnits1 = fileManager
.getJavaFileObjectsFromFiles(files);
compiler.getTask(null, fileManager, null, null, null, compilationUnits1).call();
fileManager.close();
URL url = sourceFolder.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { url });
Object newInstance = urlClassLoader.loadClass(newClassName).newInstance();
assertEquals(newClassName, newInstance.getClass().getName());
}
Instead of loading the class in order to verify it, you could shell out to a command like "file Hello.class" to see if it reports that it's a java class file, or even spawn a sub-process of java to load the class outside of your test JVM.
Related
I created folder src/test/resources/ in root project directory, and inside this I added a file in folder jsons as jsons/server_request.json.
Now I am trying to read this file by calling a the static function in CommonTestUtilityclass given as:
public class CommonTestUtility {
public static String getFileAsString(String fileName) throws IOException {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
File file = new File(classLoader.getResource(fileName).getFile());
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
}
Now while calling this function as
class ServerTest {
#Test
void test_loadResource() {
String content = CommonTestUtility.getFileAsString("jsons/server_request.json");
}
}
, It's giving me the error as:
CommonTestUtility - Cannot invoke "java.net.URL.getFile()" because the return value of "java.lang.ClassLoader.getResource(String)" is null.
I tried to include the src/test/resources/ in the run configuration
of Junit ServerTest.java, but still it's not able to find out the
resource
How to resolve this issue?
https://mkyong.com/java/java-read-a-file-from-resources-folder/
This above link might be helpful.
The getResource() method return an URI you need to change
.getFile() function to. toURI().
Simple code
private File getFileFromResource(String fileName) throws URISyntaxException{
ClassLoader classLoader = getClass().getClassLoader();
URL resource = classLoader.getResource(fileName);
if (resource == null) {
throw new IllegalArgumentException("file not found! " + fileName);
} else {
// failed if files have whitespaces or special characters
//return new File(resource.getFile());
return new File(resource.toURI());
}
}
I recreated the same scenario you describe and your code works for me.
Could you double-check that your project looks like mine below? If so, I suspect it might be something with your environment.
i've loaded jar dynamically from other jar file, then at some point, i want to delete this jar and replace it by newer version, on linux it works fine, while on windows when i try to move the file to backup directory i get file being used by another process exception.
public void loadJarAndClass() {
URL[] jarUrl = new URL[1];
jarUrl[0] = jarFile.toURI().toURL();
classLoader = new URLClassLoader (jarUrl, this.getClass().getClassLoader());
classToLoad = Class.forName ("Burner.MainWindow", true, classLoader);
}
public void unloadJarAndClass() {
/* all object must be collected in order to reload jar */
jarFile = null;
dukeClassLoader = null;
classToLoad = null;
System.gc();
}
my main:
jarPath = currentPath.getAbsolutePath() + File.separator + JAR_NAME;
jarFile = new File(jarPath);
loadJarAndClass();
unloadJarAndClass();
Files.delete(FileSystems.getDefault().getPath(jarPath));
my problem is with the delete which throws exception " the process cannot access the file because it is being used by another process"
how can i bypass this exception and close any handler opened ?
Try using Classloader.close() method,
Here is the extract from the Oracle link,
In Java SE 7, the URLClassLoader close() method effectively invalidates the loader, so that no new classes can be loaded from it. It also closes any JAR files that were opened by the loader. This allows the application to delete or replace these files and, if necessary, create new loaders using new implementations.
Following is the simplified version of the code that might serve the purpose,
public class Example {
public static void main(String[] args) throws IOException, ClassNotFoundException {
String jarPath = "C:\\example.jar";
File jarFile = new File(jarPath);
URL[] jarUrl = new URL[1];
jarUrl[0] = jarFile.toURI().toURL();
URLClassLoader classLoader = new URLClassLoader (jarUrl, Example.class.getClassLoader());
Class classToLoad = Class.forName ("DataGenerator", true, classLoader);
classLoader.close();
Files.delete(FileSystems.getDefault().getPath(jarPath));
}
}
please try closing the classloader before you 'unload' it.
public void unloadJarAndClass() throws IOException {
dukeClassLoader.close();
/* all object must be collected in order to reload jar */
jarFile = null;
dukeClassLoader = null;
classToLoad = null;
// System.gc(); don't do this unless you're really
// sure you have to !
}
I would recommend not calling System.gc() explicitly !
(see Why is it bad practice to call System.gc()? for example)
I have selected a jar file using file selector, then loaded all the classes in the jar file using java reflection. Some classes has dependency on another jar file.
But when I try to get method of class then following exception is thrown because this class has a import statement import com.thoughtworks.xstream.XStream; and XStream class is defined in another jar file.
Exception in thread "main" java.lang.NoClassDefFoundError: com/thoughtworks/xstream/io/HierarchicalStreamDriver
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2365)
at java.lang.Class.privateGetPublicMethods(Class.java:2488)
at java.lang.Class.getMethods(Class.java:1406)
at com.axway.xtp.testgenerator.templatewizard.MethodSelectionWizardUI.updateListofMethods(MethodSelectionWizardUI.java:744)
at com.axway.xtp.testgenerator.templatewizard.MethodSelectionWizardUI$7.widgetSelected(MethodSelectionWizardUI.java:474)
at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:90)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:928)
I wanted to know that is there any way to prevent the dependency class or jar file to be loaded using java reflection. Following are the piece of code I am using to load classes.
URLClassLoader ucl = new URLClassLoader(new URL[] { new URL("file:" + codeRepository) });
JarFile jarFile = new JarFile(new File(codeRepository));
Enumeration enm = jarFile.entries();
while (enm.hasMoreElements()) {
JarEntry entry = ((JarEntry) enm.nextElement());
if (entry.getName().endsWith(".class")) {
String fullClassNameWithPath = entry.getName();
String fullyClassifiedClassName = fullClassNameWithPath
.replace('/', '.');
try {
Class c = ucl.loadClass(fullyClassifiedClassName.substring(
0, fullyClassifiedClassName.indexOf(".class")));
String className = c.getPackage().getName() + "."
+ c.getSimpleName();
listClasses.add(className);
} catch (Exception e) {
continue;
} catch (Throwable t) {
continue;
}
}
}
Well, if your application depends on that class, you most definitely need to have the jar containing it (or provide an alternative path containing the package+class) on the classpath.
As part of the classloading process, any classes which the class you want to load depends upon will also be loaded.
I don't think there's anything you can do about that.
I want to load class from that is not in class path.
is there any way that I load class by file path without being in classpath ?
for example
ClassLoader.load("c:\MyClass.class");
Example taken from here:
// Create a File object on the root of the directory containing the class file
File file = new File("c:\\myclasses\\");
try {
// Convert File to a URL
URL url = file.toURL(); // file:/c:/myclasses/
URL[] urls = new URL[]{url};
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
// Load in the class; MyClass.class should be located in
// the directory file:/c:/myclasses/com/mycompany
Class cls = cl.loadClass("com.mycompany.MyClass");
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
}
Load your class content into a byte array and use ClassLoader.html#defineClass(java.lang.String, byte[], int, int) manually.
How do I open a .class or .jar file within a Java program?
(remember that .jar files may have more than one class with main(String[] args) method)
(individual question from IDE-Style program running )
Here is a quick and dirty dirty hack for running all main methods found in the jar.
import java.io.*;
class JarRunner {
public static void main(String[] args) throws IOException,
ClassNotFoundException {
File jarFile = new File("test.jar");
URLClassLoader cl = new URLClassLoader(new URL[] {jarFile.toURL() });
JarFile jf = new JarFile(jarFile);
Enumeration<JarEntry> entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry je = entries.nextElement();
String clsName = je.getName();
if (!clsName.endsWith(".class"))
continue;
int dot = clsName.lastIndexOf('.');
Class<?> clazz = cl.loadClass(clsName.substring(0, dot));
try {
Method m = clazz.getMethod("main", String[].class);
m.invoke(null, (Object) new String[0]);
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
}
}
As mentioned by other posters, you may want to have a look in the manifest file for the main class (so you don't have to be guessing). This can be accessed through JarFile.getManifest().
The manifest names the jar's entry point.
Use
java -cp my.jar org.myorg.MyClass
if MyClass is the one you want to start. If my.jar has a proper MANIFEST.MF file indicating MyClass you can use
java -jar my.jar
You can open a .jar with any compression-software (winrar, winzip, 7zip) and you can run the .class file with java.exe
I think your questions is about situation when you don't know specification of external class in compilation time. Am I right?
So you need to use reflection API for creating instance of necessary class and invoking its method. You can see example above.
And for determining class for running from jar file you should use package 'java.util.jar' for accessing manifest via Manifest class. And you can determine entry point of this jar from attribute 'Main-Class'.