How to use maven test classes in main class - java

I am trying to create a test automation framework using Maven and TestNG. All the test classes in the application are written under src/test/java folder and all utility methods are written under src/main/java. I can run all the test scripts using pom.xml successfully. The framework also contains a main method from where testng.xml is created dynamically and the test classes are run. In the main method I am loading the test classes using below code
File classDir = new File("C:/workspace/myproject/target/test-classes/packagename/testScripts/"); //This is the path of all the compiled test classes
URL[] classUrl = {classDir.toURI().toURL()};
URLClassLoader urlClassLoader = new URLClassLoader(classUrl);
Class<?> testClass=urlClassLoader.loadClass("packagename.testScripts.TestClassName");
but it throws exception
java.lang.ClassNotFoundException: packagename.testScripts.TestClassName
How to resolve this issue?

According to the FQN of your class which is packagename.testScripts.TestClassName, your classDir is not properly set it should rather be:
File classDir = new File("C:/workspace/myproject/target/test-classes/");

Related

java.lang.ClassNotFoundException: io.quarkus.runtime.Quarkus

I am trying to run runner jar of the quarkus application which would be listening over port 9411 on http.
Programmatically using UrlClassLoader, when I try to load the jar it throws
(also with java -jar)
1.java.lang.ClassNotFoundException: io.quarkus.runtime.Quarkus
2.java.lang.reflect.InvocationTargetException
here is the snippet of code ,
URLClassLoader loader = new URLClassLoader(
new URL[]{ new File(<location of runner jar>).toURI().toURL()});
Thread.currentThread().setContextClassLoader(loader);
Class<?> mainClass = loader.loadClass("io.quarkus.runner.GeneratedMain");
Method mainMethod = mainClass.getMethod("main", String[].class);
mainMethod.invoke(null, (Object) new String[]{});
another observation is when I place /lib folder at the runner jar location it loads successfully meaning it requires the lib folder altogether.
How can I make my code work only with runner jar?
To produce a fat jar that includes all the libraries necessary to run the app, use the property quarkus.package.uber-jar=true (you can add that into src/main/resources/application.properties or pass it as a system property when running the build).
With mvn clean package I got the following error starting:
Unrecognized configuration key "quarkus.package.uber-jar" was provided
I've found
quarkus.package.type=uber-jar
as a property.
What I prefer is setting
<quarkus.package.type>uber-jar</quarkus.package.type>
in the pom properties.
https://github.com/fluentcodes/sandbox/tree/java-quarkus-empty

How to run main class packed in springboot jar

My project uses springboot, after pack it to jar file, I can execute java -jar my-project.jar to run the instance.
I also have a script which is a main class, when I execute java -cp my-project.jar com.test.MyScript, it says Could not find or load main class.
How can this happen? By the way, when I execute java -cp my-project.jar com.test.MyApplication, the same error occurs. MyApplication is the SpringBootApplication class.
Why can't I manually run the main class?
That is because spring boot doesn't use the SpringBootApplication as the main entry point. It uses org.springframework.boot.loader.Launcher.
Excerpt from the spring docs:
The org.springframework.boot.loader.Launcher class is a special
bootstrap class that is used as an executable jar’s main entry point.
It is the actual Main-Class in your jar file, and it is used to setup
an appropriate URLClassLoader and ultimately call your main() method.

How do I make the java ClassLoader aware of available classes?

I am trying to create Java plugins for an existing application. The plugins would like to re-use a lot of the already existing code-base in the main application (e.g. logging, error handling, etc).
I am trying to load plugins as .jar files like this:
String localPath = "...";
String pluginName = "...";
File jarFile = new File(localPath);
ClassLoader pluginLoader = URLClassLoader.newInstance(new URL[]{jarFile.toURL()});
pluginLoader.loadClass(pluginName).newInstance();
The problem I am having is that the classes I would like to import inside the plugin can not be found, even though they exist in the main app, I am getting errors like this:
NoClassDefFoundError: com/foo/exception/FooException
at com.foo.plugins.PluginManager.loadPlugin(PluginManager.java:187)
at com.foo.plugins.PluginManager.loadPlugins(PluginManager.java:86)
...
com/foo/exception/FooException is used everywhere in the code, but I didn't want to have to include this class (and many many others) in the plugin jar file. Instead I would like the ClassLoader to somehow be aware of the locally existing classes. Is this possible? If so, how can I do it?
You need to use your main application's classloader as a parent:
ClassLoader mainLoader = ThisClass.class.getClassLoader(); // some class in the main application
ClassLoader pluginLoader = URLClassLoader.newInstance(new URL[]{jarFile.toURL()}, mainLoader);
Then classes loaded by the plugin classloader will have access to classes loaded by the main classloader (as well as that classloader's parent, if it has one, and so on).

Load test resources within other module?

I'm using a abstract class in another module for reading and input for my testdata with:
package src/main/java/path/to/my/base/testclass;
InputStream stream = getClass().getResourceAsStream(filename);
filename is eg "test.txt", located in src/main/resources/path/to/my/base/testclass
As long as I put this abstract class into the same module as my testclasses are in, everything works fine.
Then i extract the acstract class (as well as the resources) to other module, compile, add to pom etc.
Result: My test implementation runs fine, but: I'm getting IO exception as the file could not be found.
What am I missing here? Why does the abstract class work within the same module, but not within another?
Test resources are for this artifact's tests only, they don't get deployed.
There are two possible ways around this:
Dirty: Make your app deploy a test jar along with the main jar,
and add that as a dependency with scope TEST to the second artifact.
Clean: Create a separate test artifact for base test classes and
common test resources. Important: in this artifact, nothing goes in src/test and everything goes in src/main. Reference this test artifact from both other
artifacts with scope TEST.

Cast from super class with dynamic class load JAR

I have some classes with this organisation
--> : Inherit
TwittEntititesNetwork --> TwitterGephiStreamer
TwittGrapher --> TwitterGephiStreamer
TwitterGephiStreamer is Abstract
TwitterGephiStreamer have a method : myMethod()
Directory
./myApp.jar
./NetworkLogicDirectory/TwittGrapher.jar
./NetworkLogicDirectory/TwittEntititesNetwork.jar
I use this code to load dynamically the daughters classes (which are in another .jar file)
public static TwitterGephiStreamer LoadNetworkLogicJar() throws Exception
{
File dir = new File(NetworkLogicDirectory);
URL[] urls = new URL[dir.listFiles().length];
for(int i = 0;i < dir.listFiles().length;i++)
{
File s = dir.listFiles()[i];
String url = "file:///"+s.getAbsolutePath();
urls[i] = new URL(url);
}
ClassLoader = new URLClassLoader(urls);
if(defaultProps.containsKey("NetworkLogic") && !defaultProps.getProperty("NetworkLogic").isEmpty())
{
Class<?> networkLogicClassLoader = ClassLoader.loadClass("org.naoyun.gephistream.networklogic."+defaultProps.getProperty("NetworkLogic"));
Object object = networkLogicClassLoader.newInstance();
return (TwitterGephiStreamer) object;
}
else
{
throw new Exception("blabalbalbal ");
}
}
So it's have to return a TwitterGephiStreamer which I can use as a normal class and I can use myMethod() normally .
When I run on eclispe it's works well I don't have any error.
When I export my app as a runnable .jar (myApp.jar) it's throw me this error :
java.lang.ClassCastException: org.naoyun.gephistream.networklogic.TwittEntitiesNetwork cannot be cast to org.naoyun.gephistream.TwitterGephiStreamer
at org.naoyun.utils.ConfigurationTools.LoadNetworkLogicJar(ConfigurationTools.java:62)
at org.naoyun.TwitterStreamer.<init>(TwitterStreamer.java:34)
at org.naoyun.TwitterStreamer.main(TwitterStreamer.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
So, I don't know how to resolve this problem. Is my code creepy but Eclispe can handle it on the fly, or is there other stuff that I'm not up do date?
Thanks for your time !
You probably have org.naoyun.gephistream.TwitterGephiStreamer included more than once on your dynamic classpath. When the subclass is loaded it loads a copy of TwitterGephiStreamer that is conflicting with a previous loaded copy.
Since, TwittGrapher.jar and TwittEntititesNetwork.jar depend on the same core classes/interfaces (i.e. TwitterGephiStreamer), I would suggesting putting those types in a separate utility jar. This should help eliminate any duplicated types on the classpath and provide for a clean jar dependency tree:
myApp
/ \
TwittGrapher TwittEntitiesNetwork
\ /
TwittUtil
You should not use Eclipse to build your executable jar but rather make one manually, e.g. using an Ant build script.
When Eclipse builds an executable jar it packages everything together in one tidy package, loading dependent jars through its own classloader, found in the "jarinjarloader" package you see referenced in your stack trace. This classloader can't find your external jar when it's not part of the "omni-jar" that Eclipse builds.
I've used the URLClassLoader in the past to successfully do what you're trying to do: load external jars at runtime. Here is a question on SO that explains how to use it:
Is it possible to “add” to classpath dynamically in java?
This tutorial should help with using Ant to build an executable jar:
Build an executable jar file by referencing your dependencies
This Ant tutorial is similar and shows how to do it with Eclipse, though it doesn't set the dependencies in the manifest. You'll need to do that for your core application classes, not any external jars to be loaded at runtime.

Categories