dirku
asked on
Modify CLASSPATH on-the-fly / dynamically
I have an application which inspects JAR files and performs some action afterwards. The JAR file needs to be choosen via a JFileChoser dialog. How can I add this choosen JAR file to the CLASSPATH automatically after it has been chosen?
I tried to use
Properties props = System.getProperties();
String cp = props.getProperty("java.cl ass.path") ;
...
System.setProperties(props );
but the CLASSPATH doesn't seem to be changed although using System.out.println( System.getProperties("java .class.pat h")); shows, that the JAR has been appended to the CLASSPATH (at least to System.properties). Do I need to explicitely flush the Proeprties to be set effectively in th eenvironment?
Thank you,
Dirk
I tried to use
Properties props = System.getProperties();
String cp = props.getProperty("java.cl
...
System.setProperties(props
but the CLASSPATH doesn't seem to be changed although using System.out.println( System.getProperties("java
Thank you,
Dirk
The class-path is picked up bye the JVM when it starts so even if you modify the system property, I don't think you can actually tell the JVM (once it has started) to recognize a new class-path (it could also be dangerous as you might remove some of the JARs from the class-path which are already being used).
ASKER
Well, mayankeagle, you're right. However, how else can I make my application being aware that there is a (new) JAR file to be used in the further run?
My application choses the JAR file at runtime (and there are a lot of JAR files which could be chosed). Thus, I don't want these "thousands" of JAR files to be put in the CLASSPATH before starting the application.
So I want the application to use the chosed JAR file on later actions and the application needs to know about this JAR file to access the packed classes in this JAR file.
Dirk
My application choses the JAR file at runtime (and there are a lot of JAR files which could be chosed). Thus, I don't want these "thousands" of JAR files to be put in the CLASSPATH before starting the application.
So I want the application to use the chosed JAR file on later actions and the application needs to know about this JAR file to access the packed classes in this JAR file.
Dirk
ASKER
Hello, hoomanv.
I tried to use the code but it has no effect. The idea is great but I couldn't make it work until now. ...but I'm trying, hoping it's a mistake of mine.
I tried to use the code but it has no effect. The idea is great but I couldn't make it work until now. ...but I'm trying, hoping it's a mistake of mine.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I used the file obtained from the JFileChoser via File file = fc.getSelectedFile(); when calling ClassLoader urlCl = URLClassLoader.newInstance (new URL[]{file.toURL()}, prevCl);
The selected file is a JAR file in my case it is: D:\tmp\TTK\PRN_Printer.jar
The classes Vector of urlCl has no content and thus, the subsequent calls fail.
The selected file is a JAR file in my case it is: D:\tmp\TTK\PRN_Printer.jar
The classes Vector of urlCl has no content and thus, the subsequent calls fail.
It had no content? What did you use to verify that? Did you print it?
ASKER
Running it from within Eclipse it seems to work but starting the application with a batch file results in a ClassNotFoundException for a class from within the just selected JAR file.
Eclipse uses a different class-path than the system class-path.
ASKER
It seems so. When Eclipse can do it should be possible to do this either. But: HOW? Of course, the application should run as a stand-alon-app in the end and not within Eclipse. ;-)
At command prompt, try :
jar -tf <thejarfile>
to check that class is in the jar file.
You can also try to directly load the class using the classloader :
ClassLoader urlCl =
URLClassLoader.newInstance (new URL[]{file.toURL()}, prevCl);
Class cl=urlCl.loadClass("<class name>");
jar -tf <thejarfile>
to check that class is in the jar file.
You can also try to directly load the class using the classloader :
ClassLoader urlCl =
URLClassLoader.newInstance
Class cl=urlCl.loadClass("<class
You have to add classpath used by eclipse to your batch file.
see https://parse-dot-classpath.dev.java.net/
see https://parse-dot-classpath.dev.java.net/
ASKER
...but is the class available in another class than in the class which loads it?
I mean, I have a class which creates the UI in which I can invoke a JFileChoser dialog. I chose a file and (that's what I intended to do) the selected JAR file is added to the existing CLASSPATH.
The JAR file contains some classes (in particular junit testcases) as well as an XML file (a configuration file) which I need later.
In a different class the XML file needs to be get from th eJAR file. In my testcase (which in turn is in the same JAR file) I use the path to this XML file (String) as a parameter for a method call. This called method does not know anything from the existence of the JAR file and performs the following with the path to the XML file:
URL url = this.getClass().getResourc e(configFi le);
System.out.println(url == null ? "url == null" : url.toString());
assertTrue(deviceManager.s tart(url.o penStream( )));
Hence, the class extending the CLASSPATH is not the class using the extended CLASSPATH. So loading the class directly does not work, does it?
I mean, I have a class which creates the UI in which I can invoke a JFileChoser dialog. I chose a file and (that's what I intended to do) the selected JAR file is added to the existing CLASSPATH.
The JAR file contains some classes (in particular junit testcases) as well as an XML file (a configuration file) which I need later.
In a different class the XML file needs to be get from th eJAR file. In my testcase (which in turn is in the same JAR file) I use the path to this XML file (String) as a parameter for a method call. This called method does not know anything from the existence of the JAR file and performs the following with the path to the XML file:
URL url = this.getClass().getResourc
System.out.println(url == null ? "url == null" : url.toString());
assertTrue(deviceManager.s
Hence, the class extending the CLASSPATH is not the class using the extended CLASSPATH. So loading the class directly does not work, does it?
>> ...but is the class available in another class than in the class which loads it?
yes, if you called addClassesFrom before
But calling Thread.currentThread().set ContextCla ssLoader(u rlCl);
only work for the current thread, and threads created from that thread.
yes, if you called addClassesFrom before
But calling Thread.currentThread().set
only work for the current thread, and threads created from that thread.
I think you have to explicitly call urlCl.loadClass("<classnam e>"); and use reflection to create new instance of the class.
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/package-frame.html
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Class.html
because eclipse compile your application with Jarfile in the classpath (hardcoding direct class access), and you try to run it without the Jarfile in the classpath, which generates error because JVM try to load a class it cannot found, before your class can do anything.
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/package-frame.html
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Class.html
because eclipse compile your application with Jarfile in the classpath (hardcoding direct class access), and you try to run it without the Jarfile in the classpath, which generates error because JVM try to load a class it cannot found, before your class can do anything.
ASKER
Here's what I coded:
protected JButton createJarButton() {
final JButton jarChoose= new JButton("...");
jarChoose.addActionListene r(
new ActionListener() {
public void actionPerformed(ActionEven t e) {
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File("."));
fc.setFileSelectionMode(JF ileChooser .FILES_AND _DIRECTORI ES);
fc.setFileFilter(new DBSJarFileFilter());
int returnVal = fc.showOpenDialog(jarChoos e.getParen t());
if (returnVal == JFileChooser.APPROVE_OPTIO N) {
File file = fc.getSelectedFile();
try
{
//jFile = new JarFile(file.getName());
jFile = new JarFile(file.getAbsolutePa th());
browseSectionButton.setEna bled(true) ;
if (fFrame.getTitle().indexOf (file.getN ame()) < 0)
{
fFrame.setTitle(fFrame.get Title() + " - " + file.getName());
}
jarFileText.setText(file.g etName());
StringTokenizer st = new StringTokenizer(cp, ";");
boolean isInCp = false;
while ( st.hasMoreTokens() )
{
String cpEntry = st.nextToken();
//System.out.println(">>> " + cpEntry);
if ( cpEntry.equalsIgnoreCase(f ile.getNam e()) )
{
isInCp = true;
break;
}
}//end while
if ( isInCp == false )
{
String newPath = //"." +
//System.getProperty("file .separator ") +
//file.getName();
file.getAbsolutePath();
System.out.println("Select ed file: " + file.getAbsolutePath());
ClassLoader prevCl = Thread.currentThread().get ContextCla ssLoader() ;
//Create the class loader by using the given URL
//Use prevCl as parent to maintain current visibility
ClassLoader urlCl =
URLClassLoader.newInstance (new URL[]{file.toURL()}, prevCl);
Thread.currentThread().set ContextCla ssLoader(u rlCl);
}//end if ( isInCp == false )
} catch (IOException ioEx)
{
ioEx.printStackTrace();
}
}
}
}
);
return jarChoose;
}
protected JButton createJarButton() {
final JButton jarChoose= new JButton("...");
jarChoose.addActionListene
new ActionListener() {
public void actionPerformed(ActionEven
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new
fc.setFileSelectionMode(JF
fc.setFileFilter(new DBSJarFileFilter());
int returnVal = fc.showOpenDialog(jarChoos
if (returnVal == JFileChooser.APPROVE_OPTIO
File file = fc.getSelectedFile();
try
{
//jFile = new JarFile(file.getName());
jFile = new JarFile(file.getAbsolutePa
browseSectionButton.setEna
if (fFrame.getTitle().indexOf
{
fFrame.setTitle(fFrame.get
}
jarFileText.setText(file.g
StringTokenizer st = new StringTokenizer(cp, ";");
boolean isInCp = false;
while ( st.hasMoreTokens() )
{
String cpEntry = st.nextToken();
//System.out.println(">>> " + cpEntry);
if ( cpEntry.equalsIgnoreCase(f
{
isInCp = true;
break;
}
}//end while
if ( isInCp == false )
{
String newPath = //"." +
//System.getProperty("file
//file.getName();
file.getAbsolutePath();
System.out.println("Select
ClassLoader prevCl = Thread.currentThread().get
//Create the class loader by using the given URL
//Use prevCl as parent to maintain current visibility
ClassLoader urlCl =
URLClassLoader.newInstance
Thread.currentThread().set
}//end if ( isInCp == false )
} catch (IOException ioEx)
{
ioEx.printStackTrace();
}
}
}
}
);
return jarChoose;
}
ASKER
I removed to much statements. The following to line of code are coded right befor StringTokenizer instantiation:
Properties props = System.getProperties();
String cp = props.getProperty("java.cl ass.path") ;
Properties props = System.getProperties();
String cp = props.getProperty("java.cl
Can you post the code where you use classes from the selected jar file ?
I think you'll have to modify it to use reflection as I explained above.
I think you'll have to modify it to use reflection as I explained above.
ASKER
I have extended the functionality of JUnit classes by subclassing to have more flexibility in chosing the testcases or even test methods.
Here's the class which is for inspecting the JAR file to find TestCases to setup the GUI which means to select the directories in which useful TestCases are located:
package junit.runner;
import java.io.File;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import de.bahn.ae.tests.AbstractD BSTestCase ;
public class DBSJarInspectTestSectionCo llector extends SimpleTestCollector
{
private JarFile jarFile = null;
//======================== ========== ========== ========== ========== =========
/**
*
* @param jFile
*/
public DBSJarInspectTestSectionCo llector(Ja rFile jFile)
{
jarFile = jFile;
}//end constructor
//------------------------ ---------- ---------- ---------- ---------- ---------
/**
* Sammelt die Einträge für den {@link DBSTestSectionSelector}
* zusammen.
*
* @return Eine Aufzählung der gesammelten Elemente.
*/
public Enumeration collectTests()
{
Hashtable result = new Hashtable();
Enumeration jFileEnum = jarFile.entries();
while (jFileEnum.hasMoreElements ())
{
JarEntry jEntry = (JarEntry)jFileEnum.nextEl ement();
if (!jEntry.getName().endsWit h(".class" ))
{
continue;
}
File f = new File(jEntry.getName());
if (this.isTestClass(f.getNam e()))
{
//System.err.println(jEntr y.getName( ));
String fName = jEntry.getName().replaceAl l("/", ".")
.substring(0, jEntry.getName().replaceAl l("/", ".")
.lastIndexOf("."));
//System.err.println(fName );
Class cl = null;
try
{
cl = Class.forName(fName);
} catch (ClassNotFoundException e1)
{
e1.printStackTrace();
}
if (cl != null)
{
Class superClass = cl;
while((superClass = superClass.getSuperclass() ) != null )
{
if (superClass == AbstractDBSTestCase.class)
{
// Auf einem File Objekt zu arbeiten funktioniert
// nicht, da das JarEntry lediglich im JarFile
// vorliegt, aber nicht als Datei im Dateisystem!
// eintrag des JarFiles vorbereiten...
String s = jEntry.getName().replaceAl l("/", "\\\\");
String parentEntry = s.substring(0, s.lastIndexOf("\\"));
// Sektionsnamen und kompletten Pfad zum Parent
// der Sektion ermitteln.
int dirIdx = parentEntry.lastIndexOf("\ \");
String grandParentEntry = parentEntry.substring(dirI dx+1, parentEntry.length());
if ( grandParentEntry.startsWit h("section _") &&
result.containsKey(grandPa rentEntry) == false )
{
result.put(grandParentEntr y, parentEntry); //section, pfad
break;
}
}//end if (superClass == AbstractDBSTestCase.class)
}//end while
}//end if (cl != null)
}//end if (this.isTestClass(f.getNam e()))
}//end while (jFileEnum.hasMoreElements ())
return result.elements();
}//end collectTests
//------------------------ ---------- ---------- ---------- ---------- ---------
/**
* Korrigiert einen Fehler aus {@link SimpleTestCollector#isTest Class}.
* dort wird geprüft auf <code>classFileName.indexO f("Test") > 0</code>.
* <code>String.indexOf(Strin g)</code> liefert aber <b>-1</b>, wenn der
* gesuchte String nicht gefunden werden konnte. Wird der gesuchte String
* gleich am Anfang gefunden, wird <b>0</b> zurück geliefert.
* Die Implementierung aus SimpleTestCollector liefert also immer
* <code>FALSE</code>, wenn die Testmethode mit "Test" beginnt.
*/
protected boolean isTestClass(String classFileName) {
/*
boolean res = classFileName.endsWith(".c lass");
res = classFileName.indexOf('$') < 0;
res = classFileName.indexOf("Tes t") >= 0;
return res;
*/
return
classFileName.endsWith(".c lass") &&
classFileName.indexOf('$') < 0 &&
classFileName.indexOf("Tes t") >= 0;
}//end isTestClass
//------------------------ ---------- ---------- ---------- ---------- ---------
}
At the command prompt I get this excerpt of hte StackTrace:
Selected file: D:\tmp\TTK\PRN_Printer.jar
java.lang.ClassNotFoundExc eption: de.bahn.ae.tests.spi.sut.P RN_MT2Prin ter.sectio n_004_Prin t.TestCase _001_Print
at java.net.URLClassLoader$1. run(Unknow n Source)
at java.security.AccessContro ller.doPri vileged(Na tive Method)
at java.net.URLClassLoader.fi ndClass(Un known Source)
at java.lang.ClassLoader.load Class(Unkn own Source)
at sun.misc.Launcher$AppClass Loader.loa dClass(Unk nown Source)
at java.lang.ClassLoader.load Class(Unkn own Source)
at java.lang.ClassLoader.load ClassInter nal(Unknow n Source)
at java.lang.Class.forName0(N ative Method)
at java.lang.Class.forName(Un known Source)
at junit.runner.DBSJarInspect TestSectio nCollector .collectTe sts(DBSJar InspectTes tSectionCo llector.ja va: 59)
which is infact: cl = Class.forName(fName);
So, the JAR file is given into DBSJarInspectTestSectionCo llector properly but when I try to instantiate a class using Class.forName it fails.
Here's the constructor of one TestCase I intend to use:
public TestCase_001_Print(String testName)
{
super(testName);
configFile =
//"\\de\\bahn\\ae\\tests\\ spi\\sut\\ PRN_MT2Pri nter\\sect ion_004_Pr int\\Servi ceProvider Config.xml ";
"/de/bahn/ae/tests/spi/sut /PRN_MT2Pr inter/sect ion_004_Pr int/Servic eProviderC onfig.xml" ;
//"de.bahn.ae.tests.spi.su t.PRN_MT2P rinter.sec tion_004_P rint.Servi ceProvider Config.xml ";
}//end constructor
//------------------------ ---------- ---------- ---------- ---------- ---------
Here's the class which is for inspecting the JAR file to find TestCases to setup the GUI which means to select the directories in which useful TestCases are located:
package junit.runner;
import java.io.File;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import de.bahn.ae.tests.AbstractD
public class DBSJarInspectTestSectionCo
{
private JarFile jarFile = null;
//========================
/**
*
* @param jFile
*/
public DBSJarInspectTestSectionCo
{
jarFile = jFile;
}//end constructor
//------------------------
/**
* Sammelt die Einträge für den {@link DBSTestSectionSelector}
* zusammen.
*
* @return Eine Aufzählung der gesammelten Elemente.
*/
public Enumeration collectTests()
{
Hashtable result = new Hashtable();
Enumeration jFileEnum = jarFile.entries();
while (jFileEnum.hasMoreElements
{
JarEntry jEntry = (JarEntry)jFileEnum.nextEl
if (!jEntry.getName().endsWit
{
continue;
}
File f = new File(jEntry.getName());
if (this.isTestClass(f.getNam
{
//System.err.println(jEntr
String fName = jEntry.getName().replaceAl
.substring(0, jEntry.getName().replaceAl
.lastIndexOf("."));
//System.err.println(fName
Class cl = null;
try
{
cl = Class.forName(fName);
} catch (ClassNotFoundException e1)
{
e1.printStackTrace();
}
if (cl != null)
{
Class superClass = cl;
while((superClass = superClass.getSuperclass()
{
if (superClass == AbstractDBSTestCase.class)
{
// Auf einem File Objekt zu arbeiten funktioniert
// nicht, da das JarEntry lediglich im JarFile
// vorliegt, aber nicht als Datei im Dateisystem!
// eintrag des JarFiles vorbereiten...
String s = jEntry.getName().replaceAl
String parentEntry = s.substring(0, s.lastIndexOf("\\"));
// Sektionsnamen und kompletten Pfad zum Parent
// der Sektion ermitteln.
int dirIdx = parentEntry.lastIndexOf("\
String grandParentEntry = parentEntry.substring(dirI
if ( grandParentEntry.startsWit
result.containsKey(grandPa
{
result.put(grandParentEntr
break;
}
}//end if (superClass == AbstractDBSTestCase.class)
}//end while
}//end if (cl != null)
}//end if (this.isTestClass(f.getNam
}//end while (jFileEnum.hasMoreElements
return result.elements();
}//end collectTests
//------------------------
/**
* Korrigiert einen Fehler aus {@link SimpleTestCollector#isTest
* dort wird geprüft auf <code>classFileName.indexO
* <code>String.indexOf(Strin
* gesuchte String nicht gefunden werden konnte. Wird der gesuchte String
* gleich am Anfang gefunden, wird <b>0</b> zurück geliefert.
* Die Implementierung aus SimpleTestCollector liefert also immer
* <code>FALSE</code>, wenn die Testmethode mit "Test" beginnt.
*/
protected boolean isTestClass(String classFileName) {
/*
boolean res = classFileName.endsWith(".c
res = classFileName.indexOf('$')
res = classFileName.indexOf("Tes
return res;
*/
return
classFileName.endsWith(".c
classFileName.indexOf('$')
classFileName.indexOf("Tes
}//end isTestClass
//------------------------
}
At the command prompt I get this excerpt of hte StackTrace:
Selected file: D:\tmp\TTK\PRN_Printer.jar
java.lang.ClassNotFoundExc
at java.net.URLClassLoader$1.
at java.security.AccessContro
at java.net.URLClassLoader.fi
at java.lang.ClassLoader.load
at sun.misc.Launcher$AppClass
at java.lang.ClassLoader.load
at java.lang.ClassLoader.load
at java.lang.Class.forName0(N
at java.lang.Class.forName(Un
at junit.runner.DBSJarInspect
which is infact: cl = Class.forName(fName);
So, the JAR file is given into DBSJarInspectTestSectionCo
Here's the constructor of one TestCase I intend to use:
public TestCase_001_Print(String testName)
{
super(testName);
configFile =
//"\\de\\bahn\\ae\\tests\\
"/de/bahn/ae/tests/spi/sut
//"de.bahn.ae.tests.spi.su
}//end constructor
//------------------------
Replace:
cl = Class.forName(fName);
by:
cl=urlCl.loadClass(fName);
// so you need to pass urlCl to your DBSJarInspectTestSectionCo llector class
cl = Class.forName(fName);
by:
cl=urlCl.loadClass(fName);
// so you need to pass urlCl to your DBSJarInspectTestSectionCo
ASKER
Well, although not very nice: it works. At least for setting up the GUI.
However, when it's time to let the TestCases run there is some strange behaviour. I have a JAR file for testing printers and I have a JAR file for testing cardreaders.
The TestCases derive from a class called SpiTestCase which in turn derives form AbstractDBSTestCase which finally derives from JUnit's TestCase class.
In the setUp() (you remember, this method is called for each test method of a testcase) method from SpiTestCase a so called DeviceManger is started:
protected void startSPs(String configFile)
{
try
{
System.out.println("startS Ps(" + configFile + ")");
URL url = this.getClass().getResourc e(configFi le);
System.out.println("url == " + (url == null ? "null" : url.toString()));
if (url == null) return;
long timeVorher = System.currentTimeMillis() ;
assertTrue(deviceManager.s tart(url.o penStream( )));
//assertTrue(deviceManager .start(con figFile));
long timeElapsed = System.currentTimeMillis() -timeVorhe r;
assertTrue("Startvorgang des DeviceManagers dauert länger als 2500ms.",
(timeElapsed >= 0) && (timeElapsed <= 2500));
}
catch (SPIParameterException e)
{
if (e.getParameterName().equa lsIgnoreCa se("File") )
{
System.err.println(e.getMe ssage());
assertTrue("Falscher Parameter: " + e.getParameterName() +
" = " + configFile, false);
}
else
{
assertTrue("Falscher Parameter: " + e.getParameterName(), false);
}
System.err.println(e.toStr ing());
}
catch (SPIServiceProviderAlready StartedExc eption e)
{
System.err.println(e.getMe ssage());
//deviceManager.reset();
assertTrue("ServiceProvide r sind bereits gestartet.", false);
} catch (IOException e)
{
// TODO Auto-generated catch block
System.err.println("Konnte Datei " + configFile + " nicht lesen.");
e.printStackTrace();
}
}//end startSPs
When executing: URL url = this.getClass().getResourc e(configFi le); the URL for a cardreader is null. Executing it for a printer I get a valid URL to work upon.
The JAR files are identicall except for the TestCase class. Especially the configuration file which is used in the statement URL url = this.getClass().getResourc e(configFi le); has the same content for both, the cardreader and the pritner.
I have created the JAR files for printer and cardreader the same way using Eclipse.
How can it be that the XML/configuration file can be found using the PRN_printer.jar but not when using CRD_Cardreader.jar although the structur of both JARs is identical?
However, when it's time to let the TestCases run there is some strange behaviour. I have a JAR file for testing printers and I have a JAR file for testing cardreaders.
The TestCases derive from a class called SpiTestCase which in turn derives form AbstractDBSTestCase which finally derives from JUnit's TestCase class.
In the setUp() (you remember, this method is called for each test method of a testcase) method from SpiTestCase a so called DeviceManger is started:
protected void startSPs(String configFile)
{
try
{
System.out.println("startS
URL url = this.getClass().getResourc
System.out.println("url == " + (url == null ? "null" : url.toString()));
if (url == null) return;
long timeVorher = System.currentTimeMillis()
assertTrue(deviceManager.s
//assertTrue(deviceManager
long timeElapsed = System.currentTimeMillis()
assertTrue("Startvorgang des DeviceManagers dauert länger als 2500ms.",
(timeElapsed >= 0) && (timeElapsed <= 2500));
}
catch (SPIParameterException e)
{
if (e.getParameterName().equa
{
System.err.println(e.getMe
assertTrue("Falscher Parameter: " + e.getParameterName() +
" = " + configFile, false);
}
else
{
assertTrue("Falscher Parameter: " + e.getParameterName(), false);
}
System.err.println(e.toStr
}
catch (SPIServiceProviderAlready
{
System.err.println(e.getMe
//deviceManager.reset();
assertTrue("ServiceProvide
} catch (IOException e)
{
// TODO Auto-generated catch block
System.err.println("Konnte
e.printStackTrace();
}
}//end startSPs
When executing: URL url = this.getClass().getResourc
The JAR files are identicall except for the TestCase class. Especially the configuration file which is used in the statement URL url = this.getClass().getResourc
I have created the JAR files for printer and cardreader the same way using Eclipse.
How can it be that the XML/configuration file can be found using the PRN_printer.jar but not when using CRD_Cardreader.jar although the structur of both JARs is identical?
ASKER
BTW:
Here's the output of the first two System.out.println() statements of startSPs(configFile):
1. for CRD_Cardreader.jar
startSPs(/de/bahn/ae/tests /spi/sut/C RD_MT2Card reader/sec tion_001_C ardhandlin g/ServiceP roviderCon fig.xml)
url == null
2. for PRN_Printer.jar
startSPs(/de/bahn/ae/tests /spi/sut/P RN_MT2Prin ter/sectio n_004_Prin t/ServiceP roviderCon fig.xml)
url == jar:file:/D:/tmp/TTK/PRN_P rinter.jar !/de/bahn/ ae/tests/s pi/sut/PRN _MT2Printe r/section_ 004_Print/ Service
ProviderConfig.xml
Here's the output of the first two System.out.println() statements of startSPs(configFile):
1. for CRD_Cardreader.jar
startSPs(/de/bahn/ae/tests
url == null
2. for PRN_Printer.jar
startSPs(/de/bahn/ae/tests
url == jar:file:/D:/tmp/TTK/PRN_P
ProviderConfig.xml
1. /de/bahn/ae/tests/spi/sut/ CRD_MT2Car dreader/se ction_001_ Cardhandli ng/Service ProviderCo nfig.xml
Check this file is located in the jar you loaded.
As you load 2 jars, you can create 2 class loader, -> urlCl1 urlCl2
or create only one (URLClassLoader accepting an array of URL) -> urlCl
In both cases, you have to use the class loader
urlCl.getResource(configFi le);
instead of
this.getClass().getResourc e(configFi le);
Check this file is located in the jar you loaded.
As you load 2 jars, you can create 2 class loader, -> urlCl1 urlCl2
or create only one (URLClassLoader accepting an array of URL) -> urlCl
In both cases, you have to use the class loader
urlCl.getResource(configFi
instead of
this.getClass().getResourc
ASKER
This behaviour occurs even if I solely try to load CRD_Cardreader.jar!!!
ServiceProviderConfig.xml is located in the JAR I loaded.
Using urlCl.getResource(configFi le) would be difficult to do since I have no chance to priovide the TestCase with urlCl because:
DBSTestRunner e.g. invokes JarInspectTestSectionColle ctor. This works fine giving urlCl as parameter.
Finally, however, JUnit is used to run the TestCases which is not in my hands. Thus, I don't have a chance to provide the TestCase with urlCl, do I?
It's weird that the PRN_Printer.jar works fine but CRD_Cardreader does not although they are identical in its structure.
Running the app with PRN_Printer.jar succeeds every time even running after CRD_Cardreader.jar has failed already.
Running the app with CRD_Cardreader.jar fails every time even if CRD_Cardreader.jar is the only JAR file to load.
Here's the structure of CRD_Cardreader:
META-INF/MANIFEST.MF
de/
de/bahn/
de/bahn/ae/
de/bahn/ae/tests/
de/bahn/ae/tests/spi/
de/bahn/ae/tests/spi/sut/
de/bahn/ae/tests/spi/sut/C RD_Mt2Card reader/
de/bahn/ae/tests/spi/sut/C RD_Mt2Card reader/sec tion_001_C ardhandlin g/
de/bahn/ae/tests/spi/sut/C RD_Mt2Card reader/sec tion_001_C ardhandlin g/TestCase _001_Cardh andlingCon tactlessCa rdreader.c lass
de/bahn/ae/tests/spi/sut/C RD_Mt2Card reader/sec tion_001_C ardhandlin g/TestCase _002_Cardh andling.cl ass
de/bahn/ae/tests/spi/sut/C RD_Mt2Card reader/sec tion_001_C ardhandlin g/ServiceP roviderCon fig.xml
de/bahn/ae/tests/SpiTestCa se.class
Here's the structure of PRN_Printer.jar:
META-INF/MANIFEST.MF
de/
de/bahn/
de/bahn/ae/
de/bahn/ae/tests/
de/bahn/ae/tests/spi/
de/bahn/ae/tests/spi/sut/
de/bahn/ae/tests/spi/sut/P RN_MT2Prin ter/
de/bahn/ae/tests/spi/sut/P RN_MT2Prin ter/sectio n_004_Prin t/
de/bahn/ae/tests/spi/sut/P RN_MT2Prin ter/sectio n_004_Prin t/TestCase _001_Print .class
de/bahn/ae/tests/spi/sut/P RN_MT2Prin ter/sectio n_004_Prin t/TestCase _002_Print Line.class
de/bahn/ae/tests/spi/sut/P RN_MT2Prin ter/sectio n_004_Prin t/ServiceP roviderCon fig.xml
de/bahn/ae/tests/SpiTestCa se.class
ServiceProviderConfig.xml is located in the JAR I loaded.
Using urlCl.getResource(configFi
DBSTestRunner e.g. invokes JarInspectTestSectionColle
Finally, however, JUnit is used to run the TestCases which is not in my hands. Thus, I don't have a chance to provide the TestCase with urlCl, do I?
It's weird that the PRN_Printer.jar works fine but CRD_Cardreader does not although they are identical in its structure.
Running the app with PRN_Printer.jar succeeds every time even running after CRD_Cardreader.jar has failed already.
Running the app with CRD_Cardreader.jar fails every time even if CRD_Cardreader.jar is the only JAR file to load.
Here's the structure of CRD_Cardreader:
META-INF/MANIFEST.MF
de/
de/bahn/
de/bahn/ae/
de/bahn/ae/tests/
de/bahn/ae/tests/spi/
de/bahn/ae/tests/spi/sut/
de/bahn/ae/tests/spi/sut/C
de/bahn/ae/tests/spi/sut/C
de/bahn/ae/tests/spi/sut/C
de/bahn/ae/tests/spi/sut/C
de/bahn/ae/tests/spi/sut/C
de/bahn/ae/tests/SpiTestCa
Here's the structure of PRN_Printer.jar:
META-INF/MANIFEST.MF
de/
de/bahn/
de/bahn/ae/
de/bahn/ae/tests/
de/bahn/ae/tests/spi/
de/bahn/ae/tests/spi/sut/
de/bahn/ae/tests/spi/sut/P
de/bahn/ae/tests/spi/sut/P
de/bahn/ae/tests/spi/sut/P
de/bahn/ae/tests/spi/sut/P
de/bahn/ae/tests/spi/sut/P
de/bahn/ae/tests/SpiTestCa
You can create one URLClassLoader :
// file1 : new File("CRD_Cardreader.jar") ;
// file2 : new File("PRN_Printer.jar");
urlCl=URLClassLoader.newIn stance(new URL[]{ file1.toURL() , file2.toURL() }, prevCl);
and use urlCl to load the class
or create a different class loader for each jar file :
urlCl1=URLClassLoader.newI nstance(ne w URL[]{ file1.toURL() }, prevCl);
urlCl2=URLClassLoader.newI nstance(ne w URL[]{ file2.toURL() }, prevCl);
and use the right loader to load the class
you can also chain the 2 classloaders :
urlCl=URLClassLoader.newIn stance(new URL[]{ file1.toURL() }, prevCl);
urlCl=URLClassLoader.newIn stance(new URL[]{ file2.toURL() }, urlCl); // urlCl instead of prevCl
in this case you'll make a function like this one :
ClassLoader prevCl=null;
ClassLoader addJarFile(File f)
{
return prevCl=URLClassLoader.newI nstance(ne w URL[]{ file.toURL() },
(prevCl==null)? Thread.currentThread().get ContextCla ssLoader() :prevCl );
}
// file1 : new File("CRD_Cardreader.jar")
// file2 : new File("PRN_Printer.jar");
urlCl=URLClassLoader.newIn
and use urlCl to load the class
or create a different class loader for each jar file :
urlCl1=URLClassLoader.newI
urlCl2=URLClassLoader.newI
and use the right loader to load the class
you can also chain the 2 classloaders :
urlCl=URLClassLoader.newIn
urlCl=URLClassLoader.newIn
in this case you'll make a function like this one :
ClassLoader prevCl=null;
ClassLoader addJarFile(File f)
{
return prevCl=URLClassLoader.newI
(prevCl==null)? Thread.currentThread().get
}
ASKER
OK. But I don't that this is the point.
The prior soultion works fine (maybe it's prettier to implement the way you suggested with your last posting and so I did) but the fact is that the ServiceProviderConfig.xml cannot be found within the JAR file.
I printed out which JAR the URLClassLoader has 'loaded' after chosing in the JFileChoser and the CRD_Cardreader.jar has been loaded.
The question is now:
Why does my cardreader testcase cannot find the XML file within the JAR file although the printer testcase can do? (Looking for this XML file is performed in a method of the super class so both testcases call the same method.)
BTW: I increased point from 50 to 75 since you helped me so much so far.
The prior soultion works fine (maybe it's prettier to implement the way you suggested with your last posting and so I did) but the fact is that the ServiceProviderConfig.xml cannot be found within the JAR file.
I printed out which JAR the URLClassLoader has 'loaded' after chosing in the JFileChoser and the CRD_Cardreader.jar has been loaded.
The question is now:
Why does my cardreader testcase cannot find the XML file within the JAR file although the printer testcase can do? (Looking for this XML file is performed in a method of the super class so both testcases call the same method.)
BTW: I increased point from 50 to 75 since you helped me so much so far.
I found the error :
You're looking for a config file in
de/bahn/ae/tests/spi/sut/C RD_MT2Card reader/
But in Jar it is
de/bahn/ae/tests/spi/sut/C RD_Mt2Card reader/
Difference is letters 'T' and 't' in CRD_MT2Cardreader
You're looking for a config file in
de/bahn/ae/tests/spi/sut/C
But in Jar it is
de/bahn/ae/tests/spi/sut/C
Difference is letters 'T' and 't' in CRD_MT2Cardreader
ASKER
Oh no!!!!
I knew it must have been something really obvious. It was TOO trivial!! :-)
Thanks a lot, Webstorm. Next thing I will do is looking for an optivian (hoping I will find any as blind as I am). :-))
However, I learned a lot about class loading which I will keep in mind for future tasks.
Best regards,
Dirk
I knew it must have been something really obvious. It was TOO trivial!! :-)
Thanks a lot, Webstorm. Next thing I will do is looking for an optivian (hoping I will find any as blind as I am). :-))
However, I learned a lot about class loading which I will keep in mind for future tasks.
Best regards,
Dirk
:-)
http://forum.java.sun.com/thread.jspa?threadID=300557