Loading a jar's context.xml from classpath - java

I'm trying to load an application context which is inside a jar as a plugin. I use this to load the context:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:**my-context.xml");
When I load the jar through pom.xml, it works fine.
Then I add it directly in the classpath using eclipse instead of maven to avoid to compile every time (ultimate goal is the shared lib folder in tomcat, not working too). Now spring is unable to find it and return a default context (no exception)
I checked that it's correctly insert in the classpath using:
InputStream in1 = this.getClass().getClassLoader().getResourceAsStream("my-context.xml");
It works.
I checked logs. Using the pom.xml, spring is correctly searching in the jar
Searching directory [...target\classes\META-INF\maven\x.y.z] for files matching pattern [...\x.y.z/target/classes/**/my-context.xml]
Searching directory [...ehealth.poc.module1] for files matching pattern [D:/JRB/Projects/Vivates/workspaces/default/extcom/ehealth.poc.module1/target/classes/**/ecm-context.xml]
...
Resolved location pattern [classpath*:**/my-context.xml] to resources [file [...\target\classes\my-context.xml]]
Loading XML bean definitions from file [...\target\classes\my-context.xml]
...
In the second case, nothing in the log about my jar.
Why spring does not have the same behavior when I use maven or directly the classpath? I maven doing something else than simple adding dependencies location in the classpath?

Finally, we found the solution on eclipse.
The problem comes from the ** in
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:**my-context.xml");
It looks like ** doesn't scan the .jar files. Setting the direct path is working :
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:my-context.xml");

Related

Get Maven basedir from a properties file in a SpringBoot project

The Maven project I inherited has some resource files used in JUnits.
Those files are referred in a properties file as absolute paths.
Let's assume the Maven project is under myproject, where the main pom.xml resides.
A config.properties file has:
keystore.file=C:/Users/tom/myproject/web/src/test/resources/myfile.jks
I want to refer to that resource from a relative path of the Maven project.
So I have been trying something like:
keystore.file=${project.basedir}/web/src/test/resources/myfile.jks
I have been reading about resource filtering which is referred in this question.
The project uses SpringBoot, and when running a JUnit, complains with:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'project.basedir' in string value "${project.basedir}/web/src/test/resources/myfile.jks"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
After trying different things, found a solution to my problem.
Adding this line in Spring Boot application.properties:
maven.basedir=#project.basedir#
And then in config.properties:
keystore.file=${maven.basedir}/web/src/test/resources/myfile.jks
Makes it work.
Check: Spring Boot automatic Property Expansion Using Maven.

Spring Boot project can't find Hibernate.cfg.xml when run as executable jar

I see that issues with the hibernate.cfg.xml not being found when SessionFactory is being set up is a somewhat common occurrence, but my question here is somewhat specific. My project works fine when run in Eclipse, even when I move the hibernate.cfg.xml around; I can leave it at the source level and do this:
Configuration configuration = new Configuration();
configuration = new Configuration();
configuration.configure();
Or I can move it to a different location and define it this way:
Configuration configuration = new Configuration();
configuration = new Configuration();
configuration.configure("/path/to/hibernate.cfg.xml");
Both ways work in Eclipse. However, when I build an executable jar to run the application elsewhere, when it launches it complains:
Initial SessionFactory creation
failed.org.hibernate.internal.util.config.ConfigurationException: Could not
locate cfg.xml resource [hibernate.cfg.xml]
org.hibernate.internal.util.config.ConfigurationException: Could not locate
cfg.xml resource [hibernate.cfg.xml]
I understand (or I think I do) that the reason for this is that the hibernate.cfg.xml isn't getting included in the jar itself and so even when the path is defined it can't find it but am not sure how to fix it. I think if I can get the file into the jar then it may work (maybe the classpath also needs an entry for this?) but I'm actually not sure how to do so.
It mainly depends on whether you are using a framework or not and if yes the which framework you are using. If you are not using any framework then keeping hibernate.cfg.xml file in your root path can be fine. But Because of urge in standardising the coding process, frameworks usually expect the file in your resources folder.But in your case you should give the path to that configuration file not relative to the root folder but entire path.
I think you are using absolute path here:
configuration.configure("/path/to/hibernate.cfg.xml");
Instead of that you should use classpath loader. Something like this :
Resource r = new ClassPathResource("hibernate.cfg.xml")
String path = r.getURI().getPath();
configuration.configure(path);
This should work after packaging jar.

ClassPathXmlApplicationContext error, Spring framework

I have encountered a problem when it comes to the Springs framework, which leads to that the communication between the server and the database does not work.
The project that I created is a Spring project, then refactored to Maven.
At this line in the code:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("projectName/spring.xml");
I get this error:
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [projectName/spring.xml]; nested exception is java.io.FileNotFoundException: class path resource [projectName/spring.xml] cannot be opened because it does not exist
But it does exist. And I've tried solutions for this problem such as writing ClassPathXmlApplicationContext("spring.xml") instead. This doesn't help however, since then Spring automatically looks in the folder src/main/resources. This doesn't work for me since my project structure doesn't allow me to add this folder and put a XML-file in it. If I try to create this folder, then it is automatically put inside the Java-resources folder, and Eclipse won't allow me to put XML in there.
This is how my project looks:
enter image description here
Is there a way for me to declare where Spring should look for this spring.xml-file?
The ClassPathXmlApplicationContext assumes that the file is on your classpath (Javy describes how to do load a resource from your classpath).
If you want to load the configuration from your file system (as you're doing), you might want to consider using FileSystemXmlApplicationContext instead. Using this mechanism to load your context you can pass a file system location as you're currently doing.
new ClassPathXmlApplicationContext(this.getClass().getResource("/spring.xml").getPath())
try the code above
hope that helped
Spring doesn't look at the src/main/resources, it looks at the classpath.
If you write projectName/spring.xml you need to have this file in bin/projectName/spring.xml or build/projectName/spring.xml. Where bin or build your build folder.
If you build a jar, this file should be in the jar!projectName/spring.xml.
For the web-application this file should be in the WEB-INF/classes/projectName/spring.xml.
If you add src/main/resources at the class path, then content of this folder will be in the build folder. Maven adds src/main/resources at the class path automatically.
Sometimes you should rebuild (clean) your project in the IDE to have such files in the build folder.
Use "FileSystemXmlApplicationContext" as
ApplicationContext context = new FileSystemXmlApplicationContext("spring.xml");

How to retrieve .properties?

Im developing desktop java application using maven.
I got a *.properties file that I need to retrive during execution (src/resources/application.properties).
The only thing comes to my mind is to use:
private Properties applicationProperties;
applicationProperties.load(new BufferedInputStream(new FileInputStream("src/resources/application.properties")));
This would work if I run my application directly from IDE.
I want to to keep outpout hierarchy clear, so I set maven to copy resources folder dircetly to target folder (which is a basedir for the output application). This way application.properties file won't load (since I have target/resources/application.properties but not target/src/resources/application.properties).
What is the best way to manage resources so they work both when I debug from IDE and run builded jar file directly?
Don't expect files to be in the src folder - it doesn't exist at runtime. The properties files go to /bin. But don't rely on that either. Because FileInputStream takes absolute paths only.
When you need a classpath-relative path, use:
InputStream is = YourClass.class.getResourceAsStream("/a.properties")`
(maven sends files from /src/main/resources to the root of the classpath)
You should load the property file from the classpath rather than from an explicit file system location:
applicationProperties.load(new BufferedInputStream(this.getClass().getResourceAsStream( "/application.properties" );
As long as your IDE is configured to include the resources directory on your classpath (this should be the default with Maven), then this will work whether you're running within the IDE or not since maven will copy the resources to the right place when packaging your archive.

Error with the .class location when building a WAR for a Play! framework application

I'm working on a 1.2 Play! framework application, and I have a problem when deploying it as a WAR on a Tomcat 6.
One page of my application displays a list of information.
These information are retrieved from a .yml file.
So I have a controller that generate a Iterable<Object> from this .yml file, like that:
public static void myFunction() {
Constructor constructor = new Constructor(MyClass.class); // org.yaml.snakeyaml.constructor.Constructor
constructor.addTypeDescription(new TypeDescription(MyClass.class));
Yaml yaml = new Yaml(constructor);
Iterable<Object> listOfInfo = yaml.loadAll(Application.class.getResourceAsStream("/my-file.yml"));
render("Application/my-page.html", listOfInfo);
}
The important point is that MyClass is located in the app/my/company/my-app/ package (my.company.my-app.MyClass).
When I run my application using play run, there is no problem.
Now, I build the WAR package (using play war -o some/dir --zip), and I install this generated WAR on a Tomcat (6.0).
Once the server is started, and try to access the corresponding page, I get the following error:
#683lh76fn
Internal Server Error (500)
Template execution error (In /app/views/Application/my-page.html around line 9)
Execution error occured in template /app/views/Application/my-page.html. Exception raised was ConstructorException : null; Can't construct a java object f
or tag:yaml.org,2002:my.company.my-app.MyClass; exception=Class not found: my.company.my-app.MyClass.
play.exceptions.TemplateExecutionException: null; Can't construct a java object for tag:yaml.org,2002:my.company.my-app.MyClass; exception
=Class not found: my.company.my-app.MyClass
at play.templates.BaseTemplate.throwException(BaseTemplate.java:84)
at play.templates.GroovyTemplate.internalRender(GroovyTemplate.java:252)
at play.templates.Template.render(Template.java:26)
at play.templates.GroovyTemplate.render(GroovyTemplate.java:184)
at play.mvc.results.RenderTemplate.<init>(RenderTemplate.java:24)
at play.mvc.Controller.renderTemplate(Controller.java:659)
at play.mvc.Controller.renderTemplate(Controller.java:639)
at play.mvc.Controller.render(Controller.java:694)
at controllers.Application.myFunction(Application.java:311)
If I have a look in the exploded war, I see that my.company.my-app.MyClass is located in the directory WEB-INF/application/precompiled/java/my/company/my-app/ directory.
If I move this directory into WEB-INF/classes, then I don't get this error anymore.
Why does this error occurs? What are my options to make it work (without modifying manually the WAR)?
By the default, Tomcat only looks at files in /WEB-INF/classes and /WEB-INF/lib (for each war file) as they are included in the classpath. There are a number of things you could do..
Put your classes in the Tomcat lib folder and they'll be handled by the common loader rather than the webapp loader. (not recommended as they will be available to other apps)
You can enable the shared loader in conf/catalina.properties and use whatever directory you want.
add the path to the CLASSPATH variable in the '/bin/setclasspath.sh' script (or setclasspath.bat for
Windows).
Personally i would fix/modify how i build the war file and make sure that the classes are copied to WEB-INF/classes instead of WEB-INF/application folder.
I finally found the answer of this problem!
The Yaml parser (snakeyaml) creates its own ClassLoader in order to parse a .yml file. The structure of the Play! framework uses its own ClassLoader, and the compiled classes are located in the WEB-INF/application/precompiled/java directory, which is not the WAR standard.
Due to that, Yaml was not able to retrieve the classes, in particular MyClass.class.
The solution to solve this issue (except by modifying the WAR using Ant for example), is to give the Play! ClassLoader to the Yaml parser. Instead of writing that:
Constructor constructor = new Constructor(MyClass.class);
constructor.addTypeDescription(new TypeDescription(MyClass.class));
I write:
CustomClassLoaderConstructor constructor = new CustomClassLoaderConstructor(MyClass.class, MyController.class.getClassLoader());
constructor.addTypeDescription(new TypeDescription(MyClass.class));
using this, I can use the WAR created by Play! directly without getting the Yaml error anymore!

Categories