I have a program that will start other JUnit test from a program. I will first tell you what it does:
1. Searching for the programma that are in the folder
2. Find the jar en searching through it for the test classes
Now I want to run that test class, but when I'm starts the class with this I get an error that he couldn't find the class:
for (String testclass: arrayList){
Class cl = Class.forName(testclass);
Logger.error(TestEnablerViewtool.class, "CL NAME : " + cl.getName());
JUnitTest test = new JUnitTest(cl.getName());
test.setTodir(new File(pathToReports));
task.addTest(test);
task.execute();
}
And I find the class with this piece of code:
public static List<String> getClasseNamesInPackage(String jarName, String packageName){
String s = "C:\\CMS\\CMS\\WEB-INF\\lib\\plugin-Login.jar";
jarName = "Login";
packageName = "test/" + jarName + "/deploy";
ArrayList<String> arrayList = new ArrayList<String> ();
packageName = packageName.replaceAll("\\." , "/");
try {
JarInputStream jarFile = new JarInputStream(new FileInputStream(s));
JarEntry jarEntry;
while(true) {
jarEntry=jarFile.getNextJarEntry();
if(jarEntry.getName() == null) {
break;
}
if((jarEntry.getName().startsWith (packageName)) &&
(jarEntry.getName().endsWith (".class")) ) {
arrayList.add(jarEntry.getName().replaceAll("/", "\\."));
}
}
}
catch( Exception e){
e.printStackTrace ();
}
return arrayList;
}
I hope the question is clear..
Related
I am writing Java application and I want to write some simple plugin system. I want to have base class Plugin. Other classes extends Plugin, these files are in some other directory out of class path.
public class Plugin {
public Plugin() {
//code
}
public void proc() {
//code
}
}
and class loader:
public class PluginLoader {
private static final FilenameFilter filter = new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return Pattern.matches("^.*[a-zA-Z]*[.]class$", name);
}
};
public static final String removeExtension(String str) {
if (str == null)
return null;
int pos = str.lastIndexOf(".");
if (pos == -1)
return str;
return str.substring(0, pos);
}
#SuppressWarnings("unchecked")
public static LinkedList<Plugin> loadEffects(String path) {
LinkedList<Plugin> result = new LinkedList<Plugin>();
Plugin instance = null;
File[] classesList = null;
System.out.println("Searching in " + path);
try {
File classDir = new File(path);
URL[] url = { classDir.toURI().toURL() };
URLClassLoader urlLoader = new URLClassLoader(url);
String filename;
classesList = classDir.listFiles(filter);
System.out.println(classesList.length + " class files found:");
for (File file : classesList) {
System.out.println("- " + file.getName());
}
for (File file : classesList) {
filename = removeExtension(file.getName());
if (filename.equals(".") || filename.equals("..") || filename.startsWith("."))
continue;
if (filename.equals("Plugin")) {
System.err.println("File name is Plugin");
continue;
}
System.out.println("Reading " + filename);
instance = (Plugin) urlLoader.findClass(filename).getConstructor().newInstance();
System.out.println("Adding: " + url + ", " + filename);
result.push(instance);
}
urlLoader.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
This code causes java.lang.NoClassDefFoundError: D:\test\PluginImpl/class (wrong name: test/PluginImpl). Plugin class is in D:\test.
You are calling File#getAbsolutePath() which will include the entire path and the drive letter (D:\). The class name stored in the class does not match with the class name you provided so Java throws an error.
Try calling findClass with just the class name and it should work
I'm having this weird issue where a class from some transitive dependency keeps showing up at runtime, shadowing a newer version of the class from the (correct) first level dependency, even though I thought I made sure that I excluded the older version from all other dependencies I declare (this is in a Maven/IntelliJ setup)
More specifically, at runtime the app fails with a NoClassDefFoundError, since during class loading a wrong version of the owning class is loaded, which has a field of a type that does not exist in newer versions of the library that class is defined in. To illustrate:
// lib.jar:wrong-version
class Owner {
private SomeType f;
}
// lib.jar:new-version
class Owner {
private OtherType f;
}
At runtime, the class loader finds a reference to the symbol Owner and attempts to load the version that has SomeType, which in return does not exist anymore. This is even though I excluded wrong-version where ever I could spot it.
I also ran mvn dependency:tree to see if the old version is still being pulled in somewhere, but it's not!
In order to further debug this, I was wondering if there is a way to find out where a class loader was reading a specific class from, i.e. which file? Is that possible? Or even better, build a list of origins where a certain symbol is defined, in case it's defined more than once?
Sorry if this is vague, but the problem is rather nebulous.
The following code will search the whole classpath for a particular class. With no arguments it will dump every class it finds and then you can pipe to grep or redirect to a file. It looks inside jars...
Usage: WhichClass or WhichClass package.name (note no .class)
Apologies for the lack of comments ...
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public final class WhichClass {
private WhichClass() {
}
static Vector<String> scratchVector;
public static void main(final String[] argv) {
Vector v;
if ((argv.length == 0) || "-all".equals(argv[0])) {
v = findClass(null);
} else {
v = findClass(argv[0]);
}
for (int i = 0; i < v.size(); i++) {
System.out.println(v.elementAt(i));
}
}
static String className(final String classFile) {
return classFile.replace('/', '.').substring(0, classFile.length() - ".class".length());
}
static Vector findClass(final String className) {
if (className != null) {
scratchVector = new Vector<String>(5);
} else {
scratchVector = new Vector<String>(5000);
}
findClassInPath(className, setupBootClassPath());
findClassInPath(className, setupClassPath());
return scratchVector;
}
static void findClassInPath(final String className, final StringTokenizer path) {
while (path.hasMoreTokens()) {
String pathElement = path.nextToken();
File pathFile = new File(pathElement);
if (pathFile.isDirectory()) {
try {
if (className != null) {
String pathName = className.replace('.', System.getProperty("file.separator").charAt(0)) + ".class";
findClassInPathElement(pathName, pathElement, pathFile);
} else {
findClassInPathElement(className, pathElement, pathFile);
}
} catch (IOException e) {
e.printStackTrace();
}
} else if (pathFile.exists()) {
try {
if (className != null) {
String pathName = className.replace('.', '/') + ".class";
ZipFile zipFile = new ZipFile(pathFile);
ZipEntry zipEntry = zipFile.getEntry(pathName);
if (zipEntry != null) {
scratchVector.addElement(pathFile + "(" + zipEntry + ")");
}
} else {
ZipFile zipFile = new ZipFile(pathFile);
Enumeration entries = zipFile.entries();
while (entries.hasMoreElements()) {
String entry = entries.nextElement().toString();
if (entry.endsWith(".class")) {
String name = className(entry);
scratchVector.addElement(pathFile + "(" + entry + ")");
}
}
}
} catch (IOException e) {
System.err.println(e + " while working on " + pathFile);
}
}
}
}
static void findClassInPathElement(final String pathName, final String pathElement, final File pathFile)
throws IOException {
String[] list = pathFile.list();
for (int i = 0; i < list.length; i++) {
File file = new File(pathFile, list[i]);
if (file.isDirectory()) {
findClassInPathElement(pathName, pathElement, file);
} else if (file.exists() && (file.length() != 0) && list[i].endsWith(".class")) {
String classFile = file.toString().substring(pathElement.length() + 1);
String name = className(classFile);
if (pathName != null) {
if (classFile.equals(pathName)) {
scratchVector.addElement(file.toString());
}
} else {
scratchVector.addElement(file.toString());
}
}
}
}
static StringTokenizer setupBootClassPath() {
String classPath = System.getProperty("sun.boot.class.path");
String separator = System.getProperty("path.separator");
return new StringTokenizer(classPath, separator);
}
static StringTokenizer setupClassPath() {
String classPath = System.getProperty("java.class.path");
String separator = System.getProperty("path.separator");
return new StringTokenizer(classPath, separator);
}
}
If you know the fully qualified name of the class, say somelib.Owner, you can try calling the following in your code:
public void foo() {
URL url = somelib.Owner.class.getClassLoader().getResource("somelib/Owner.class");
System.out.println(url);
}
I have used this code to get a list of class names from a package:
private List<String> getClasses()
{
List<String> classes = new ArrayList<String>();
String packageName = "algorithm/impl";
URL directoryUrl = Thread.currentThread().getContextClassLoader().
getResource(packageName);
File directory = new File(directoryUrl.getFile());
if(directory.exists())
{
String [] files = directory.list();
for(String filename : files)
{
classes.add(filename.substring(0, filename.lastIndexOf(".")));
}
}
return classes;
}
but this does not work when the app is packaged as an executable jar file. Why?
You can make use of this class JarFile.
JarFile file = new JarFile("YourFileName.jar");
for (Enumeration<JarEntry> enum = file.entries(); enum.hasMoreElements();) {
JarEntry entry = enum.next();
System.out.println(entry.getName());
}
Or if you want to search for particular class inside your jar you can use ZipFile class.
JarFile jar = new JarFile(YourJarFile);
ZipEntry e = jar.getEntry(CLASS_FILE_TO_FIND);
if (e == null) {
e = jar.getJarEntry(CLASS_FILE_TO_FIND);
if (e != null) {
foundIn.add(f.getPath());
}
} else {
foundIn.add(f.getPath());
}
I need to read class names(just the simple name) from a jar file(OSGified). I've placed the jar file in the lib folder and it's added to class path. Here is the code I've written:
public void loadClassName() throws IOException {
JarFile jf = new JarFile("/lib/xxxx-1.0.0.jar");
List<String> list = new ArrayList<String>();
for (JarEntry entry : Collections.list(jf.entries())) {
if (entry.getName().endsWith(".class")) {
String className = entry.getName().replace("/", ".").replace(".class", "");
list.add(className);
}
}
}
Somehow, I"m getting Filenotfound exception while constructing the jarfile object. Can somebody let me know how we should give the jar path to the JarFile constructor ?
try this:
JarFile jf = new JarFile("lib/xxxx-1.0.0.jar");
Thanks to the user #Perception. His answer has worked flawlessly.
This is the working code:
final InputStream jarStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("lib/xxxxx-1.0.0.jar");
JarInputStream jfs = new JarInputStream(jarStream);
List<String> list = new ArrayList<String>();
JarEntry je = null;
while (true) {
je = jfs.getNextJarEntry();
if (je == null) {
break;
}
if (je.getName().endsWith(".class")) {
String className = je.getName().replace("/", ".").replace(".class", "");
list.add(className);
}
}
This question already has answers here:
Can you find all classes in a package using reflection?
(30 answers)
Closed 9 years ago.
So I have a package that has classes that extend JPanel and I want to add them as tabs dynamically. At the beginning I used a factory and I registered all the classes in it and it worked, but now I want load all the classes in the package without knowing their names. I've tried several things including Reflections library (which I found very confusing) and I couldn't get them to work. I appreciate any help.
Here's one of my trials:
public static void registerTab() {
String pkg = TabA.class.getPackage().getName();
String relPath = pkg.replace('.', '/');
URL resource = ClassLoader.getSystemClassLoader().getResource(relPath);
if (resource == null) {
throw new RuntimeException("Unexpected problem: No resource for "
+ relPath);
}
File f = new File(resource.getPath());
String[] files = f.list();
for (int i = 0; i < files.length; i++) {
String fileName = files[i];
String className = null;
String fileNm = null;
if (fileName.endsWith(".class")) {
fileNm = fileName.substring(0, fileName.length() - 6);
className = pkg + '.' + fileNm;
}
if (className != null) {
if (!tabClasses.containsKey(className))
tabClasses.put(fileNm, className);
}
}
}
Here is a custom solution I developed to find all the classes of a package:
public class ClassFinder {
private static final char PKG_SEPARATOR = '.';
private static final char DIR_SEPARATOR = '/';
private static final String CLASS_FILE_SUFFIX = ".class";
private static final String BAD_PACKAGE_ERROR = "Unable to get resources from path '%s'. Are you sure the package '%s' exists?";
public static List<Class<?>> find(String scannedPackage) {
String scannedPath = scannedPackage.replace(PKG_SEPARATOR, DIR_SEPARATOR);
URL scannedUrl = Thread.currentThread().getContextClassLoader().getResource(scannedPath);
if (scannedUrl == null) {
throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage));
}
File scannedDir = new File(scannedUrl.getFile());
List<Class<?>> classes = new ArrayList<Class<?>>();
for (File file : scannedDir.listFiles()) {
classes.addAll(find(file, scannedPackage));
}
return classes;
}
private static List<Class<?>> find(File file, String scannedPackage) {
List<Class<?>> classes = new ArrayList<Class<?>>();
String resource = scannedPackage + PKG_SEPARATOR + file.getName();
if (file.isDirectory()) {
for (File child : file.listFiles()) {
classes.addAll(find(child, resource));
}
} else if (resource.endsWith(CLASS_FILE_SUFFIX)) {
int endIndex = resource.length() - CLASS_FILE_SUFFIX.length();
String className = resource.substring(0, endIndex);
try {
classes.add(Class.forName(className));
} catch (ClassNotFoundException ignore) {
}
}
return classes;
}
}
Then, just use:
List<Class<?>> classes = ClassFinder.find("com.package");