Running testNG programmatically by pointing to an external jar throws ClassNotFoundException - java

I want to run TestNG tests programmatically by pointing to a jar which contains the test classes. For this, firstly the testng.xml is parsed and the classes are taken. Then each class is loaded into the classpath using the URLCLassLoader. But this throws org.testng.TestNGException: Cannot find class in classpath: exception.
Below is the code I tried
public void execute() {
String testNGXmlPath = "/path/to/testng.xml";
try {
getClassesToLoad(testNGXmlPath);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
TestNG testng = new TestNG();
List<String> suites = Lists.newArrayList();
suites.add(testNGXmlPath);
testng.setTestSuites(suites);
testng.run();
}
public void getClassesToLoad(String path) throws ParserConfigurationException, IOException, SAXException {
File inputFile = new File(path);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getElementsByTagName("class");
Element element;
Node node;
NamedNodeMap namedNodeMap;
int i, length;
length = nodeList.getLength();
for (int j=0; j < length; j++) {
element = (Element)nodeList.item(j);
namedNodeMap = element.getAttributes();
if (namedNodeMap != null) {
for (i=0; i<namedNodeMap.getLength(); i++) {
node = namedNodeMap.item(i);
if (node.getNodeName() == "name") {
try {
loadClass("/path/to/testng.sample-1.0-SNAPSHOT.jar", node.getNodeValue());
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
}
}
}
}
}
public static void loadClass(String jarFilePath, String className) throws MalformedURLException,
ClassNotFoundException {
File jarFile = new File(jarFilePath);
if (jarFile.isFile()) {
URL url = jarFile.toURL();
URL[] urls = new URL[] { url };
ClassLoader cl = new URLClassLoader(urls);
cl.loadClass(className);
}
}

You are loading the class loader using the URLClassLoader, but for the classes that were loaded by your class loader to be visible to the current ContextualClassLoader, you need to set it up.
Please try doing it via Thread.currentThread().setContextClassLoader(); within your loadClass() method and then try running your test. This would ensure that when TestNG kicks in, it uses the ContextClassLoader that you injected to the current thread, to be used to load classes and thus help you get past your ClassNotFoundException

If your intention is to run your tests from a jar, you can simply package them and run using your xml.
Refer to the commandline section of the testng documentation.
Can refer to these steps if yours is a maven project :

Related

Not able to scan hbm files and build mappings?

try {
// Add mapping locations
PropertyValue mappingLocationsProp = properties.getPropertyValue("mappingLocations");
if (mappingLocationsProp != null) {
List<TypedStringValue> mappingLocations = (List<TypedStringValue>) mappingLocationsProp.getValue();
if (mappingLocations != null) {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
for (TypedStringValue mappingLocation : mappingLocations) {
LOG.info("Found mappingLocation " + mappingLocation.getValue());
Resource[] resources = resourcePatternResolver.getResources(mappingLocation.getValue());
for (int i = 0; i < resources.length; i++) {
LOG.info("Adding resource " + resources[i].getURL());
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// Disable DTD resolution
documentBuilder.setEntityResolver(new EntityResolver() {
#Override
public InputSource resolveEntity(String arg0, String arg1) throws SAXException, IOException {
return new InputSource(new StringReader(""));
}
});
Document document = documentBuilder.parse(resources[i].getInputStream());
config.addDocument(document);
} catch (SAXException e) {
throw new DatabaseException("Error reading document " + resources[i].getURL(), e);
}
}
}
}
}
} catch (Exception e) {
if (e instanceof DatabaseException) {
throw (DatabaseException) e;
} else {
throw new DatabaseException(e);
}
}
I am trying to build configuration and build mapping files from it like this. config.buildMappings();
In hibernateTestContext.xml I have defined the mapping location as :
<property name="mappingLocations">
<list>
<value>classpath*:../WEB-INF/mapping/*/*.hbm.xml</value>
</list>
</property>
I have my hbms in E:\*\web\src\main\webapp\WEB-INF\mapping
But still I am not able to scan the hbms. I also have tried using file:../web/src/main/webapp/WEB-INF/mapping/*/*.hbm.xml
But I got this exception:
org.hibernate.InvalidMappingException: Could not parse mapping document from unknown
full error: org.hibernate.PropertyNotFoundException: field [testHole] not found on org.test.*.*.synchronization.hole.Hole
Reading and building hibernate config file:
` Configuration config = new Configuration();
// Disable xml validation
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setValidating(false);
// Read configuration
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.setNamespaceAware(true);
reader.loadBeanDefinitions(new ClassPathResource(connection.getPath()));`

After making changes in XML file, old data is loading in Java application

I am making some changes to an embedded XML file in my Java application. I have some fields, a LOAD button and a SAVE button. After clicking the save button I can see the XML file updating, but after clicking the load button the old values are being loaded to the fields.
Here is my code:
public class MyLoad_SaveSampleProject {
public String field1 = "";
public String field2 = "";
public void loadSampleProject() {
InputStream file = MyLoad_SaveSampleProject.class.getResourceAsStream("/main/resources/otherClasses/projects/SampleProject.xml");
try {
DocumentBuilderFactory DocBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder DocBuilder = DocBuilderFactory.newDocumentBuilder();
Document Doc = DocBuilder.parse(file);
NodeList list = Doc.getElementsByTagName("*"); //create a list with the elements of the xml file
for (int i=0; i<list.getLength(); i++) {
Element element = (Element)list.item(i);
if (element.getNodeName().equals("field1")) {
field1 = element.getChildNodes().item(0).getNodeValue().toString();
} else if (element.getNodeName().equals("field2")) {
field2 = element.getChildNodes().item(0).getNodeValue().toString();
}
}
} catch (Exception e) {
System.out.println(e);
}
}
public void saveSampleProject(String field1Str, String field2Str) {
InputStream file = MyLoad_SaveSampleProject.class.getResourceAsStream("/main/resources/otherClasses/projects/SampleProject.xml");
try {
DocumentBuilderFactory DocBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder DocBuilder = DocBuilderFactory.newDocumentBuilder();
Document Doc = DocBuilder.parse(file);
NodeList list = Doc.getElementsByTagName("*"); //create a list with the elements of the xml file
for (int i=0; i<list.getLength(); i++) {
Node thisAttribute = list.item(i);
if (thisAttribute.getNodeName().equals("field1")) {
thisAttribute.setTextContent(field1Str);
} else if (thisAttribute.getNodeName().equals("field2")) {
thisAttribute.setTextContent(field2Str);
}
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(Doc);
StreamResult result = new StreamResult(new File("src/main/resources/otherClasses/projects/SampleProject.xml"));
transformer.transform(source, result);
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
}
}
public String returnField1() {
return field1;
}
public String returnField2() {
return field2;
}
}
And this is my default XML file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><Strings>
<field1>string1</field1>
<field2>string2</field2>
</Strings>
When the save button is pressed I am using the saveSampleProject method. When the load button is pressed I am using the loadSampleProject method and then I am getting the field values with the returnField1 and returnField2 methods.
I have no idea of what could be wrong with what I'm doing. I would appreciate any suggestions.
Most probably that calling method getResourceAsStream() leads to resource caching. Since you are using File() in save method try to get InputStream on data load using File object, and not as resource.

nullpointerexception while trying to read from xml file with dom parser

I am trying to read from xml file but I get a null pointer exception.
this is the xml file:
<war>
<missileLaunchers>
<launcher id="L101" isHidden="false">
<missile id="M1" destination="Sderot" launchTime="2" flyTime="12" damage="1500"/>
<missile id="M2" destination="Beer-Sheva" launchTime="5" flyTime="7" damage="2000"/>
</launcher>
<launcher id="L102" isHidden="true">
<missile id="M3" destination="Ofakim" launchTime="4" flyTime="3" damage="5000"/>
<missile id="M4" destination="Beer-Sheva" launchTime="9" flyTime="7" damage="1000"/>
</launcher>
</missileLaunchers>
<missileDestructors >
<destructor id="D201">
<destructdMissile id="M1" destructAfterLaunch="4"/>
<destructdMissile id="M3" destructAfterLaunch="7" />
<destructdMissile id="M4" destructAfterLaunch="2"/>
</destructor>
<destructor id="D202">
<destructdMissile id="M2" destructAfterLaunch="3"/>
</destructor>
</missileDestructors>
<missileLauncherDestructors >
<destructor type="plane" >
<destructedLanucher id="L101" destructTime="4"/>
</destructor>
<destructor type="ship">
<destructedLanucher id="L102" destructTime="8" />
<destructedLanucher id="L102" destructTime="12"/>
</destructor>
</missileLauncherDestructors>
</war>
and this is the code:
public class XmlReader
{
File fXmlFile=null;
DocumentBuilderFactory dbFactory=null;
DocumentBuilder dBuilder=null;
Document doc=null;
public XmlReader(String filePath) throws ClassNotFoundException
{
if(filePath!=null)
{
this.fXmlFile = new File(filePath);
dbFactory = DocumentBuilderFactory.newInstance();
try {
dBuilder = dbFactory.newDocumentBuilder();
} catch (ParserConfigurationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
} catch (SAXException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else System.out.println("Xml file not found");
}
//gets value by tag name
private static String getTagValue(String tag, Element element) {
if(element.hasChildNodes())
{
NodeList nodeList = element.getElementsByTagName(tag).item(0).getChildNodes();
Node node = (Node) nodeList.item(0);
if(node==null)
return null;
return node.getNodeValue();
}
else return element.getNodeValue();
}
//launcher
public List<Launcher> readLauncher() throws Exception
{
List<Launcher> launcherList = new ArrayList<Launcher>();
try
{
NodeList nList = doc.getElementsByTagName("launcher");
for(int i=0;i<nList.getLength();i++)
{launcherList.add(getLauncher(nList.item(i)));}
}
catch (Exception e)
{
e.printStackTrace();
}
return launcherList;
}
//builds the object
private static Launcher getLauncher(Node node)
{
//XMLReaderDOM domReader = new XMLReaderDOM();
Launcher launcher = new Launcher();
if (node.getNodeType() == Node.ELEMENT_NODE)
{
Element element = (Element) node;
// launcher.setIsHidden(Boolean.parseBoolean(getTagValue("isHidden", element)));
// launcher.setId(getTagValue("id", element));
System.out.println("id = "+getTagValue("id", element));
System.out.println("ishidden = "+getTagValue("isHidden", element));
}
return launcher;
}
}
And this is the stack trace:
java.lang.NullPointerException
at XmlReader.getTagValue(XmlReader.java:56)
at XmlReader.getLauncher(XmlReader.java:96)
at XmlReader.readLauncher(XmlReader.java:78)
at Program.main(Program.java:27)
I can not change the format of the xml file.
It seems to fail when it tries to get the actual value of the node's fields or so I assume.
Though I don;t understand the reason...when I check the size of the node list it turns fine it does give me 2.
The problem is below line:
System.out.println("id = " + getTagValue("id", element));
where getTagValue("id", element) is calling
NodeList nodeList = element.getElementsByTagName(tag).item(0).getChildNodes();
Here element.getElementsByTagName("id") will return null
It should be get from attribute
// gets value by tag name
private static String getTagValue(String tag, Element element) {
return element.getAttributeNode(tag).getValue();
}
You are calling getElementsByTagName() in getTagValues, however you are trying to retrieve attributes of the tag. You may need to call getAttribute() instead. For Example:
element.getAttribute(attributeName)
where attributeName is "id" or "isHidden". This will return the value as a String and can be returned directly with no further processing.

How to load a Jasper customizer class during runtime?

I need to render Jasper reports with charts and require individual ChartCustomizer classes for them. My application is running as a Java web-application.
Current state is, that the templates (.jasper files) are packaged with their required resources in a separate jar-file. These jar files themselves are stored as BLOBs in the Database. I load them with an own FileResolver, which I provide as a parameter to the Jasper Engine.
So far this works great for me, except I cannot load my Customizer classes. I tried to put them in another jar file and load them with an own ClassLoader and also provide that to the Jasper Engine:
URL customizersUrl = classLoader.findResource("customizers.jar");
if (customizersUrl != null) {
URI jarUri = customizersUrl.toURI();
JarFile jarFile = new JarFile(new File(jarUri));
Enumeration e = jarFile.entries();
URL[] jarContentUrls = {new URL("jar:file:" + jarUri.getPath() + "!/")};
customizerClassLoader = URLClassLoader.newInstance(jarContentUrls);
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if (je.isDirectory() || !je.getName().endsWith(".class")) {
continue;
}
// -6 because of .class
String className = je.getName().substring(0, je.getName().length() - 6);
className = className.replace('/', '.');
Class c = customizerClassLoader.loadClass(className);
}
}
parameters.put(JRParameter.REPORT_CLASS_LOADER, customizerClassLoader);
but I am still getting a java.lang.ClassNotFoundException, although I can see in the Debugger, that the classloading from jar works.
Any help is appreciated!
Ok, I figured out that I need to put the class loader into the current thread's context. I am also using an anonymous class loader now, so that only requested classes get loaded (also improves debugging).
// check if customizer classes are present and load them
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final URL customizersUrl = classLoader.findResource("customizers.jar");
if (customizersUrl != null) {
ClassLoader cl = new ClassLoader() {
#Override
public Class loadClass(String className) throws ClassNotFoundException {
try {
return contextClassLoader.loadClass(className);
} catch (ClassNotFoundException ex) {
if (customizersUrl != null) {
try {
URI jarUri = customizersUrl.toURI();
URL[] jarContentUrls = {new URL("jar:file:" + jarUri.getPath() + "!/")};
URLClassLoader customizerInnerClassLoader = URLClassLoader.newInstance(jarContentUrls);
return customizerInnerClassLoader.loadClass(className);
} catch (URISyntaxException ex1) {
logger.debug("Exception during customizer class loading", ex1);
} catch (IOException ex1) {
logger.debug("Exception during customizer class loading", ex1);
} catch (ClassNotFoundException ex1) {
throw new ClassNotFoundException("Exception during customizer class loading", ex1);
}
}
}
return null;
}
};
// squeeze our own class loader in
Thread.currentThread().setContextClassLoader(cl);
}
byte[] result = generate(jasperReport, parameters);
// changing the class loader back to its origin... just to be safe
Thread.currentThread().setContextClassLoader(contextClassLoader);

How do I load instances of a certain class from a java directory?

Here's my method:
Feature[] getFeatures(File dir)
I'm trying to go through the directory, check each class file. Any class that is of type 'Feature', I want to load an instance of it. Then I want to return an array of these instances.
How is this done?
Thank you.
EDIT:
Here's what I have now:
private static LinkedList<Feature> getFeaturesInDirectory(File dir) throws ClassNotFoundException {
LinkedList<Feature> features = new LinkedList<Feature>();
ClassLoader cl = new IndFeaClassLoader();
// list all files in directory
for(String s : dir.list()) {
Class klass = cl.loadClass(s);
try {
Object x = klass.newInstance();
if (x instanceof Feature) {
features.add((Feature)x);
}
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
}
}
return features;
}
Using:
MyClassName mcn = (MyClassName) Class.forName("MyClassName").newInstance();
Note, however, that this relies on the ClassLoader. If the classes are not coming from the same location as your current class (or the system classloader) you need to specify a classloader:
File myDir = new File("/some/directory/");
ClassLoader loader = null;
try {
URL url = myDir.toURL();
URL[] urls = new URL[]{url};
ClassLoader loader = new URLClassLoader(urls);
}
catch (MalformedURLException e)
{
// oops
}
MyClassName mcn =
(MyClassName) Class.forName("MyClassName", true, loader).newInstance();
I think that should work, but if not it should at least put you on the right path.

Categories

Resources