I have a SpringBoot application that is run with the command java -classpath <longlist of JARs> com.example.MyApp.
I have the path to a JAR - in this case liquibase-core-4.4.0.jar - specified on the classpath. However, on startup the app complains about missing class definitions.
Attaching a debugger I can see that the URLClassPath does have this JAR in its path list. However, there is no loader for it.
What would cause a JAR to be on the classpath but have no loader?
Spring boot applications have pretty clever system of class path searching, for example it finds jars in BOOT-INF/lib - something that a regular java system can't do. So spring has custom class loaders for this purpose.
Now its possible to add an external jar with the help of LOADER_PATH environment variable or loader.path parameter.
Bottom line, instead of using "standard" java mechanism, consider using "special" spring boot's mechanisms.
Read the official documentation for concrete examples
Related
In the Spring Boot's docs here, about serving static content, it says:
By default Spring Boot will serve static content from a directory
called /static (or /public or /resources or /META-INF/resources) in
the classpath.
I found that all the content in the directory:
src/main/resources
will be copied inside the classpath, so I can put my static content in:
src/main/resources/static
and all will work fine and I'm happy since I can have my static content under the src directory.
But, I have some questions about this:
Why the documentation doesn't say to put static content in src/main/resources/static instead of speaking about the classpath (I think this is a bit confusing)?
Is it good to assume that the content in src/main/resources/ will be always copied in the classpath?
Is there some Spring Boot official documentation explaining what I'm supposed to find in the classpath other than Java classes and packages (up to now I only know I can found all the content from src/main/resources/)?
/src/main/resources is a Maven project structure convention. It's a path inside your project where you place resources. During the build step, Maven will take files in there and place them in the appropriate place for you to use them in your runtime classpath, eg in an executable .jar, some physical file system location used in the classpath (with java's -cp option), etc.
I could choose to build my application myself or with a different build tool. In such a case, /src/main/resources would not exist. However, the intention is for the classpath to be the same, ie. to contain the same resources and .class files.
The Spring boot documentation talks about the classpath because it shouldn't make assumptions about how your project is set up.
The classpath also contains additional libraries (JARs), which also can have a static folder, which would then be included for serving static resources. So if the documentation would only state the folder src/main/resources/static, it would be incomplete.
Ad 2: As long as you don't mess with the default Maven configuration, then it's safe to assume this.
Ad 3: Maybe start with the official Oracle documentation: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html. Hint: Of course, it's not only the contents of the resources folder, which are in the classpath, but also of course all compiled classes, hence its name.
To add to previous answers, it's the Spring Boot Maven Plugin (spring-boot-maven-plugin in the pom.xml) that that enables you to run the application using Maven. One of its functions is to ensure contents in the app including dependency libraries are available on the runtime classpath, such as within the the executable JAR file.
I'm learning Spring Boot and sometimes I have to config application.properties with values like classpath:/some/packages and file:/some/url. What is the difference between classpath vs file in this situation ?
Firstly, you need to understand what the classpath is. Here is a good answer about it:
It would be impractical to have the VM look through every folder on your machine, so you have to provide the VM a list of places to look. This is done by putting folder and jar files on your classpath.
Shortly, classpaths contain:
JAR files of your project
and Paths to the top of package hierarchies.
So when you have classpath:/some/packages - think of it as you point to a file inside your project (the first / is the root for the compiled classes and resources). But when you have file:/some/url you point to a file anywhere in the OS.
By example, have a WEB project, but need add a custom static content from vendors without recompile the main jar project.
Is it possible to run the Spring Boot .jar file and give some argument to tell it to load other jars where different static contents are found or from code dynamically? For example:
1.jar : src/resources/static/vendor1/
2.jar : src/resources/static/vendor2/
Etc.
You need to specify a property named loader.path. Quote from Docs
Comma-separated Classpath, such as lib,${HOME}/app/lib. Earlier
entries take precedence, like a regular -classpath on the javac
command line.
We'd like to configure ESAPI property files directory, in JBOSS WildFly
(What usually done by VM argument: -Dorg.owasp.esapi.resources="/path/to/.esapi")
but prefer to do so in OTHER way, to suppurt diffrent property configuration for diffrent projects
does someone know how to do so?
Thaks!
There's really only two methods for loading these files, neither of them care about the application server you use. The first method, as you suggested is to supply the path via JVM properties.
The second method is via the classpath. I've never worked in JBOSS, but in Weblogic there's a config menu where you can place files on the classpath directly. In your case, it sounds like you want a different properties file for multiple applications? A JVM property or a similar classpath edit to weblogic would be the only choices.
The final classpath method, which I'm only including to be complete, is to compile your own copy of the library with your properties files in src/main/resources. Or--really hacky--crack open the jar file and dump them in by hand. The benefit of the "compile yourself" approach is that you'll have all the unpublished bugfixes, so if another CWE gets assigned to it you don't have to wait for the official release.
I have a jar file that cannot be modified, but I want to use a different .class file in place of one of the members of the jar. How can I tell Java to use the external .class file when the code within the jar attempts to load it?
You could compile another jar file with replacement classes with exactly the same name and put it ahead of the jar file in the class path. For example, this is what the various slf4j bridge jars do to replace calls to log4j or Jakarta Commons Logging in library code with cognate slf4j code; one need not maintain two sets of logging systems and configurations that way.
If you want to override a java... class, you can use some of the command line options to change the boot class path. Look at the -Xbootclasspath options in http://docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html. Heed the warnings.
There is also the lib/endorsed directory if you need to upgrade a third-party jar that Sun uses. Oracle uses other organizations' XML and CORBA libraries; if they release a new version and you need to adopt it, you can.
You can use AspectJ to instrument the code and possibly replace it. An around advice can call the original code if it wants.
You could see if you really need to replace the original code. Some systems provide customization hooks.
You need to make sure the external .class file is loaded first. If a class is already loaded by the class loader then it will not be reloaded. If you are using an application server, then there are ways to configure the preferences for loading classes for class loader. But if you are using a standalone application then you may need to extend the class loader to load the files in the order you want to.