Keep resource file on root level in repackaged JAR file - java

I'm using the Spring Boot Maven Plugin in my pom.xml and more precisely the repackage goal to create an executable jar: https://docs.spring.io/spring-boot/docs/1.4.1.RELEASE/maven-plugin/examples/repackage-classifier.html
This moves all application classes under BOOT-INF/classes in the JAR file.
In my case I have a file under my src/main/resources path, let's say it's src/main/resources/my-file.txt.
In a normal JAR file the above my-file.txt would be placed at root level in the JAR.
When I repackage the JAR however, the file goes to BOOT-INF/classes/my-file.txt. This is a problem for me as I really need this file on root level in the JAR.
Is there a way to achieve what I'm looking for with maven somehow as I don't want to have to manually insert the file on root level into the JAR with a command afterwards?
Thanks!

Related

Is there a way to get the relative path from a jar of a jar?

I have a requirement where I want to find the path of a jar that is inside the running jar. Let's say there is a jar called example-1.0.0.jar inside a running jar called main-1.0.0.jar. I want to know the path of that jar that is present inside the running jar.
Edit 1:
For example, the jar is a dependency in the project. For example, let's say I have a log4j dependency in my project and I want to know the path of the log4j jar from a class. How can I get the path?
A jar is just a ZIP file. So once you know how to access the 'running' jar, open it using ZipFile and scan it for the entry you like. Once you have the entry you also know the path inside the ZIP.
If by 'running jar' you mean something on the classpath you could use any classes' getClassLoader().getResource() method but in this case you'd have to know the path to the contained jar upfront.

How do I package this maven project or Java Application?

I'm creating a new project that run as a Java application(.jar), but I am confused about how to package the lib folder into the final jar file.
And I try to use Maven, but did not found some eligable plugins.
The project structure is here
first, I try to package with IDEA's build Artifact. it will extract all jar file into final jar and create a MANIFEST file, but the impact is there are some file like "*.SF, *.RSA", it destory the java -jar xxx.jar, But we can solve it by delete these .sf/.rsa file. Next problem occur, cause I use some springframework dependency, when extract these jar file, they will create a file like spring.handles, but its not complete.
second, I try to use MAVEN. I use the maven-jar-plugin maven-compiler-plugin maven-dependency-plugin to copy all jar file into final jar, and create the correct MANIFEST file. BUT a java.lang.NoClassDefFoundError occur, I am DEAD!!!
So, the actual question is how can I package the lib folder into final executable jar???

java relative file path issue in dependant projects

I've a maven project called Project_1. In this project I've a file reader which reads a config file(using relative path) from resources folder(which is sourced) of this project. I've another maven project called Project_2 in which Project_1 is added as dependency. When I'm running the Project_2 now, the relative path for reading config file is not working as ClassPath is set based on Project_2. Could anyone please help me to use proper file path which works in any condition.
NOTE: I don't want to use absolute file path, as I want these projects to be portable. Project_2 alone is customer facing and config file is specific to Project_1 which is not allowed to be configured by customer facing application.

ClassNotFoundException when using a self-created jar file

Using Eclipse I created some parser classes I want to provide to another project as a jar archive for validation purposes. So the parser project look like this:
ParserProject
- src
-- com.package.x
--- ClassA
--- ClassB
- lib
-- external1.jar
-- external2.jar
The ClassA and ClassB use the external jar archives, like Jackson or some Apache commons. To provide the functionality to another project, I exported the entire project as jar archive and executable jar archive (Right click on project > Export... > Java > JAR file > Select all files and "Export generated class files and resources" > Finish).
The jar file is created without any errors. When I use the parserproject.jar in my validation project, I can access all my methods using auto completion, but when I run the validation project, I get a java.lang.ClassNotFoundException: com.fasterxml.jackson.core.JsonParseException.
Now three strange things:
All jackson jars are included in the parser project. Besides, I can run a main() method in the parser project and everything works fine, no ClassNotFoundException occurs.
When I add the parserproject.jar to my validation project in the class path and open the jar archive in the Package Explorer, the parserproject.jar seems to contain all jars it needs.
For the executable jar archive, all required external jars are contained in the MANIFEST.MF (Package Explorer > validation project > Referenced Libraries > + besides parserproject.jar > META-INF > MANIFEST.MF). It looks like this:
Manifest-Version: 1.0
Rsrc-Class-Path: ./ json-20140107.jar jackson-annotations-2.5.4.jar ja
ckson-core-2.5.4.jar jackson-databind-2.5.4.jar commons-io-2.4.jar co
mmons-validator-1.3.1.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.5.jar
json-schema-validator-2.2.6.jar jackson-module-jsonSchema-2.4.4.jar
juniversalchardet-1.0.3.jar snakeyaml-1.15.jar commons-beanutils-1.7.
0.jar commons-digester-1.6.jar commons-logging-1.0.4.jar joda-time-2.
8.1.jar jopt-simple-4.6.jar jsr305-3.0.0.jar json-schema-core-1.2.5.j
ar libphonenumber-6.2.jar jackson-coreutils-1.8.jar commons-lang-2.6.
jar guava-16.0.1.jar msg-simple-1.1.jar btf-1.2.jar mailapi-1.4.3.jar
uri-template-0.9.jar
Class-Path: .
Rsrc-Main-Class: com.package.SchemeValidator
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
I get the exception if and only if I use the generated jar file in my validation project. In case I get rid of the parserproject.jar and define a dependency to the ecplise parser project instead (Right click on validation project > Properties > Java Build Path > Projects) I do not get the ClassNotFoundException.
So now my question is, how I should export the jar so that every class is found. Thank you!
Eclipse only takes care of the compile-time dependencies while generating a .jar
Since your generated .jar can be moved to virtually anywhere, the dependencies must again be present during execution time.
You have two options:
Execute your jar with the -jar option, while leaving all
dependencies in the same folder. Since your manifest uses "./" as classpath, this means all dependencies must be on the same directory you are executing your jar from. NOTE classpath is relative to the directory you are executing from, not the directory the file is on.
Execute your jar withour the -jar option, and specify the -cp option to point to the dependencies, and the specify the main class.
java -cp "<path to your jar>;<path to dependency 1>;<path to dependency 3>[;...]" <your main class>
You might consider creating a so called fat jar which will contain all the needed classes. For example: http://fjep.sourceforge.net/
If you do not want to go through the hassle of managing all the depencencies by yourself, consider using a build tool like
Maven https://maven.apache.org/ or Gradle https://gradle.org/.

Where is the correct location to put Log4j.properties in an Eclipse project?

Where in my Eclipse project should I add the log4j.properties file so that it will work as intended?
you can add it any where you want, when you run your project, configure the classpath and add the location of the log4j.properties files by clicking on:
Run->Run Configuration -> [classpath tab] -> click on user Entries -> Advanced -> Select Add Folder -> select the location of your log4j.properties file
and then -> OK -> run
and it should get loaded
The safest way IMO is to point at the file in your run/debug config
-Dlog4j.configuration=file:mylogging.properties
! Be aware: when using the eclipse launch configurations the specification of the file: protocol is mandatory.
In this way the logger will not catch any logging.properties that come before in the classpath nor the default one in the JDK.
Also, consider actually use the log4j.xml which has a richer expression syntax and will allow more things (log4j.xml tahe precedence over log4j.properties.
Add the log4j.properties file to the runtime class path of the project.
Some people add this to the root of the source tree (so that it gets copied to the root of the compiled classes).
Edit:
If your project is a maven project,
you can put the log4j.properties in the src/main/resources folder (and the src/test/resources for your unit tests).
If you have multiple environments (for example development and production),
want different logging for each environment,
and want to deploy the same jar (or war, or ear) file to each environment
(as in one build for all environments)
then store the log4j.properties file outside of the jar file and put it in the class path for each environment (configurable by environment).
Historically, I would include some known directory in each environment in the classpath and deploy environment specific stuff there.
For example,
~tomcat_user/localclasspath where ~tomcat_user is the home directory of the user that will be running the tomcat instance to which my war file will be deployed.
The best way is to create special source folder named resources and use it for all resource including log4j.properties. So, just put it there.
On the Java Resources folder that was automatically created by the Dynamic Web Project, right click and add a new Source Folder and name it 'resources'. Files here will then be exported to the war file to the classes directory
If you have a library and you want to append the log4j:
Create a folder named "resources" in your projet.
Create a .properties file named log4j
Set properties in log4j.properties file
Push right button in the project and go to properties->Java Build Path and, finally, go to the "Source" tab.
Push Add folder and search the "resources" folder created in step 1.
Finish.
(I have assumed that you have the log4j library added.)
PD: Sorry for my english.
This question is already answered here
The classpath never includes specific files. It includes directories and jar files. So, put that file in a directory that is in your classpath.
Log4j properties aren't (normally) used in developing apps (unless you're debugging Eclipse itself!). So what you really want to to build the executable Java app (Application, WAR, EAR or whatever) and include the Log4j properties in the runtime classpath.
Put log4j.properties in the runtime classpath.
This forum shows some posts about possible ways to do it.
I'm finding out that the location of the log4j.properties file depends on the type of Eclipse project.
Specifically, for an Eclipse Dynamic Web Project, most of the answers that involve adding the log4j.properties to the war file do not actually add the properties file in the correct location, especially for Tomcat/Apache.
Here is some of my research and my solution to the issue (again specifically for a Dynamic Web Project running on Tomcat/Apache 6.0)
Please refer to this article around how Tomcat will load classes. It's different than the normal class loader for Java. (https://www.mulesoft.com/tcat/tomcat-classpath) Note that it only looks in two places in the war file, WEB-INF/classes and WEB-INF/lib.
Note that with a Dynamic Web Project, it is not wise to store your .properties file in the build/../classes directory, as this directory is wiped whenever you clean-build your project.
Tomcat does not handle .property files in the WEB-INF/lib location.
You cannot store the log4j.properties file in the src directory, as Eclipse abstracts that directory away from your view.
The one way I have found to resolve this is to alter the build and add an additional directory that will eventually load into the WEB-INF/classes directory in the war file. Specifically....
(1) Right click your project in the project explorer, select 'New'->'Folder'. You can name the folder anything, but the standard in this case is 'resources'. The new folder should appear at the root level of your project.
(2) Move the log4j.properties file into this new folder.
(3) Right click the project again, and select 'Build-Path'->'Configure Build Path'. Select the 'Sources' tab. Click the 'Add Folder' button. Browse to find your new folder you created in step (1) above. Select 'OK'.
(4) Once back to the eclipse Project Explorer view, note that the folder has now moved to the 'Java Resources' area (ie it's no longer at the root due to eclipse presentation abstraction).
(5) Clean build your project.
(6) To validate that the .properties file now exists in WEB-INF/classes in your war file, export a war file to an easy location (right click Project -> Export -> War file) and checkout the contents. Note that the log4j.properties file now appears in the WEB-INF/classes.
(7) Promote your project to Tomcat/Apache and note that log4j now works.
Now that log4j works, start logging, solve world problems, take some time off, and enjoy a tasty adult beverage.
You do not want to have the log4j.properties packaged with your project deployable -- that is a bad idea, as other posters have mentioned.
Find the root Tomcat installation that Eclipse is pointing to when it runs your application, and add the log4j.properties file in the proper place there. For Tomcat 7, the right place is
${TOMCAT_HOME}/lib
In general I put it in a special folder "res" or "resources as already said, but after for the web application, I copy the log4j.properties with the ant task to the WEB-INF/classes directory. It is the same like letting the file at the root of the src/ folder but generally I prefer to see it in a dedicated folder.
With Maven, the usual place to put is in the folder src/main/resources as answered in this other post.
All resources there will go to your build in the root classpath (e.g. target/classes/)
If you want a powerful logger, you can have also a look to slf4j library which is a logger facade and can use the log4j implementation behind.
For a normal (non maven and non web) java project in eclipse.
Create a "source" folder with new options and with any name (as a standard we can name it as resources) under the project directory
push the log4j.properties file to this "source" folder.
Build and run the application.

Categories