Need understanding of spring.handlers and spring.schemas - spring

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

Related

Spring boot resources properties from config dependency

So my project is dependent on some another one which is kinda shared config for several projects.
I have added it as dependency using maven. Now I can easly import classes from this depeneney project and use them.
So the question is how to copy some src/resources or test/resources files into my project or maybe I dont need to copy them but how to point to those files ? As I can import classess so this jar should be in classpath so how to point to resources?
classpath:shared_project_name.jar/src/resources/<file>
Maybe I should't use jar name?
If you are sharing stuff between several projects i suggest you check out Monorepos.

Spring Resource Loading

Can anyone explain how Spring decides where to look for resources when one uses the ResourceLoader.getResource(...) method?
I am having a problem with a multi-module maven application built using Spring Boot whereby in my integration tests my code is able to find resources using resourceLoader.getResource("templates/") or even resourceLoader.getResource("classpath:templates/"). So far so good...
However, when the module is eventually packaged into the executable JAR and run with embedded Tomcat the resources can no longer be resolved. I also tried resourceLoader.getResource("classpath*:templates/") with no success.
What I find concerning is that when I add a logging statement to output the URL being used in the search i get a path to one of the other modules in the project (not the one that actually contains the resource in question). E.g: jar:file:/Users/david/exmaple/target/spring-boot-0.0.1-SNAPSHOT.jar!/lib/module1-0.0.1-SNAPSHOT.jar!/templates/ whereas I believe the resource is in jar:file:/Users/david/exmaple/target/spring-boot-0.0.1-SNAPSHOT.jar!/lib/module2-0.0.1-SNAPSHOT.jar!/templates/
The resource loader was obtained from an Autowired constructor param.
Thanks in advance for any hints.
Edit
Just in case it isn't clear or is of importance, my integration tests for the module in question aren't aware of the other module. I have module1, module2 and a spring-boot module which has dependencies on module1 & module2. Essentially, when I run the integration tests for module 2 the classpath isn't aware of module1 - so I suspect that this has something to do with why it works in the tests.
When you use classpath: or classpath*: prefix, internally, this essentially happens via a ClassLoader.getResources(…​) call in spring.
The wildcard classpath relies on the getResources() method of the underlying classloader. As most application servers nowadays supply their own classloader implementation, the behavior might differ especially when dealing with jar files. A simple test to check if classpath* works is to use the classloader to load a file from within a jar on the classpath: getClass().getClassLoader().getResources("<someFileInsideTheJar>"). Try this test with files that have the same name but are placed inside two different locations. In case an inappropriate result is returned, check the application server documentation for settings that might affect the classloader behavior.
Do not use classpath: form as you have multiple classloader locations of templates/ .
Refer to: resources-classpath-wildcards

Maven filter src/main/resources of a JAR dependency

My maven top level project refers to a common-db project. In this project I have a spring file which defines the DB parameters.
However, I want the top-level project to define the DB parameters through the profile and inject these into the spring config file in /src/main/resources.
The top-level project only does the filtering on its own /src/main/resources files and ignores those located in the JAR dependencies.
How can I do this?
So you want to depend on common-db but then modify its contents to change the parameters in the config file? Ok, if you really want to do that, you could do something convoluted where you use dependency:unpack to expand the common-db jar, then overwrite / filter its contents, and then use a custom jar:jar execution to re-jar up the dependency and ship it with your application.
But, wow - why would you jump through all these hoops? Like #hoaz suggested, just place your application-specific config in the same classpath location so that it is loaded before common-db's default configuration. This is the convention followed by many, many Java libraries.

Maven Jetty plugin with endorsed external directory

I have a project with more than an hundred external library dependencies, here we use tomcat with this endorsed jar libs configured on a directory in the server (now is under $CATALINA_HOME/lib/endorsed), so the webapp can access those resources on runtime start.
I wanted to try jetty instead, because tomcat takes too much memory and crashes frequently. Now I'm wondering if there is a parameter to pass on maven-jetty-plugin to specify this jar's folder so as the webapp class loader find them in its classpath.
I've tried extraClasspath in configuration tag, but it seems to load only classes and ignore all jars in the directory I set into (if I pass the full name path of the jar, it is loaded, but I don't want to set every library that I need there).
Thanks in advance for the help
update:I know it's not a standard maven operation, i'm searching for an emergency workaround since this project is very huge and I can't refactor as I want.
But also I expected this feature was not as tricky as it seemed to me at first glance.
You need to pass them as absolute paths, or, alternatively, have them as dependencies of the plugin itself.
What you want to have done goes against Maven's portability principles, so don't expect it to support it.

spring configuration XML files location in multiple projects - what's the best practice?

We have multiple projects, and there are spring configuration XMLs in all of them. We're contemplating 2 options:
A) Loading the spring files from the classpath, by using import "classpath:a.xml". In this option our springjunit4classrunner and our main console application both happily find the files. However, when you need to change or inspect some XML, it's well hidden in some obscure jar.
B) Creating a "conf" folder, and by using some maven magic gathering all the XML files from all the projects there. This is good for the main application, but the unittests don't like this setting, as obviously we don't build the "conf" folder before running unittests, and they fail to find the dependent projects XMLS...
(This is a spring re-take on Is it bad practice to include properties/configuaration files within jars?)
In the past, I've gone with <import resource="classpath*:beans.xml"/> or similar, i.e. import every beans.xml file the classloader can find in the root of the classpath. In turn, those beans.xml files import their own specific config files as required.
It requires discipline, so that you don't get big spider webs of Spring configs, but if you keep it simple, then it makes integration very easy, so that you don't need to maintain complex lists of config file imports, and the build process stays simple also.
It's interesting that you mention that prior question, because I don't consider Spring beans files to be "configuration". Rather, they're part of the application - they cannot and should not be separated from the Java code, because they're intimately coupled with it.
If those beans files require genuine configuration, e.g. from a properties file, then yes, those probably should be kept separate.

Resources