How to load jar files from web-inf/lib in desired order - web-inf

I have 2 java files with same name and package structure. One file is from framework team and second file is from customization team. There are 2 jar files framework.jar and customization.jar. In my web application i want to search class file first in the customization.jar and if not found then search in the framework.jar. i.e customization.jar take the precedence.
How to achieve this ? How to enforce that customization.jar take the precedence.
I have put the 2 jars in web-inf\lib folder. but here there is no way to confirm that customization.jar take precedence.
Thanks.

Related

What is the best place to store the application.properties file for a Spring boot application?

I have an application.properties file which I have placed at the same level as the src folder. Things are working correctly. But, is this the standard place to keep this file? What is the best practice?
I place them at src/main/resources. Some would prefer src/main/resources/config. When deploying, I put the customized properties at the same folder where the jar is placed. Again, some would prefer the config sub folder.
Spring Boot picks the files from these locations by default.
Under src folder create another folder named config let's say. Here create another folder named local. Than place your file here. This structure is used when you want to deploy to different servers(i.e. local, test, live).
Then you can create profiles and for example you can configure Maven to choose the proper application.properties file located in one of these folders to create the war and deploy.
So have something live config/local/application.properties and at least config/live/application.properties
UPDATE
What IDE are you using? You need to declare the path as a resource path. See how to do that depending on what you are developing. At build time, the path need to contain some resources, i.e. one or more folders in which the .properties files will be placed.
You can also try the path sugested in another answers src/main/resources (it is more explicit I agree) but the thing is that you can place your resources anywhere but you need to declare the location as a resource location.

Spring how to get Maven artifact name in runtime

I have a Spring Integration requirement , where I need to externalize the libraries and properties file from my war file. I am able to achieve this through Maven assembly plugin, where i create a zip file which may contain
lib/*.jar
properties/{artifactId}/*.properties
The reason I am adding the artifact Id to the path is, I will be creating 100s of wars in future and would need to distinguish between them.
This wars will not contain Web.xml and the Initializer is part of one of my libraries file.
THe Initializer should know the artifactId in order to load the correct properties.
With maven, the maven artifact details gets published to
META-INF/maven/${groupId}/${artifactId}/pom.properties
META-INF/maven/${groupId}/${artifactId}/pom.xml
If I could move these files to
META-INF/maven/pom.properties
META-INF/maven/pom.xml
My application would be able to read the artifact id from pom.properties.
I need help in achieve this.
Or if there are any other approach please help in solving the issue.
The Maven archiver component does that: see here at addMavenDescriptor element. It doesn't seem to be possible to customize the paths of these files.
But I guess every property you need can just be placed in a specific file and so you just have to create a resource file (properties like) containing all the information you want and let Maven filter that file for you.

cxf webservice in standalone spring application packaged as jar-with-dependencies using maven

When running the packaged app like "java -jar my-app-0.0.1-SNAPSHOT-jar-with-dependencies.jar", I get the following error:
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 47 in
XML document from URL [jar:file:/.../cxf/javafirst/target/my-app-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/application-context.xml]
is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 47;
columnNumber: 61; cvc-complex-type.3.2.2: Attribute 'sendServerVersion'
is not allowed to appear in element 'httpj:engine'.
This is due to an outdated http-jetty.xsd schema published at apache.org. And that is NOT my problem. My problem is that this does not happen in cases like:
maven jetty:run
or
maven exec:java
where the service runs directly against the unpacked binary directories and obviously finds the updated and correct http-jetty.xsd schema file.
I want to do basically one thing:
put the webservice into one jar including dependencies. That should also include all XML schema files because, obviously, it is not a good idea to make a web service dependent on outside resources.
What's the best way to do that using maven?
My possibly naive solution would be to copy the XML schema files manually into the resources directory and tell CXF to resolve them in the jar file. Therefore I have two more specific questions:
1.) Is it possible to let maven find the XML schema files and copy them into appropriate places?
2.) What's the recommended way to make CXF look up the schema files in the jar file?
3.) Is there any better, best-practice solution to that problem?
My maven configuration regarding the maven assembly plugin is the direct combination of the last two sections at http://maven.apache.org/plugins/maven-assembly-plugin/usage.html.
Spring has a very good mechanism to resolve the schema files that it requires - it typically does not download it from the web at all, instead using locally available files within jar files to get the schema and validate the xml, for eg. consider the context custom namespace schema in Spring, if you look at the META-INF/spring.schemas file in spring-context.jar file, you will see an entry along these lines:
http\://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd
basically what it is saying is to resolve the spring-context-3.1.xsd files from the classpath org.springframework.context.config.spring-context-3.1.xsd file
This applies for any third party library also, which in your case is http-jetty.xsd.
I think what I would recommend is to simply create a spring.schemas file in your jar file in META-INF/ folder, put an entry for the full path to the schema and replace it with a classpath version of http-jetty.xsd.

Need understanding of spring.handlers and spring.schemas

I have some questions derived from a problem that I have already solved through this other question. However, I am still wondering about the root cause. My questions are as follows:
What is the purpose of spring.handlers and spring.schemas?
As I understand it's a way of telling the Spring Framework where to locate the xsd so that everything is wired and loaded correctly. But...
Under what circumstances should I have those two files under the META-INF folder?
In my other question linked above, does anybody know why I had to add the maven-shade-plugin to create those two files (based on all my dependencies) under META-INF? In other words, what was the ROOT CAUSE that made me have to use the maven shade plugin?
What is the purpose of spring.handlers and spring.schemas?
well you more or less found it out by yourself, let's add some more details:
some spring libraries contain a spring.schemas and a spring.handlers file inside a META-INF directory
META-INF/spring.schemas
re-maps(*) schemalocation to a xsd inside the library
(abstract) only re-mapped versions are supported by this library
META-INF/spring.handlers
provides namespace handler classes for specific namespaces
the namespace handler class provides the parser logic to parse spring-batch beans, like job,
step, etc.
(*) the actual re-mapping happens during the build of the spring application context
Under what circumstances should I have those two files under the
META-INF folder?
normally the files are inside the spring library jars you use, but you can use the mechanism to implement own namespace bean parsing, then you would have own files
In my other question linked above, does anybody know why I had to add
the maven-shade-plugin to create those two files (based on all my
dependencies) under META-INF? In other words, what was the ROOT CAUSE
that made me have to use the maven shade plugin?
if you use a spring namespace in your spring configuration, you need the appropriate files
the problem arises when you want to run a java application:
with a main class either
the spring libraries need to be on the classpath
or all is merged into one jar, which has to be on the classpath (*)
as war/ear server application, the spring libaries need to be on the classpath, normally inside the war
i guess you did not start the mainclass with the complete classpath and i updated my answer for your first question too
(*) if you merge all into one jar, you have to make sure, that the contents of all spring.schemas/spring.handlers files are merged into one spring.schemas and one spring.handlers file, see this answer for a configuration with maven to create an all-in-one.jar

Classloader issue

I've got an interesting question about classloader behavior.
Question one: What is the order in which the classloader will load jars?
The following jars and containing classes are given:
a.jar
+-com/scheffield/foo/A.class
b.jar
+-com/scheffield/foo/B.class
Which class will be loaded?
Question two: Is it true that the path and name of a file in the classpath is unique?
The following jars and containing classes are given (realworld example):
spring-beans-3.0.3.RELEASE.jar
+-META-INF/spring.schemas
spring-aop-3.0.3.RELEASE.jar
+-META-INF/spring.schemas
What I can tell you is that both files are be loaded by Spring otherwise an exception would occur (see this article).
Why am I asking that:
I made a so called big jar (cookbook entry for gradle). Thats a jar with the application classes and all other dependencies unzipped and packet in the big jar. And I'm not absolutely sure what to do with duplicated files.
Classes are resolved however a classloader wants to resolve them (that's the whole point of having a classloader architecture). Most classloaders you deal with in practice are variants of java.net.URLClassLoader which loads classes (and resources) based on a search path (class path) of directories and jars. Each location in the search path is treated as a source of classes and the locations are searched in order.
No, names are not unique. The first one encountered in the search order will be used.
If you combine jars into one big jar there is a definite possibility of conflict. If you are careful to merge them from the last source in your effective classpath to the first (thus overriding later jars with earlier jars), you will get approximately the same result.
I say approximately because the manifests in jars contain additional processing instructions that need to be merged as well. For example, a manifest can contain a Class-Path attribute that includes additional jars in the classpath. It's possible to merge jars but lose manifest attributes that are specifying part of your actual necessary classpath. If your manifest contains sealed or signed jars then you might not be able to do this merging at all without violating the signed parts of the jar.
In summary, jars are not really designed to be merged in this way. It can work but there are many possibilities for error, some of which are not possible to solve. One common cause of error is to merge two jar files and end up with more than one entry with the same path, which is allowed in zip files. The ant jar and zip tasks allow you to merge multiple sources and can produce these kinds of issues.
Really, it's better to instead bundle web apps consisting of many jars and sources into a single WAR or EAR archive. That's kind of the whole point of why they exist.
the files are being loaded in the order the containing jars appear on the classpath. this applies to classes. if you are loading other resources (like the spring.schema) you may use either classloader.getResource(...) or classloader.getResources(...). the first one returnes the first resource on the classpath, the second one also returnes shadowed resources.
I don't think a valid zip archive contains duplicate entries.
regards

Resources