Spring: exclude some properties files from context - spring

suppose we have some jars with properties files with the same key/values.
configA.jar:
log4j.A.properties
configB.jar:
log4j.B.properties
The problem: Spring mixes values from the both properties files. So, how to exclude log4j.A.properties from the context and process only log4j.B.properties?
UPDATE (added some stuff): there is a maven build which produces two jars mentioned above. Here in webapp (applicationContext.xml) following setup:
<util:properties id="propertyConfigurer" location="classpath:common.properties,classpath*:edrive.properties,classpath*:job.properties,classpath*:log4j.B.properties"/>
After the startup Spring mixes both jars and takes random (or the last one) jar and it's log4j.properties. But we need only the log4j.B.properties. How to do that?

try adding the config file to be used in your properties file
logging.config=log4j.B.properties

I resolved the issue by myself. I've upgraded logging facility to Log4j2 with following configuration:
log4j2.component.properties in classpath:
log4j.configurationFile=classpath:log4j2.web.xml
That's it.

Related

jar with embedded tomcat, when using another spring project, is not working with just yml - it's needing a blank application.properties file as well

Been searching for others that have run into this issue, and not finding much out there, so it can't be that common.
I have a spring-boot project that I want to convert into a jar project, running with embedded tomcat. It's using yml files (application.yml and then the profile versions - eg appplication-dev.yml.) It ran fine as war with the yml files, however, when I convert it to a jar, and kick off the jar, the embedded tomcat never starts UNLESSS I add an empty application.properties file as well. (No errors just no Tomcat startup unless the empty application.properties file is added.)
I believe it's somehow related to one of our internal jar dependencies (also spring), since if I remove that dependency from the pom (and any of the code referencing it) I can get the jar to startup the embedded tomcat just fine (without providing the empty application.properties file.)
I could also, of course, forgo using yml files and just use .properties files, but I'd like to use yml files if possible. Why adding an empty applcation.properties file causes things to work has me stumped.
If it helps, the config in the dependency project that causes the issue we're seeing is set up as:
#Configuration
#EnableConfigurationProperties(OracleDataSourceProperties.class)
#EnableTransactionManagement
#ComponentScan(basePackages = {"com.foo.data.services","com.foo.data.domain", "com.foo.utility", "com.foo.cipher.utility"})
#MapperScan(value = {"com.foo.data.services.mapper","com.foo.data.services.batchmapper"})
public class DataServicesPersistenceConfig { ... }
and the OracleDataSourceProperties class:
#ConfigurationProperties(prefix="oradb", ignoreUnknownFields = true)
public class OracleDataSourceProperties extends BaseVO implements InitializingBean{

Spring Tools Suite and Gradle - Setup to use correct resources from inside STS

I have a Spring Boot Gradle project setup in Spring Tools Suite (3.7.2 RELEASE) with the following source folders:
- src/integration-test/java
- src/integration-test/resources
- src/main/java
- src/main/resources
- src/test/java
- src/test/resources`
Whenever I run the application or unit tests from within STS, I see that STS is using the resources found under src/integration-test/resources.
I see a duplicate resource warning in STS for files which exist in all 3 resource source folders. For example, I have an application.properties in all 3 source folders and I see following:
The resource is a duplicate of src/integration-test/resources/application.properties and was not copied to the output folder
If I run the application as a JAR or unit tests/integration tests from the command line (via gradle build), everything seems to use the correct resources. This makes me believe it is a problem with how STS/Eclipse is handling gradle.
Does anybody know of how I can configure STS to use the correct resource source folders when using gradle?
I think my problem may be related to (or the same as?) Spring Boot incorrectly loads test configuration when running from eclipse+gradle, https://issuetracker.springsource.com/browse/STS-3882, https://issues.gradle.org/browse/GRADLE-1777
I also tried the solution found here, but that seems to only fix Maven builds:
Spring Tool Suite finds spring-boot integration test configuration and does not start main application
I think my problem may be related to...
Yes, it is related but in my opinion not the same. That problem is caused by the runtime classpath being incorrect. This problem is an error coming from the eclipse project builder so it is a compile-time issue.
The problems are closely related though. Depending on your point of view, you could say they are the same (incorrect mixing of test and compile-time classpaths).
Here, specifically, the problem is that the eclipse builder tries to copy all the resources it finds in source folders to the project's single output folder. Each source folder has a 'application.properties'. The builder warns that it could not copy some of them because one would overwrite the other.
I think there may be a solution for this problem. But it is a solution that really should come from Gradle + ( BuildShip | STS Gradle Tooling) than from you.
It is possible in Eclipse to configure each source-folder individually to target a specific outputfolder. Maven + M2E are doing this correcty, but Gradle + (BuildsShip | STS Gradle Tooling) combdos do not.
For example this is what maven puts into the eclipse .classpath file when it configures a test resources folder:
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
Notice how it explicitly sets the output folder for that entry (to something different from the project's default output folder).
You may be able to address the problem yourself by modifying the .classpath for a gradle project in a similar way. Either by doing it manually or from your build.gradle.
I'm not sure this is worth it however as you will then likely still get hit by the runtime classpath issue (since these folders will still be added to your runtime classpath, your runtime classpath will end-up with two appication.properties resources, one which will 'shadow' the other. See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=482315)
I would say, the right thing to do is add a comment to the issue I linked, and hope they fix it soon as there is only so much you can do yourself by hacking the build.gradle file to modify the .classpath (this can not solve the runtime classpath issue, but in order to solve the runtime classpath issue, they would have to configure source folders to target individual output folder similar to what m2e does).
I would add this as a comment to #Kris's answer but it's too long.
I have solved the runtime classpath issue by adding the code below to my build.gradle file. The code generates an Eclipse launch configuration for the Spring Boot application class and includes only the runtime classpath (i.e. no test JARs).
My project uses the Gradle 'eclipse' plugin to generate the Eclipse project files (which I then import into Eclipse). Running the eclipseClasspath Gradle target will generate the launch file in the project's root directory.
def mainClassName = "com.example.MyApplication"
task eclipseApplicationLaunch {
group "IDE"
description "Generate an Eclipse launch configuration file for the Spring Boot application class"
}
eclipseApplicationLaunch << {
def writer = new FileWriter("${mainClassName.substring(mainClassName.lastIndexOf(".")+1)}.launch")
def xml = new groovy.xml.MarkupBuilder(writer)
xml.doubleQuotes = true
xml.launchConfiguration(type: "org.eclipse.jdt.launching.localJavaApplication") {
listAttribute(key:"org.eclipse.debug.core.MAPPED_RESOURCE_PATHS") {
listEntry(value:"/${project.name}/src/main/java/${mainClassName.replace(".","/")}.java")
}
listAttribute(key:"org.eclipse.debug.core.MAPPED_RESOURCE_TYPES") {
listEntry(value:"1")
}
listAttribute(key:"org.eclipse.jdt.launching.CLASSPATH") {
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry containerPath=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/\" javaProject=\"${project.name}\" path=\"1\" type=\"4\"/>\r\n")
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry path=\"3\" projectName=\"${project.name}\" type=\"1\"/>\r\n")
configurations.runtime.resolvedConfiguration.resolvedArtifacts.each { artifact ->
def filePath = artifact.file.canonicalPath.replace("\\","/")
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry externalArchive=\"${filePath}\" path=\"3\" type=\"2\"/>\r\n")
}
}
booleanAttribute(key:"org.eclipse.jdt.launching.DEFAULT_CLASSPATH", value:"false")
stringAttribute(key:"org.eclipse.jdt.launching.MAIN_TYPE", value:"${mainClassName}")
stringAttribute(key:"org.eclipse.jdt.launching.PROGRAM_ARGUMENTS", value:"--spring.profiles.active=local --spring.config.location=conf/")
stringAttribute(key:"org.eclipse.jdt.launching.PROJECT_ATTR", value:"${project.name}")
stringAttribute(key:"org.eclipse.jdt.launching.VM_ARGUMENTS", value:"-Djava.net.preferIPv4Stack=true")
}
writer.close()
}
eclipseClasspath.dependsOn eclipseApplicationLaunch
I haven't modified the Eclipse .classpath file as per Kris' suggestion. Instead, I have added #Profile("test") to my test application class and #ActiveProfiles("test") to my test classes.

Spring Boot and external configurations

I am trying to make a Spring Boot application. Everything is fine once I deploy to the fat jar file with everything contained in it. But, what I actually want is the configuration files to be located externally. for example I have the following directory structure:
bin - contains startup and shutdown scripts
conf - all configurations. i.e. application.properties, logback.xml i18n.properties
logs - log files
libs - app.jar
If I use this directory structure and execute the jar using
java -cp ./conf -jar ../libs/app.jar
then the properties in the conf directory are not loaded or recognized. Is there a better way to do this maintaining the directory structure above? Or, what is the alternative/best practice?
Boot external config is what you are looking for.
Especially it mentions:
SpringApplication will load properties from application.properties
files in the following locations and add them to the Spring
Environment:
A /config subdir of the current directory.
The current directory
A classpath /config package
The classpath root
So I would say adding the config folder on classpath is good step. Them it should find application.properties and load it automatically.
For different config files I use:
#Configuration
#EnableAutoConfiguration
#PropertySource({
"classpath:path/some.properties",
"classpath:another/path/xmlProperties.xml"
})
public class MyConfiguration {
// ...
}
Edit:
As Dave pointed out (Thank Dave!) there is either -cp or -jar, so you can't add it to classpath like that. But there are options. This should help you to solve the problem: Call "java -jar MyFile.jar" with additional classpath option.
Additionally #PropertySource doesn't require the resources to be classpath resources if I'm not mistaken.
It should also be mentioned that there is a spring.config.location parameter that allows one to specify a file system / classpath location for externalized configuration files. This is documented in the following section of the Spring Boot reference guide:
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files

spring junit load application context for tests

I've got some XML files under my WEB-INF directory:
lyricsBaseApp-servlet.xml
hibernate.xml
dataSource.xml
beans.xml
the servlet xml imports other xml files:
<import resource="dataSource.xml"/>
<import resource="hibernate.xml"/>
<import resource="beans.xml"/>
I would like my junit4 JukeboxTest class to include entire spring configuration. Using default filename I have created a JukeboxTest-content.xml file. And finally, I do not know what to put there...
I've tried:
<import resource="/WEB-INF/dataSource.xml"/>
<import resource="/WEB-INF/hibernate.xml"/>
<import resource="/WEB-INF/beans.xml"/>
or
<import resource="classpath:./WEB-INF/dataSource.xml"/>
<import resource="classpath:./WEB-INF/hibernate.xml"/>
<import resource="classpath:./WEB-INF/beans.xml"/>
and some other ideas but all failed. Could someone point me how to access those files and what way spring interprets those filepaths?
Option 1 (should be preferred as it's the best practice):
Refactor your config files under WEB-INF and move the common parts (that you want to access also from integration tests) to src/main/resources/. Then write test specific configuration files in src/test/resources/ (if you only need to import several different config files from src/main to assemble your test context, then skip this, and use #ContextConfiguration preferably).
Option 2 (hack):
Use references like:
#ContextConfiguration("file:src/main/webapp/WEB-INF/dataSource.xml")
Option 3 (hack):
If you have a Maven project, you can configure the maven-surefire-plugin (used in the test phase) to declare src/main/webapp as an additional classpath element during test execution.
The latter two options are considered as hack, because files under src/main/webapp are simply not supposed to be on the classpath.
Now the detailed explanation:
The reason why you can't refer to these files as classpath:/WEB-INF/*.xml is that they are indeed not on the classpath. It's important to understand how your webapp is packaged, and what exactly ends up on the classpath. Assuming a default Maven project structure:
Java classes from src/main/java go to /WEB-INF/classes after compilation.
Resources from src/main/resources go to /WEB-INF/classes as well.
Project dependencies go to /WEB-INF/lib.
Everything you have in src/main/webapp goes to / (root of the package). This means that all files from src/main/webapp/WEB-INF go to /WEB-INF, of course.
The most important thing to know is that the classpath will only contain /WEB-INF/classes and one entry for each jar in /WEB-INF/lib. Consequently, resources outside these two locations are completely invisible for the classloader. This is also true for the xml config files directly under /WEB-INF, which is why the reference classpath:/WEB-INF/dataSource.xml will never work.
You may ask yourself, how the hell are then these xml config files loaded by Spring if they are not reachable from the classpath? The answer is simple: When you start your webapp (as opposed to executing just unit/integration tests), it is running in a Servlet Container which provides access to the ServletContext (an actual class from the Servlet API), so it uses ServletContext.getResourceAsStream() to load these files. The key for understanding is the following quote from the javadoc of this method:
This method is different from java.lang.Class.getResourceAsStream, which uses a class loader. This method allows servlet containers to make a resource available to a servlet from any location, without using a class loader.
Sorry this become way too long, but that's the whole story...
try this
#ContextConfiguration(locations = {"classpath:**/dataSource.xml",
"classpath:**/hibernate.xml",
"classpath:**/WEB-INF/beans.xml"})

How do I include two files of the same name in my spring application context?

Not sure if this has an answer, but here goes. I'm using JUnit 4.8.1 to test my Spring 3.1.0.RELEASE project. I have two JAR files on my classpath. Within each, there are files of identical names -- /module/rootContext.xml .
In my testApplicationContext.xml file (my Spring context file for my JUnit tests), is it possible to include each of those? Right now, the only thing I know how to do is
<import resource="classpath:/module/rootContext.xml" />
but I don't know how to specify the exact JAR file where each file lives.
Because I'm dealing with code that's not my own, it is not an option to change the names of the XML files within the JARs.
If you want to include both files simultaneosly, you can do it as follows:
<import resource="classpath*:/module/rootContext.xml" />
See also:
4.7.2.2 The classpath*: prefix

Resources