Must I unpack a war file to run a single class? [duplicate] - java

I have a Java class which has a main and I used to run as a standalone app from the command line e.g.
java -jar myjar.jar params
I needed to repackage the code to run under apache and all my code, including the entry point class from the old jar, has ended up in a WAR file for easy deplyment into the web server.
However, I still want to be able to run it from the command line and the code has not changed and is all in there, I just can't figure out how to get it to run.
Here's what I tried...
I presumed the WAR was just like a jar, so
java -jar mywar.war params
That failed saying there was no main class defined in the manifest.
I manually added a manifest to the war and tried again, with the same effect.
I noticed that in my war I had a folder called META-INF containing a manifest.mf, so I added a line to that declaring my main class as I would to a normal manifest...
Manifest-Version: 1.0
Main-Class: mypackage.MyEntryPointClass
This gave a noClassDefFoundError mypackage.MyEntryPointClass, which is progress of a sort. That led me to believe that it was just a path issue, so I tried
Manifest-Version: 1.0
Main-Class: WEB-INF.classes.mypackage.MyEntryPointClass
I now get the same error, but with a stack trace...
Exception in thread "main" java.lang.NoClassDefFoundError: WEB-INF/classes/mypackage/MyEntryPointClass (wrong name: mypackage/MyEntryPointClass)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
I've googled for a bit but can't find anything which answers my question, and I read a couple of other questions here which are slightly different, so I thought I would post.
Java 1.5, not that I think that should make any difference.

Similar to what Richard Detsch but with a bit easier to follow (works with packages as well)
Step 1: Unwrap the War file.
jar -xvf MyWar.war
Step 2: move into the directory
cd WEB-INF
Step 3: Run your main with all dependendecies
java -classpath "lib/*:classes/." my.packages.destination.FileToRun

You can do what Hudson (continuous integration project) does.
you download a war which can be deployed in tomcat or to execute using
java -jar hudson.war
(Because it has an embedded Jetty engine, running it from command line cause a server to be launched.) Anyway by looking at hudson's manifest I understand that they put a Main class in the root for the archive. In your case your war layout should be look like:
under root:
mypackage/MyEntryPointClass.class
WEB-INF/lib
WEB-INF/classes
META-INF/MANIFEST.MF
while the manifest should include the following line:
Main-Class: mypackage.MyEntryPointClass
please notice that the mypackage/MyEntryPointClass.class is accessable from the command line only, and the classes under WEB-INF/classes are accessable from the application server only.
HTH

A war is a webapp. If you want to have a console/standalone application reusing the same classes as you webapp, consider packaging your shared classes in a jar, which you can put in WEB-INF/lib. Then use that jar from the command line.
Thus you get both your console application, and you can use the same classes in your servlets, without making two different packages.
This, of course, is true when the war is exploded.

If you're using Maven, just follow the maven-war-plugin documentation about "How do I create a JAR containing the classes in my webapp?": add <attachClasses>true</attachClasses> to the <configuration> of the plugin:
<project>
...
<artifactId>mywebapp</artifactId>
<version>1.0-SNAPSHOT</version>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
The you will have 2 products in the target/ folder:
The project.war itself
The project-classes.jar which contains all the compiled classes in a jar
Then you will be able to execute a main class using classic method: java -cp target/project-classes.jar 'com.mycompany.MainClass' param1 param2

To execute SomeClass.main(String [] args) from a deployed war file do:
Write class SomeClass.java that has a main method method i.e. (public static void main(String[] args) {...})
Deploy your WAR
cd /usr/local/<yourprojectsname>/tomcat/webapps/projectName/WEB-INF
java -cp "lib/jar1.jar:lib/jar2.jar: ... :lib/jarn.jar" com.mypackage.SomeClass arg1 arg2 ... arg3
Note1: to see if the class SomeOtherClass.class is in /usr/tomcat/webapps/<projectName>/WEB-INF/lib run:
cd /usr/tomcat/webapps/projectName/WEB-INF/lib &&
find . -name '*.jar' | while read jarfile; do if jar tf "$jarfile" | grep SomeOtherClass.class; then echo "$jarfile"; fi; done
Note2: Write to standard out so you can see if your main actually works via print statements to the console. This is called a back door.
Note3: The comment above by Bozhidar Bozhanov seems correct

The rules of locating classes in an archive file is that the location of the file's package declaration and the location of the file within the archive have to match. Since your class is located in WEB-INF/classes, it thinks the class is not valid to run in the current context.
The only way you can do what you're asking is to repackage the war so the .class file resides in the mypackage directory in the root of the archive rather than the WEB-INF/classes directory. However, if you do that you won't be able to access the file from any of your web classes anymore.
If you want to reuse this class in both the war and outside from the java command line, consider building an executable jar you can run from the command line, then putting that jar in the war file's WEB-INF/lib directory.

In Maven project, You can build jar automatically using Maven War plugin by setting archiveClasses to true. Example below.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>

the best way if you use Spring Boot is :
1/ Create a ServletInitializer extends SpringBootServletInitializer Class
. With method configure which run your Application Class
2/ Generate always a maven install WAR file
3/ With this artefact you can even :
. start application from war file with java -jar file.war
. put your war file in your favorite Web App server (like tomcat, ...)

Well, according to Wikipedia, with a WAR file, the classes that get loaded into the classpath are in the "/WEB-INF/classes" and "/WEB-INF/lib" directory.
You could try simply putting a copy of the classes on the root file system of the zip file (which is what a war/jar is). I'm not sure if that would work though.
You can always just create two separate files.

As an alternative option, include into the war file, the rest service to trigger the application logic via url. Deploy the war file onto any web/application server you want.
Then you can start your application via any command-line based HTTP client like curl on Linux.
The disadvantage: usually these HTTP clients are different on different OSs. Which is not critical for a lot of cases. Also you can install curl on Windows.

It's not possible to run a java class from a WAR file. WAR files have a different structure to Jar files.
To find the related java classes, export (preferred way to use ant) them as Jar put it in your web app lib.
Then you can use the jar file as normal to run java program. The same jar was also referred in web app (if you put this jar in web app lib)

Related

Cannot get my features files recognized by aws device farm

I am having an issue running my cucumber project with device farm.
I am getting this error:
[TestNG] Caused by: java.lang.IllegalArgumentException: Not a file or directory: /tmp/scratchheDEgq.scratch/test-packagex5ZhYf/src/test/java/cucumber/features
I understand from this message that there is an issue with the path of the features directory in my project but locally it works.
This is how I put it in my code:
#CucumberOptions(features = "src/test/java/cucumber/features", glue = "cucumber.steps")
Should I provide a different path to device farm? What am I missing here?
Thanks
By default the src/test/java/cucmber directory(if it exists in the project) is not included the *-test.jar file. Try putting the feature files in the src/test/resources directory as shown in the Device Farm sample project.
https://github.com/aws-samples/aws-device-farm-appium-cucumber-tests-for-sample-app/tree/master/src/test/resources/LoginTest
Alternatively, you can implement the testResources tags in the pom.xml to explicitly reference another directory besides src/test/resources assuming that we're using maven:
<testResources>
<testResource>
<directory>${project.basedir}/src/test/YOUR_DIRECTORY_HERE</directory>
</testResource>
</testResources>
Check out this link for more info on the testResources tag
https://maven.apache.org/pom.html#Resources
testResources: The testResources element block contains testResource elements. Their definitions are similar to resource elements, but are naturally used during test phases. The one difference is that the default (Super POM defined) test resource directory for a project is ${basedir}/src/test/resources. Test resources are not deployed.
HTH
-James

Where exactly do I put project-defaults.yml?

I'm working on a Wildfly Swarm project (using Wildfly Swarm version 2017.8.1, Maven 3.5.0, OpenJDK 1.8.0_141) where users will often upload files WAY bigger than Undertow's default 10485760 bytes (10MB) max-post-size setting.
I see from other questions that what I need to change is the key swarm.undertow.servers.default-server.http-listeners.default.max-post-size.
To try this setting out, I put it on the command line when I start the jar:
java -jar project-swarm.jar -Dswarm.undertow.servers.default-server.http-listeners.default.max-post-size=4000000000
This worked. The following also works if I want to run it using the Wildfly Swarm maven plugin:
mvn wildfly-swarm:run -Dswarm.undertow.servers.default-server.http-listeners.default.max-post-size=4000000000
Using either of the above two commands I can upload files bigger than 10485760 bytes (10MB). The next step is to make this the default so that I don't have to pass it in via command line each time. The official Wildfly Swarm configuration documentation said that I should put the undertow setting in a project-defaults.yml file. This is what that looks like for me:
swarm:
undertow:
servers:
default-server:
http-listeners:
default:
max-post-size: 4000000000
The thing is, none of that documentation says WHERE the file should ultimately end up. Should it end up as part of the war, under WEB-INF/classes, or the root of the war, or somewhere else? From the wildfly-swarm examples repo on github, usually the project-defaults.yml file is insrc/main/resources`, which is where I had it originally. However, it didn't work for me. Any attempts to upload a file bigger than 10485760 bytes (10MB) fail.
I found out that anything in a maven project that is put into src/main/resources gets put into the war file's /WEB-INF/classes (and the war file itself is wrapped by the swarm jar). So, I updated my maven pom so that the project-defaults.yml would be stored in the base directory of the war file itself. This STILL didn't work.
Next, I tried putting project-defaults.yml in the swarm jar itself, rather than the enclosed war. Yet again, I could not break past the 10485760 bytes (10MB) max-post-size default.
Finally, I tried using the command line option to refer to an external yml file, like so:
java -jar project-swarm.jar -s../src/main/root-resources/project-defaults.yml
This loaded the file, but alas I was STILL STUCK at the default max-post-size of 10485760 bytes (10MB).
At this point, I'm stumped. My project-defaults.yml file might be wrong or I'm not putting it in the right location. How do I fix this so I can upload files bigger than 10485760 bytes (10MB) and specify it via the project-defaults.yml file?
For those searching for an answer to this question, you have two alternatives for placing project-defaults.yml in your project.
Use Default Location
src/main/resources/project-defaults.yml
Use Maven Resource Declaration
Place the file somewhere else, for example: src/main/java/project-defaults.yml
Then, declare it as a resource using maven inside of the build section like so:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>project-defaults.yml</include>
</includes>
</resource>
</resources>
</build>

Executable JAR ignores its own Class-Path attribute

I used the instructions found at Maven - how can I add an arbitrary classpath entry to a jar to add an arbitrary entry to the Class-Path attribute. Here is my MANIFEST.MF file:
Manifest-Version: 1.0
Class-Path: jace-runtime.jar
Main-Class: org.jace.examples.Test
I defined org.jace.examples.Test as follows:
public class Test
{
public static void main(String[] args)
{
System.out.println("classpath: " + System.getProperty("java.class.path"));
System.out.println("PeerExample: " + Class.forName("org.jace.util.ShutdownHook"));
}
}
where org.jace.util.ShutdownHook is defined in jace-runtime.jar. When I invoke java -jar peer_example1.jar I get the following output:
classpath: peer_example1.jar
Exception in thread "main" java.lang.ClassNotFoundException: org.jace.util.ShutdownHook
In other words, Java is adding the executable JAR file to the classpath but ignoring Class-Path. If I invoke java -cp jace-runtime.jar;peer_example1.jar org.jace.examples.Test I get the expected output:
classpath: jace-runtime.jar;peer_example1.jar
Any ideas?
Answering my own question:
Adding arbitrary entries to Class-Path is fine on its own. The problem arises when you enable JAR indexing using:
<configuration>
<archive>
<index>true</index>
</archive>
</configuration>
Maven will omit your entries from META-INF/INDEX.LIST.
When you use the JAR at runtime, Java will look at INDEX.LIST for finding classes, not MANIFEST.MF.
Because your entries are missing from INDEX.LIST, they will not be found by the classloader, no matter what the manifest says.
A simple workaround is to disable JAR indexing. I'm not sure how to inject an arbitrary Class-Path with indexing enabled.
For those that may otherwise be unaware, the executable archive mechanism takes the manifest classpath and uses it to load classes external to the archive.
So if you are expecting a WAR with a manifest classpath of WEB-INF/classes to find classes in the WEB-INF/classes entry inside the archive then you will be disappointed.
Per the tooldocs page for the jar option - Link to docs
When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.

java.lang.ClassNotFoundException when running java -jar

I'm using ant to build my build.xml file, it compiles ok, but then getting a runtime java.lang.NoClassDefFoundError when running the resulting jar via "java -jar my_jar.jar". It seems like this comes up a lot but none of the related questions' solutions worked for me.
My classpath for javac contains only "/usr/local/lib/libthrift.jar" and the main .java file imports a bunch of thrift packages such as org.apache.thrift.transport.TTransportException.
When I try running the program via:
java -jar MyClass.jar
, I get the error:
Exception in thread "main" **java.lang.NoClassDefFoundError**: org/apache/thrift/transport/TTransportException
Caused by: java.lang.ClassNotFoundException: org.apache.thrift.transport.TTransportException
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
Could not find the main class: **MyClass**. Program will exit.
Here are the things I've tried so far that don't work:
adding a flag on the command line like "java -cp /usr/local/lib/libthrift.jar -jar my_jar.jar", the result is the same error as above
adding <attribute name="Class-Path" value="./:/usr/local/lib/libthrift.jar"/> inside my jar's manifest> tag, the result is the same error as above
adding -Xbootclasspath/a:/usr/local/lib/libthrift.jar:./ to the java command line. it solves the first error but a different error comes up:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logger
at org.apache.thrift.transport.TServerSocket.<clinit>(TServerSocket.java:36)
at MyClass.start(Unknown Source)
at MyClass.main(Unknown Source)
EDIT:
If I comment out the code that instantiates the missing classes but leave the imports, the code executes fine.
EDIT:
I moved my java classes to a server and referenced the MainClass with the server in the manifest attribute, but that didn't fix anything.
Could not find the main class: MyClass
The error seems actually related to your MANIFEST which:
may not have a complete classpath Class-Path: see this HowTo
The best solution when you have a jar is to try to include the required jars into the manifest declaration.
Manifest-Version: 1.0
Class-Path:
customer_client.jar
mailer_client.jar
signon_client.jar
or may not define adequately the MainClass within your 'my_jar.jar'.
See this HowTo:
<target name="jar" depends="compile">
<delete file="hello.jar"/>
<delete file="MANIFEST.MF"/>
<manifest file="MANIFEST.MF">
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-Class" value="howto.Hello"/>
</manifest>
<jar destfile="hello.jar"
basedir="."
includes="**/*.class"
manifest="MANIFEST.MF"
/>
</target>
the <attribute name="Main-Class" value="howto.Hello"/> needs to specify the full path (packages) of the MainClass, not just MainClass.
If your main class is in the default package (the unnamed package), I am not sure it can be referenced by the loader (see this SO question)
So move your JarRunner into a package, and declare it appropriately in the <attribute name="Main-Class" value="myPackage.JarRunner"/> element.
You need to specify all the other jars that are required in your classpath in the manifest file before you can execute java -jar my-test.jar, here is a copy of one of my manifest files. With all these entries in the manifest I can specify java -jar db_field_cleaner.jar and all the other jars are inlined into the classpath :
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: James B
Build-Jdk: 1.6.0_01
Package: com.blah.dbfieldcleaner
Specification-Title: db_field_cleaner
Specification-Version: 2.5.7-SNAPSHOT
Implementation-Title: db_field_cleaner
Implementation-Version: 2.5.7-SNAPSHOT
Implementation-Vendor-Id: com.blah.dbfieldcleaner
Implementation-Vendor:
Main-Class: com.blah.dbfieldcleaner.main.Main
mode: development
url: ..\..\db_field_cleaner\target\site
Class-Path: log4j-1.2.14.jar cygna_commons-2.5.7-SNAPSHOT.jar mail-1.4
.jar activation-1.1.jar jdic-0.9.5.jar jdic_native-0.9.5.jar jdic_plu
s-0.2.2.jar jdic_plus_native-0.2.2.jar jtds-1.2.2.jar xstream-1.3.1.j
ar xpp3_min-1.1.4c.jar commons-net-2.0.jar text_processing-2.5.7-SNAP
SHOT.jar
Alternatively, use Maven, it's loads better at this kind of stuff!
You had given answer yourself :-) add all the jars to your runtime classpath.As you said earlier *.jar solved one problem but loggers are not able to find out, so add log4j.jar to the path. Basically the idea is add all the jars required for running in to classpath.
The command line options for java can be found here.
The -jar and -cp/-classpath options are mutually exclusive. The -jar option requires the use of a manifest and the relative paths to dependencies should be listed in this file. But essentially, the manifest is an optional mechanism - you can specify the required information externally at bootstrap time. If the manifest is causing you problems, don't use one.
I would test that you have you have located all your dependencies with a command like this:
java -cp /usr/local/lib/libthrift.jar:my_jar.jar MyClass
Note that the compiler may successfully compile your classes even if all the classes that might be required at runtime are not present. Compilation will succeed if the direct dependencies of your classes are present. The dependencies of your dependencies are not necessary to create the binary and the compiler will not inspect them needlessly.
The message about org/apache/log4j/Logger suggests that you have a missing dependency on log4j. It will be necessary to add this library to the classpath. Check the documentation for the Thrift library to determine its dependencies.
The class path references in the manifest file are relative refs. Just to debug, you might want to copy all the jars into the same location as my_jar.jar and attempt it again.
reference :
http://www.rgagnon.com/javadetails/java-0587.html
You might try adding the jars to the domain of the server. I had a similar problem and this worked for me when I was running it on glassfish. I would get those not found exceptions. Eclipse recognized it and it compiled fine but when ran on the server it couldn't find the file. Try adding it to whatever lib directory the server is installed to.
This is the problem that is occurring,
if the JAR file was loaded from "C:\java\apps\appli.jar", and your manifest file has the Class-Path: reference "lib/other.jar", the class loader will look in "C:\java\apps\lib\" for "other.jar".  It won't look at the JAR file entry "lib/other.jar".
Solution:-
Right click on project, Select Export.
Select Java Folder and in it select Runnable JAR File instead of JAR file.
Select the proper options and in the Library Handling section select the 3rd option i.e. (Copy required libraries into a sub-folder next to the generated JAR).
Click finish and your JAR is created at the specified position along with a folder that contains the JARS mentioned in the manifest file.
open the terminal,give the proper path to your jar and run it using this command java -jar abc.jar
Now what will happen is the class loader will look in the correct folder for the referenced JARS since now they are present in the same folder that contains your app JAR..There is no "java.lang.NoClassDefFoundError" exception thrown now.
This worked for me... Hope it works you too!!!

What's the purpose of META-INF?

In Java, you often see a META-INF folder containing some meta files. What is the purpose of this folder and what can I put there?
From the official JAR File Specification (link goes to the Java 7 version, but the text hasn't changed since at least v1.3):
The META-INF directory
The following files/directories in the META-INF directory are recognized and interpreted by the Java 2 Platform to configure applications, extensions, class loaders and services:
MANIFEST.MF
The manifest file that is used to define extension and package related data.
INDEX.LIST
This file is generated by the new "-i" option of the jar tool, which contains location information for packages defined in an application or extension. It is part of the JarIndex implementation and used by class loaders to speed up their class loading process.
x.SF
The signature file for the JAR file. 'x' stands for the base file name.
x.DSA
The signature block file associated with the signature file with the same base file name. This file stores the digital signature of the corresponding signature file.
services/
This directory stores all the service provider configuration files.
New since Java 9 implementing JEP 238 are multi-release JARs. One will see a sub folder versions. This is a feature which allows to package classes which are meant for different Java version in one jar.
Generally speaking, you should not put anything into META-INF yourself. Instead, you should rely upon whatever you use to package up your JAR. This is one of the areas where I think Ant really excels: specifying JAR file manifest attributes. It's very easy to say something like:
<jar ...>
<manifest>
<attribute name="Main-Class" value="MyApplication"/>
</manifest>
</jar>
At least, I think that's easy... :-)
The point is that META-INF should be considered an internal Java meta directory. Don't mess with it! Any files you want to include with your JAR should be placed in some other sub-directory or at the root of the JAR itself.
I've noticed that some Java libraries have started using META-INF as a directory in which to include configuration files that should be packaged and included in the CLASSPATH along with JARs. For example, Spring allows you to import XML Files that are on the classpath using:
<import resource="classpath:/META-INF/cxf/cxf.xml" />
<import resource="classpath:/META-INF/cxf/cxf-extensions-*.xml" />
In this example, I'm quoting straight out of the Apache CXF User Guide. On a project I worked on in which we had to allow multiple levels of configuration via Spring, we followed this convention and put our configuration files in META-INF.
When I reflect on this decision, I don't know what exactly would be wrong with simply including the configuration files in a specific Java package, rather than in META-INF. But it seems to be an emerging de facto standard; either that, or an emerging anti-pattern :-)
The META-INF folder is the home for the MANIFEST.MF file. This file contains meta data about the contents of the JAR. For example, there is an entry called Main-Class that specifies the name of the Java class with the static main() for executable JAR files.
META-INF in Maven
In Maven the META-INF folder is understood because of the Standard Directory Layout, which by name convention package your project resources within JARs: any directories or files placed within the ${basedir}/src/main/resources directory are packaged into your JAR with the exact same structure starting at the base of the JAR.
The Folder ${basedir}/src/main/resources/META-INF usually contains .properties files while in the jar contains a generated MANIFEST.MF, pom.properties, the pom.xml, among other files. Also frameworks like Spring use classpath:/META-INF/resources/ to serve web resources.
For more information see How do I add resources to my Maven Project.
You can also place static resources in there.
In example:
META-INF/resources/button.jpg
and get them in web3.0-container via
http://localhost/myapp/button.jpg
> Read more
The /META-INF/MANIFEST.MF has a special meaning:
If you run a jar using java -jar myjar.jar org.myserver.MyMainClass you can move the main class definition into the jar so you can shrink the call into java -jar myjar.jar.
You can define Metainformations to packages if you use java.lang.Package.getPackage("org.myserver").getImplementationTitle().
You can reference digital certificates you like to use in Applet/Webstart mode.
Adding to the information here, the META-INF is a special folder which the ClassLoader treats differently from other folders in the jar.
Elements nested inside the META-INF folder are not mixed with the elements outside of it.
Think of it like another root. From the Enumerator<URL> ClassLoader#getSystemResources(String path) method et al perspective:
When the given path starts with "META-INF", the method searches for resources that are nested inside the META-INF folders of all the jars in the class path.
When the given path doesn't start with "META-INF", the method searches for resources in all the other folders (outside the META-INF) of all the jars and directories in the class path.
If you know about another folder name that the getSystemResources method treats specially, please comment about it.
Just to add to the information here, in case of a WAR file, the META-INF/MANIFEST.MF file provides the developer a facility to initiate a deploy time check by the container which ensures that the container can find all the classes your application depends on. This ensures that in case you missed a JAR, you don't have to wait till your application blows at runtime to realize that it's missing.
I have been thinking about this issue recently. There really doesn't seem to be any restriction on use of META-INF. There are certain strictures, of course, about the necessity of putting the manifest there, but there don't appear to be any prohibitions about putting other stuff there.
Why is this the case?
The cxf case may be legit. Here's another place where this non-standard is recommended to get around a nasty bug in JBoss-ws that prevents server-side validation against the schema of a wsdl.
http://community.jboss.org/message/570377#570377
But there really don't seem to be any standards, any thou-shalt-nots. Usually these things are very rigorously defined, but for some reason, it seems there are no standards here. Odd. It seems like META-INF has become a catchall place for any needed configuration that can't easily be handled some other way.
If you're using JPA1, you might have to drop a persistence.xml file in there which specifies the name of a persistence-unit you might want to use. A persistence-unit provides a convenient way of specifying a set of metadata files, and classes, and jars that contain all classes to be persisted in a grouping.
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
// ...
EntityManagerFactory emf =
Persistence.createEntityManagerFactory(persistenceUnitName);
See more here:
http://www.datanucleus.org/products/datanucleus/jpa/emf.html
All answers are correct. Meta-inf has many purposes. In addition, here is an example about using tomcat container.
Go to
Tomcat Doc and check
" Standard Implementation > copyXML " attribute.
Description is below.
Set to true if you want a context XML descriptor embedded inside the application (located at /META-INF/context.xml) to be copied to the owning Host's xmlBase when the application is deployed. On subsequent starts, the copied context XML descriptor will be used in preference to any context XML descriptor embedded inside the application even if the descriptor embedded inside the application is more recent. The flag's value defaults to false. Note if the deployXML attribute of the owning Host is false or if the copyXML attribute of the owning Host is true, this attribute will have no effect.
You have MANIFEST.MF file inside your META-INF folder. You can define optional or external dependencies that you must have access to.
Example:
Consider you have deployed your app and your container(at run time) found out that your app requires a newer version of a library which is not inside lib folder, in that case if you have defined the optional newer version in MANIFEST.MF then your app will refer to dependency from there (and will not crash).
Source: Head First Jsp & Servlet
As an addition the META-INF folder is now also used for multi-release jars. This is a feature which allows to package classes which are meant for different Java version in one jar, e.g. include a class for Java 11 with new features offered by Java 11 in a jar also working for Java 8, where a different class for Java 8 with less features in contained. E.g this can be useful if a newer Java version is offering enhanced, different or new API methods which would not work in earlier version due to API violations. One will see a sub folder versions then.

Categories

Resources