I have a standard Sprinb Boot project.
And in the folder: src/main/resources/tmp/my_file.json, i have a json that I read in my Java code.
File file = new File("src/main/resources/tmp/my_file.json");
When running it locally it goes perfectly
With Jib I create a docker image:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<from>
<image>adoptopenjdk:11-jre-hotspot</image>
</from>
<to>
<image>xxx/my_project:${version}</image>
</to>
<container>
<creationTime>USE_CURRENT_TIMESTAMP</creationTime>
</container>
</configuration>
</plugin>
When I run the container, it gives me an error that it cannot find the file:
java.io.FileNotFoundException: src/main/resources/tmp/my_file.json (No such file or directory)
The "src/main/resources" folder is the standard location for static resources.
Should I add any extra configuration to Jib to make the file available?
You don't want your application to open a file based on the source project structure. At runtime (whether packaged as a JAR file or a container image), you won't have the src/ directory, and new File("src/...") will always fail. For example, even outside the Docker context, suppose you packaged your app as a runnable jar. Then running your app with java -jar <your-runnable.jar> will fail from the same error.
What Java folks usually do is to search files on a classpath, and this is pretty much the standard way to what you're trying to achieve. You can find many useful materials when you google "java get resources", but here are some references:
https://www.baeldung.com/java-classpath-resource-cannot-be-opened
https://docs.oracle.com/javase/8/docs/technotes/guides/lang/resources.html
https://mkyong.com/java/java-read-a-file-from-resources-folder/
As of now, Jib 2.7.0 is the latest.
The problem is not with Jib but with your code.
Put "src/main/resources/" on the class path -- this is a standard way. And modify your code as below:
File file = new File("tmp/my_file.json");
When Jib creates an image, it copies all the resources from "src/main/resources/" to a directory ("/app/resources") on the image and puts that directory on the class path while launching your application.
Related
I have a Maven project in Eclipse, where i added the Sigar library using
<dependency>
<groupId>org.fusesource</groupId>
<artifactId>sigar</artifactId>
<version>1.6.4</version>
</dependency>
This was compiling and executing smoothly under eclipse. When i created an executable jar i was getting an error, that the .so file doesn't exist in the java.library.path.
DEBUG Sigar - no libsigar-amd64-linux.so in java.library.path
org.hyperic.sigar.SigarException: no libsigar-amd64-linux.so in java.library.path
After some research and reading (ok, more than some) i copied the lib folder of sigar (the one that holds all the .so files) under my project (i was not sure if I have to copy it to a specific place, so i put it under the project's root) and changed the maven dependency to that:
<dependency>
<groupId>org.fusesource</groupId>
<artifactId>sigar</artifactId>
<version>1.6.4</version>
<configuration>
<workingDirectory>${project.build.directory}/Sigar_lib</workingDirectory>
<mainClass>my.package.name.MyClass</mainClass>
<includeProjectDependencies>true</includeProjectDependencies>
</configuration>
</dependency>
Tried all different approaches to the <workingDirectory> tag, with/without the build directory, forward/back slash and so on. Every time the jar fails to execute with the same error.
Any help please? Thank you
please consider using Apache Maven Shade plugin in order to build your executable jar. You can configure what kind of resources you want to have in your final Uber jar . See details here
Example
<filter>
<artifact>*:*</artifact>
<includes>
<include>xxx/*.so</include>
</includes>
</filter>
Hope that helps.
I have a war project that depends on another jar project in the same directory.
Now I want to start the war project in jetty with maven, and want it to hot swap changes in the dependent project so that the chagnes take effect immediately. My plugin config looks like this:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<webAppSourceDirectory>${project.basedir}/src/main/resources</webAppSourceDirectory>
<classesDirectory>${project.basedir}/src/main/java</classesDirectory>
<webApp>
<contextPath>/</contextPath>
<descriptor>${basedir}/src/main/resources/WEB-INF/web.xml</descriptor>
</webApp>
</configuration>
</plugin>
How can i do it please? any pointer is appreciated.
First thing to point out...
You don't want to do this, as JAR reloading is poorly supported by Java itself, it will tend to want to cache the JAR and its contents on first use (standard behavior of the URLClassLoader). Replacing the JAR at runtime requires extra work, and sometimes even that is not possible without incurring some sort of memory leak (see the the various Leak Preventers that Jetty ships with for some hidden nasties in this area). Be prepared for OOM or other issues if you rely on this.
Now, with that out of the way ...
Hot Deployment on Jetty works by detecting/scanning for changes in the webapp and performing a webapp restart.
This works great with content, like html, js, css, etc.
Project JAR dependencies, which will wind up as part of the WEB-INF/lib structure, are part of the Jetty WebAppContext's [WebAppClassLoader].
This WebAppClassLoader is populated from information provided by Maven's artifact resolution system, which on a normal command line build resolves to content via the Maven local repository system. If you are using maven from Eclipse, the resolution of these artifacts might be other projects in your Eclipse workspace (more on this later)
To demonstrate, this is the minimal configuration for scanning for changes every 2 seconds on your webapp.
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.0.v20131115</version>
<configuration>
<scanIntervalSeconds>2</scanIntervalSeconds>
<webAppConfig>
<contextPath>/</contextPath>
</webAppConfig>
</configuration>
</plugin>
Lets say you have a dependant project, a jar file under the maven artifact coordinates of com.company:component:jar:1.0-SNAPSHOT.
That means the WebAppContext was loaded with a WebAppClassLoader reference to a URL of file://${user.dir}/.m2/repository/com/company/component/1.0-SNAPSHOT/component-1.0-SNAPSHOT.jar and only changes to that file will cause a hot deploy / reload.
Its simple enough on a command line in your /component/ directory to just issue a mvn clean install and see your webapp reload, but under Eclipse and its m2e plugin, a code change to the component project does not automatically represent a change to the jar file in your local repository.
In fact, m2e can be configured to swap out maven artifact references via the local repository for ones in your eclipse workspace. You need to be aware of theses settings to have success with your hot deploy / reload efforts.
Tip for figuring out your active WebAppClassloader contents
Add the following file to your war project.
src/main/jetty/dump.xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Set name="dumpAfterStart">true</Set>
</Configure>
And change your jetty-maven-plugin configuration to add ...
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
...
<jettyXml>src/main/jetty/dump.xml</jettyXml>
</configuration>
</plugin>
Now when your server starts, look for the extra output, particularly the WebAppClassLoader references.
...(snip)...
| | |
| | +> WebAppClassLoader=Web App Live#39714203
| | | +- file:/home/joakim/code/stackoverflow/samples/webapp-live/target/classes/
| | | +- file:/home/joakim/.m2/repository/org/eclipse/jetty/demo/component/1.0-SNAPSHOT/component-1.0-SNAPSHOT.jar
| | | +- ClassRealm[plugin>org.eclipse.jetty:jetty-maven-plugin:9.1.0.v20131115, parent: sun.misc.Launcher$AppClassLoader#77fe0d66]
...(/snip)...
You can see that my jetty:run has a reference to the component via the local repository.
I'm facing a very unique situation and need some advice:
I'm working on a project which depends on an other project from my same company and now I need to apply some modifications to the dependency.
The problem which I have is that the source code from the dependency has been lost, so the only thing I have is a maven dependency in the repository, with the corresponding jar file.
On top of that, some of the classes in the Jar file where created using JiBX parser, mapping some XSD files which I neither have, and the resulting classes are synthetic and I found no decompiler able to handle them properly.
The only good thing of all of that is that the class which I need to change can be properly decompiled, so went for the following:
I decompiled the whole jar file and ended up with some classes (the
JiBx ones) with empty or wrongly implemented methods.
I commented out the body of the wrong methods to have stub objects, applied the required changes to the right classes and recompiled.
I took the old Jar file, opened it and manually replaced the old class with the new one.
And the resulting Jar worked as expected.
Now my question is: Can I do all of that using Maven?
The idea would be to put the JiBX class files as resources, and keep the stub equivalents as source files and then let maven:
Compile everything as usual, putting all the compiled class files
into target folder
Remove stub class files from target folder and replace them with the old precompiled class files
package the jar.
Which approach would you recommend?
UPDATE
I give some more details about the dependency project structure:
All classes are inside the same package:
my.project.domain.JiBX__c_GeneratedObfuscatedClass1.java
my.project.domain.JiBX__c_GeneratedObfuscatedClass2.java
my.project.domain.JiBX__c_GeneratedObfuscatedClass3.java
my.project.domain.CustomizableClass1.java
my.project.domain.CustomizableClass2.java
my.project.domain.CustomizableClass3.java
JiBX classes are not imported properly as dependency and if I try to put any of the CustmizableClasses into the project source and let the JiBX ones be in a dependency, the compiler reports missing methods.
I also tried using the Shade Plugin as suggested, but since I need to include the JiBX classes into my source path, I will end up having to include into package JiBX classes from jar dependency and compiled CustomizableClasses, but skipping CustomizableClasses from jar dep and compiled JiBX classes.
I looks like it can work, but I admit that I still didn't find the way of doing it.
Any clues will be very welcomed.
UPDATE 2 (RESOLUTION)
I explain here how I finally managed this using the shade plugin as suggested, just in case someone else needs to do the same:
I finally created a project with the decompiled classes inside the same package, and left the methods which didn't want to be decompiled commented out.
In the pom.xml I added the following:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>${project.groupId}:${project.artifactId}</include>
<include>TheDamnedProject:WithoutSources</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>TheDamnedProject:WithoutSources</artifact>
<includes>
<!-- These classes will be taken directly from dependency JAR -->
<include>my/package/ClassWhichCouldNotBeDecompiled1.class</include>
<include>my/package/ClassWhichCouldNotBeDecompiled2.class</include>
<include>my/package/ClassWhichCouldNotBeDecompiled3.class</include>
<include>my/package/ClassWhichCouldNotBeDecompiled4.class</include>
</includes>
</filter>
<filter>
<artifact>${project.groupId}:${project.artifactId}</artifact>
<excludes>
<!-- These classes will be overridden by the ones inside the JAR -->
<exclude>my/package/ClassWhichCouldNotBeDecompiled1.class</exclude>
<exclude>my/package/ClassWhichCouldNotBeDecompiled2.class</exclude>
<exclude>my/package/ClassWhichCouldNotBeDecompiled3.class</exclude>
<exclude>my/package/ClassWhichCouldNotBeDecompiled4.class</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
thanks!
Carles
Here's how I would do that:
Create a new Maven project for this Jar file, with packaging type jar
Include the original Jar file as a dependency
Add the one decompiled .java file in the src folder
This should get you to a point where the .java file can be compiled, since the other classes from the jar file are available.
You now have two Jar files: one original, and one that should just contain the single recompiled and changed class.
Adding both to your application class path might work, but will depend on the order on the classpath.
If you want to end up with one jar file, I recommend to take a look at the Maven Shade Plugin (http://maven.apache.org/plugins/maven-shade-plugin/), which will allow you to create a new Jar file with contents from multiple sources. It will allow you to filter what goes into the new Jar file.
The Maven Shade plugin allows you to specify which classes from each artifact are included. It uses wildcards and include/exclude tags for this, as described here: http://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html
Once that Jar file is created, I would release it using the Maven Release plugin, and then include that artifact downstream. This will allow you to only update the patched Jar when it is really required, it probably doesn't have to be on every build. But that depends on your usage pattern.
For the version number of the new Jar file, I recommend to use a variation of the original one. Use the same groupId and artifactId, then modify the version number. If the original has 1.0.2, your new, patched file should be released as 1.0.2-1, to indicate that it's based on the 1.0.2 sources. If you need to make an additional change, release that as 1.0.2-2 and so on. This will make it easy to understand which version your patches are based on, and the incrementing patch number will give you a means to distinguis the releases.
I am getting the following error when I run my playN project.
"No file found for: /myproject/myproject.nocache.js"
Also I am getting only a black screen in the browser.
In the MyProjectHtml.java file I am giving the path as
"platform.assets().setPathPrefix("myproject/");"
How can I resolve this problem. I am not finding any file with the name "nocache".
Note: The comment in one of my previous question's answer will be useful: How to Run my playN game in production mode locally?
Thank you.
SOLVED: the resource folder under war was getting generated using eclipse compile only.I have created a source folder src/main/resources and moved all my resources package to it. Before it was under src/main/java. Now it works..! I can compile from terminal and run.
Are you running the project via Maven (mvn test -Ptest-html) or as GWT project (mvn gwt:run)?
The first case should work if your path is set correctly, but running it as a GWT project has always failed for me.
I also suggest doing a mvn clean install, and seeing which resources are contained within your .war file. Your .nocache.js file should be in there, if not, you probably have a bigger issue (incorrect project setup).
Update:
Seeing as you don't have the .nocache.js file in your war something is wrong with your Maven configuration. See if the following config has been added to your HTML pom in your plugins tags:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
Either way, your HTML version won't run until you see the .nocache.js in your war file. Double-check your Maven configuration with a new PlayN project, and see where there are differences.
I have project which builds .war file with maven. There is standard src/main/webapp directory. I have also some GWT code there which is compiled by GWT maven plugin. Sometimes I run GWT application from Eclipse, then GWT Eclipse plugin compiles it to src/main/webapp/app.policy (app.policy is name of my GWT module). This is OK.
app
|-src/main/webapp
| |-app.policy (directory created by Eclipse GWT plugin)
|target
|-app-1.0-SNAPSHOT (directory created by Maven while building war)
| |-app.policy
|-app-1.0-SNAPSHOT.war
If src/main/webapp/app.policy does not exist, gwt-maven-plugin creates target/app-1.0-SNAPSHOT/app.policy and it is included in WAR. This is desired behavior.
The problem is if src/main/webapp/app.policy exists. Then it is copied to target/app-1.0-SNAPSHOT/app.policy and is not fully overwritten by what gwt-maven-plugin creates. Can I somehow exclude src/main/webapp/app.policy from being copied to target/app-1.0-SNAPSHOT directory?
I tried <warSourceExcludes>, but it doesn't work. It makes app.policy not go into .war, which is not what I want. I want it in .war, but I want it to be created by maven-gwt-plugin, not copied from src/main/webapp.
Try to exclude the file from maven resources:
<build>
...
<resources>
<resource>
<directory>src/main/webapp</directory>
<excludes>
<exclude>app.policy</exclude>
</excludes>
</resource>
...
</resources>
...
</build>
If this works then you can add this configuration to a maven profile.