I am wondering why some resources files are put under the META-INF directory in the JAR? I am always put the resources like test.properties under the root diretcory. Any advantage to put them in the META-INF?
Lot of Java (EE) APIs have a contract that when you put a specific configuration/metadata file in the META-INF folder of your (or a 3rd party) JAR, then the API will automatically do the API-specific job, such as scanning classes, preloading specific classes and/or executing specific code based on the meta information.
An example provided by the standard Java SE API is the ServiceLoader. Among others, the JDBC 4.0 compatible drivers implement this. This way just dropping the JDBC driver JAR file folder will automatically load the driver class during Java application's startup/initialization without the need for any manual Class.forName("com.example.Driver") line in your code.
Further there is also the Java EE 6 provided JSF 2.0 API which scans during application's startup all JAR files for a faces-config.xml file in the META-INF folder. If present, it then will then take it as a hint to scan the entire JAR file for classes implementing the JSF specific annotations like #ManagedBean so that they get auto-instantiated and auto-configured. This saves time in potentially expensive job of scanning thousands of classes in all JARs in the entire classpath. In older versions of those API's the configuration was usually done by (verbose) XML files.
All with all, the major goal is to save the developer from code and/or configuration boilerplate. The JAR's META-INF folder is used for configuration files/hints. Some API's indeed also put static files/resources in there for own use. The META-INF folder is also part of the classpath, so the loading of those files by the classloader is easy done.
In servlet 3.0, certain static resources are available through the web context, such as .css, java script, and .png files, so you no longer need to use ServletContext getResource() and getResourceAsStream(). For more information, check out web-fragment.xml (https://blogs.oracle.com/swchan/entry/servlet_3_0_web_fragment) which is one resource that covers this subject.
Personally, I prefer to structure my projects the way Maven likes them, with a src/main/resources directory which is part of the application's classpath.
It's just a convention that some (most?) third party jars use to look for files that you provide. For your own classes and files, you can choose to put them where you like.
Related
I've got a few web projects that rely, all of them, in a common library. This library includes a few JSP files that are used to display errors (using the web.xml error-page feature). These JSP files are included in the library shared-resources, so they are merged with the files from the application.
What I'd like would be for a way to override thoses files with ones specific to the application if I want. If I include files with the same name in the same location in the application, they are overwritten by those in the library. Is there a way, maybe using maven plugins, so I can copy files from the application AFTER the ones from the library have been copied to the target directory? This way, if the application includes its own files, they are used. If it doesn't, then those in the library are used instead.
I've tried adding a new execution of the maven-resources-plugin, using the goal copy-resources, but they still get overwritten by the ones in the library.
Thanks for the help in advance.
I have two eclipse projects.
One of them is a library that contains property files.
Second one is a Dynamic Web Project.
In my library there are few configurable classes, that load their configuration parameters from property files.
String path = "Resources/Properties/Main.properties";
InputStream stream = getClass().getClassLoader().getResourceAsStream(path);
Properties properties = new Properties();
properties.load(stream);
My dilemma is that when I export my Web project into WAR, dependent library project gets packed into a jar and placed inside my WAR into "WEB-INF/lib" directory, which means that I can't load them as I would usually do.
My ideas are:
Copy those property files into my Web Projects, which is very
painful, because this library is meant to be used in many projects,
I do not want to have multiple instances of property files scattered
around projects.
Place property files into some system fixed path on the server, still is a bad desigion, makes it harder to deploy this application.
Is there a way to load property files from JAR files, or maybe a way to tell eclipse project to export property files from my library into my Web Project explicitly?
I would appreciate your help and ideas on this matter.
It works just fine if you load the resource file from classpath.
It goes trough classpath and searches for matching resource.
My problem was classpath resource collision, I had classes with similar package.classname and resources with similar path and filename.
When loading these resources, JVM silently ignores duplicated entities from .jar libraries.
So stay sharp and beware of non-unique entities when composing a complex library structure.
I am working on opensource project. As of of now I don't have any customization in any class. So using all the jars files provided by opensource project. My question is if I modify one java file, compile it and pack it new jar file with same folder structure, will there be any issue at start up of server or run time? If not which class file will be called(default file or my customize java class file)?
In fact it depends on many factors:
If both jar files are in the same ClassLoader, for instance the Java classpath (-cp option), normally it should be the first file found in the jar list order.
If deployed in a JavaEE container, like in an EAR file or in WEB-INF/lib or a WAR file, there is no warranty the container will load the same class between two startups. In that context, the only thing sure is that WEB-INF/classes is searched before WEB-INF/lib
In a complex ClassLoader hierarchy, the default behavior is parent-first search but JavaEE implementations have introduced mechanisms like parent-last policy (WebSphere) or filtering thanks to deployment descriptors (WebLogic, JBoss/WildFly)
An option may be to declare jar file dependencies in META-INF/MANIFEST.MF file thanks to the Class-Path attribute. It should enforce a loading order at the ClassLoader level, particularly when started with java -jar myapp.jar but it may depend on implementations in a JavaEE context.
Remark: when using an OpenSource project, it may be fair to submit a change request and publish your changes or improvements so that the community takes benefits from it. Then your project may update to main stream without such a difficulty of wild patches in your ClassPath.
Class loader is looking for the first place where needed resource is located. It means that if class with the same name and package appears in 2 jars the first found will be used. Which one is the first? According to the classpath: if for example class A appears in jars one.jar and two.jar and your command line is:
java -cp one.jar;two.jar MyMain`
the version from one.jar will be used. But if command line is
java -cp two.jar;one.jar MyMain`
the class from two.jar will be instantiated.
I have a problem with following tutorial:
http://www.mkyong.com/jsf2/jsf-2-internationalization-example/
In faces-context file you have to declare the place where all the language properties-files are (<base-name>HERE</base-name>). But in that example they use apparently maven2 and so they have a resource folder.
I am using eclipse and dynamic web project, that's why there is no resource folder. I tried a few possibilities like adding a new folder to the build path but I don't get it work.
Can you tell me please where to place those files to let my app find it. thank you so much
In addition I add a picture of my directory-structure:
They need to end up in the runtime classpath. The WebContent isn't part of the runtime classpath.
In your case, just drop them in the Java Resources folder. Imagine that they are placed in a package com.example.i18n, then you can specify as basename com.example.i18n.locale (although I would prefer text or messages over locale since they are actually no locale files).
Related:
How to internationalize a JSF 2.0 webapplication with UTF-8 properties files without native2ascii?
I'm using internationalization with Spring, and the properties file needs to be on the classpath. I also have some XML files that will need to be on the classpath. Is it acceptable to just include those resources inside the "src" in a sub-directory, and then let them build to the classpath, or is it better to add a different folder to the classpath during startup? I'm using Ant, but from the looks of it this was the approach Maven took (everything under src or test). I'm looking for the most widely accepted industry standards or better alternatives. Thanks!
Is it acceptable to just include those resources inside the "src" in a sub-directory, and then let them build to the classpath
Depends on the sole purpose of the resource in question. With this approach, any minor edit in such a resource file would thus require a full rebuild, redeploy and restart.
This may not necessarily harm for one-time-read startup and applicationwide configuration files like web.xml and application.xml and consorts since that would usually affect (or be affected by) changes in Java source code which require a full rebuild/redeploy/etc anyway.
But in case of runtime files like i18n properties files and environment-specific configuration files (which would/could be managed by a non-developer like a serveradmin or a customer), it is not useful to package it inside the webapplication. This requires knowledge how to rebuild the webapp after edits. You would rather like to externalize it so that only a webapp restart is required to reflect the changes in the configuration, or maybe even not at all, like for ResourceBundle which will just reload automagically.
I myself usually put such files in a fixed path along the servletcontainer and add that path to the servletcontainer's runtime classpath. In case of for example Tomcat, it's configureable as shared.loader property in /conf/catalina.properties. E.g.
shared.loader=/var/webapp
Anything in this folder is then taken in the servletcontainer's (and webapp's) runtime classpath.
Anything you put in your WEB-INF/classes directory is automatically in the CLASSPATH.
I usually put only .java files under /src and /test directories. Any resources that I put elsewhere have to end up in WEB-INF/classes. It's either my IDE (IntelliJ) or Ant that put them there when the WAR file is created.
I would recommend following the Spring examples and put resources where they do.
For example, if you use Velocity as your templating engine, you'll see that Spring configuration allows you to put them under /WEB-INF/vm_views.
Properties are put in WEB-INF/classes.
Check the Spring docs for examples.