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
Related
I use maven invoker to compile generated source code programmatically.
I work now inside container and I would like to avoid of embedding MAVEN as well.
Currently the code (that runs locally) generally looks like this (I simplified it a bit):
InvocationRequest request = new DefaultInvocationRequest();
request.setPomFile(new File("pom.xml"));
request.setGoals(Collections.singletonList("test"));
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(new File(System.getenv("M2_HOME")));
try {
invoker.execute(request);
} catch (MavenInvocationException e) {
e.printStackTrace();
}
I want to redirect the invoker to the MVNW (Maven wrapper) I have along with the code.
Anyone has an idea if this is possible or supported?
Thanks!
It's possible
Although the creators of the plugin seem not to support that aspect directly, you can configure the Maven Invoker API to run Maven Wrapper using the Invoker's methods setMavenExecutable and setMavenHome.
There are two ways to achieve this:
Using an absolute path of the Maven Wrapper script
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(Path.of(".").toFile());
invoker.setMavenExecutable(new File("/home/user/projects/sample/mvnw"));
Using a relative path of the Maven Wrapper script
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(Path.of(".").toFile());
invoker.setMavenExecutable(new File("../mvnw"));
You can set the executable without any problem if MVNW script's path is absolute.
When it's relative then the internals of the plugin will try to prepend the <M2_HOME>/bin/ path - you have to skip (../) one parent folder when declaring the executable location (so the final path seen by the plugin will look like <M2_HOME>/bin/../mvnw).
As for M2_HOME - you have to set it via the API as well because of the plugin requirements. If you won't configure it, an exception will be raised:
Maven application directory was not specified, and ${maven.home} is
not provided in the system properties. Please specify at least on of
these.
Thankfully, you can safely set it to your project directory because since Maven 3.5.0 M2_HOME env is not necessary anymore.
If your MVNW script is not placed in the main directory of the project, you have to configure the paths appropriately.
While writing this answer I was using maven-invoker:3.0.1.
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/");
I'm using Liquibase in my Scala application which is packaged in a JAR using sbt assembly. When the changelog location is supplied using a local file path, everything works fine. In order to deploy using only the JAR, I'd like it to look inside the JAR instead. How can I do this?
Current Setup:
build.sbt includes "org.liquibase" % "liquibase-core" % "3.3.5" as a dependency
Run:
val liquibaseChangeLog: String = (from config)
val liquibase = new liquibase.Liquibase(liquibaseChangeLog, resourceAccessor, liquibaseConnection)
liquibase.update(new Contexts())
I'd like to set liquibaseChangeLog to a classpath like org/my_org/my_project/changelog.xml but I get an error:
Exception in thread "main" liquibase.exception.ChangeLogParseException: org/my_org/my_project/changelog.xml does not exist
liquibase.parser.core.xml.XMLChangeLogSAXParser.parseToNode(XMLChangeLogSAXParser.java:100)
liquibase.parser.core.xml.AbstractChangeLogParser.parse(AbstractChangeLogParser.java:17)
Looking through the Liquibase source in this stack trace, I see that it explicitly wants a file. Is there a way to look in the JAR instead?
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.
I have the following code:
Server server = new Server(9090);
final URL warUrl = Main.class.getClassLoader().getResource("com/domain/webapps/app");
final String warUrlString = warUrl.toExternalForm();
WebAppContext wac = new WebAppContext(warUrlString, "/app");
server.setHandler(wac);
I have the Main class in the com.domain package.
The jsp's and html's are in the com.domain.webapps.app package.
When run inside Netbeans (or java -cp <classpath> com.domain.Main on the exploded jar) the application works perfectly.
If i run the jar (java -jar app.jar), the content of the com.domain.webapps.app gets extracted to /tmp/Jetty_something/webapp/, so the full path is /tmp/Jetty_something/webapp/com/domain/webapps/app/
But when i make a request for http://localhost:9090/app/file.jsp, Jetty tries to get the file from /tmp/Jetty_something/webapp/file.jsp (the wrong place :-( )
What can i do where ?
Jetty version is 6.1.26
Have a look at this article. The URL is detected by
ProtectionDomain protectionDomain = Start.class.getProtectionDomain();
URL location = protectionDomain.getCodeSource().getLocation();
This works for me in a war project and maybe also for your jar use case.