In a Spring Boot web application, I use the git-commit-id-plugin Maven plugin to generate a file named git.properties, containing all the git commit information, e.g:
git.commit.id=35ca97298544d4ee6f8a5392211ebaa0d9bdafeb
This file is generated directly in the target/classes repository. So it's included in the classpath. At runtime the file is loaded via an annotation on my main application class :
#PropertySource({"git.properties"})
I can then use expressions in my beans to get the value of the properties contained in the git.properties file :
#Value("${git.commit.id}")
private String gitCommitIdFull; // will contain "35ca97298544d4ee6f8a5392211ebaa0d9bdafeb"
It all works very well when running the app normally.
But I am now trying to run some integration tests that are run with :
#RunWith(SpringRunner.class)
#SpringBootTest
public class SampleSearchDAOTest {
//tests here...
}
I get the following exception :
java.lang.IllegalStateException: Failed to load ApplicationContext
(...)
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException:
Failed to parse configuration class [ch.cscf.mds.MdsApiApplication];
nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/git.properties]
Obviously, the way the tests are run, they seem to not use target/classes as the base for the classpath.
What does it use ? How can I make the runtime for these tests aware of the target/classes/git.properties file ?
I tried to generate the git.properties file into the src/main/resources directory instead of the target/classes repository. I still have the same error.
Test runner by default looks for resources relative to the test folder. For example when the git.properties file would have been present in src/test/resources, then it should also work.
#PropertySource({"classpath:git.properties"}) tells to look for sources from the entire classpath.
Related
everyone,
I'm new on web development. Recently, I start a tutorial to build Registration and Login with Spring Boot and MySQL Database. When I run the unit test, there are errors showing up. I cannot find ApplicationContext file in the tutorial, and also try serval methods on stack overflow e.g. change plug setting in pom.xml but isn't working.
Can anyone answer this problem?
Errors on IDE
The application context is not a file – it's a term Spring uses to describe the entire state of your application. So the error means that Spring is not able to start your application because of missing database configuration.
Looks like you are using maven (src/main/java). In this case put the applicationContext.xml file in the src/main/resources directory. It will be copied in the classpath directory and you should be able to access it with
#ContextConfiguration("/applicationContext.xml")
A plain path, for example, "context.xml", will be treated as a classpath resource from the same package in which the test class is defined. A path starting with a slash is treated as a fully qualified classpath location, for example "/org/example/config.xml".
So, it's important that you add the slash when referencing the file in the root directory of the classpath.
I'm trying to use the appassember plugin to create an embedded tomcat using the heroku howto, with tomcat7 and oracle-java-7.
I've used these instructions a number of times to convert a working war file with no problems.
The current project is a spring-batch-admin console with a single runner underneath. I'm not the code owner, and not-so-familiar with spring-batch, but it seems happy to be dropped into a 'normal' /var/lib/tomcat7/webapps.
When launched with the auto-generated shell scripts (sh ./target/bin/webapp), I get the following error:
ERROR - DispatcherServlet - Context initialization failed
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath*:/META-INF/servlet/*.xml]
Offending resource: URL [jar:file:/vagrant/pairbulkdata_app/downloadjob_batch/target/repo/org/springframework/batch/spring-batch-admin-resources/1.0.0.M1/spring-batch-admin-resources- 1.0.0.M1.jar!/org/springframework/batch/admin/web/resources/servlet-config.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [../batch/module-context.xml]
Offending resource: URL [jar:file:/vagrant/pairbulkdata_app/downloadjob_batch/target/repo/org/springframework/batch/pbdDownloadXmlConfig/1.0.0.M1/pbdDownloadXmlConfig-1.0.0.M1.jar!/META-INF/servlet/service-context.xml]; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from URL [jar:file:/vagrant/pairbulkdata_app/downloadjob_batch/target/repo/org/springframework/batch/pbdDownloadXmlConfig/1.0.0.M1/pbdDownloadXmlConfig-1.0.0.M1.jar!/META-INF/servlet/../batch/module-context.xml]; nested exception is java.io.FileNotFoundException: JAR entry META-INF/servlet/../batch/module-context.xml not found in /vagrant/pairbulkdata_app/downloadjob_batch/target/repo/org/springframework/batch/pbdDownloadXmlConfig/1.0.0.M1/pbdDownloadXmlConfig-1.0.0.M1.jar
at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
Which seems to imply that it isn't finding the servlet-config.xml file.
The interesting thing, when I go peek into the new myApp.jar vs the old myApp.war files, the contents of the META_INF file have been moved around.
The relevent parts of the original war is:
\META-INF\maven
\WEB-INF\classes\META-INF\stuff-to-launch-the-servlet
In the fat jar, I'm getting:
\META-INF
|-----> maven
|-----> stff-to-launch-the-servlet
and WEB-INF doesn't seem to be baked in at all.
Since the class it can't find is in the stuff that got moved around, I'm heading down that rabbit hole.
Why does the jar file include the META-INF at a different path? The original configuration is on the filesystem, because this isn't a onejar, and should get picked up from the CLASSPATH, correct?
I am wetting my hands in Spring and using Eclipse along with Spring. I have written a very simple Spring application with eclipse to inject a property in a bean. However, when I am running my application, Spring is throwing exception and it seems that the Spring is not able to find the Spring configuration file. Below is the stacktrace --
INFO: Loading XML bean definitions from class path resource [Beans.xml]
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [Beans.xml]; nested exception is java.io.FileNotFoundException: class path resource [Beans.xml] cannot be opened because it does not exist
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:341)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
I have tried the following -- Give the full path in the ClassPathXmlApplicationContext method like --
ApplicationContext context = new ClassPathXmlApplicationContext("C:/Users/devshankhasharm/workspace/FinalPowerShell/src/src/main/Beans.xml");
I have also updated the ClassPath variable in windows to add the path for my spring configuration file. But nothing worked. Any idea would be highly appreciated.
Try this
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:Beans.xml");
And of course your Beans.xml must be in classpath.
Update or maybe
ApplicationContext context = new ClassPathXmlApplicationContext("file:src/main/Beans.xml");
Beans.xml should be in classpath. You cannot give full physical path of xml file for ClassPathXmlApplicationContext . Please check if Beans.xml is there in build path of eclipse.
As you are using a full filepath for your Beans.xml example, use
ApplicationContext context = new GenericXmlApplicationContext("C:/Users/devshankhasharm/workspace/FinalPowerShell/src/src/main/Beans.xml");
BUT it is not recommended to do this. Use the ClassPathXmlApplicationContext for this instead.
Then move Beans.xml into the classpath. The simplest way to do this is to move it to the root of your java source if not using Maven or src/main/resources if using Maven
If it's not much of a bother then try using Spring Tool Suite. It's a Spring friendly IDE based on Eclipse, so that you don't have to depend on spring/maven plugin configurations. All you have to do is go and create a Spring Project instead of Java project and rest all the settings will be handled for you.
If you are using Spring Tool Suite (STS), it may be the case that when you create a Maven project the src/main/resources directory was configured with "Excluded: .". In other words, STS sets your src/main/resources directory to have all its contents excluded from output by default.
How to fix it:
Project properties (Alt+Enter) -> Java Build Path -> Source
On src/main/resources, you may see "Excluded: ."
Select this item and click on Edit...
Remove the . exclusion pattern
Click OK. Voila!
I have a web application, that contains a configuration xml file for one of my application services that is exposed as spring bean.
Also I have a standalone java application(which references my web app project from its pom.xml) in the same workspace, that runs tests using Spring TestContext framework and one of the tests checks the configuration of that XML file.
However I have a problem with accessing this xml file from the standalone app:
Before setting-up the test, in my previous configuration, the file was accessed through ServletContext and was located in WEB-INF/ folder. However, to make it accessable from the test project I had to move it to source/ folder and load it with getClassLoader().getResourceAsStream() method instead that of ServletContext. But it makes editing the file cumbersome because every time the app has to be redeployed.
Is it possible to keep the file in WEB-INF/ folder but load it from the referencing project during the test-runs?
P.S. Currently it's an STS project with Tomcat server.
Definitely keep the file under WEB-INF/ folder if that's where it is supposed to live.
For your test classes that are being executed from the command line. Your can use getClassLoader().getResource() on a file that you know is in the root of your classpath (e.g. application.properties file). From there you know the structure of your project and where to find WEB-INF/ relative to the properties file. Since it returns a URL you can use it to figure out a path to the XML files you're looking for.
URL url = this.getClass().getClassLoader().getResource("application.properties");
System.out.println(url.getPath());
File file = new File(url.getFile());
System.out.println(file);
// now use the Files' path to obtain references to your WEB-INF folder
Hopefully you find this useful. I have had to make assumptions about how your test classes are runing etc.
Take a look at the File Class and it's getPath(), getAbsolutePath(), and getParent() methods that could be of use to you.
I ended up using Spring MockServletContext class and injecting it directly to my service bean, before the test runs, as my service implemented ServletContextAware :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/test-ctx.xml" } )
public class SomeServiceTest {
#Autowired
private MyServletContextAwareService myService;
#Before
public void before(){
//notice that I had to use relative path because the file is not available in the test project
MockServletContext mockServletContext = new MockServletContext("file:../<my web project name>/src/main/webapp");
myService.setServletContext(mockServletContext);
}
If I had several classes using Servlet Context, then the better solution would be to use WebApplicationContext instead the default one (currently provided by DelegatingSmartContextLoader), but it would require implementing custom ContextLoader class and passing its class name to #ContextConfiguration annotation.
alternative and somewhat cleaner solution which later came to my mind is to refactor the service and inject ServletContext via #Autowired instead of messing with ServletContextAware, and provide the bean of corresponding type(effectively a MockServletContext instance).
Possibly, in future the direct support of MockServletContext from test classes will be added to Spring see SPR-5399 and SPR-5243.
UPDATE FOR SPRING 3.2
In Spring 3.2 initialization of the servlet context became as simple as adding one #WebAppConfiguration annotation:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("file:../<my web project name>/src/main/webapp")
#ContextConfiguration(locations = { "/test-ctx.xml" } )
public class SomeServiceTest {
see details in the article
In a Maven project I had same problem. I had no servletContext and couldn't access static file in
WEB-INF directory.
I came across to a solution by adding entry to pom.xml which gave me access to the directory. It actually includes this path to the classpath.
PS: I was using Tomcat container
<project>
<build>
<resources>
<resource>
<directory>src/main/webapp/WEB-INF</directory>
</resource>
</resources>
</project>
It's a classpath resource, so put it on the classpath: $webapp/WEB-INF/classes
Maven projects will copy things in $module/src/main/resources to this location when packaging the webapp.
(the former is a sourcepath, the latter - WEB-INF/classes - is always put on the classpath by the servlet container, per spec.)
We have project layout as below.
src
src/test/java
src/test/resources
and we cant add src/main/(java, resources) for code, because of earlier developemnt done.
src/test/java is having both unit and integration tests in same package as class under test has in src folder.
unit tests are running fine in current setup but issues are with running integration tests.
integration tests run perfectly fine when test class and configuration files are along side class under test, in src folder and same package as class.
but when i put test class in src/test/java and config files in src/test/resources test fails to run because of context initialization issues.
please note following about env setup
1 build output folder for all the src , src/test/java and src/test/resources is src folder only.
2 i am using classpath*: to specify config location, as otherwise spring fails to locate config file in resource folder.
#ContextConfiguration(locations={"classpath*:applicationContext_getCorpAcctPrefDetailsSP.xml"})
3 tried both #Autowired and setter based DI for test classes
> (i). in case of #Autowired i get error for depedency saying
No unique bean of type GetCorpAccountPreferencesDetailsSP is defined expected at least 1 matching bean
also i am using base package scan
> (ii). in case of Setter based DI context get initialized and unit test run but all the dependencies injected are null in test class.
please expalin what can be reason for issue and any solution.
As everything is working fine when integration tests are in src folder alongside class under test.
i suspect differect source folders (src and test)creating issue when spring create context as class under test is not in same source folder as test.
thanks
nBhati
At run-time Spring doesn't care (or know) which folder your original source code is in. All that matters is the classpath - which compiled files and which resource folders are being put on the classpath. If you are getting errors about XML files that cannot be found when you run your tests, that strongly suggests that those XML files are not on the classpath when the tests run.