3

I created a multi module maven project that contains the library module (spring boot starter application) and application module (spring boot application that have included library as a dependency).

This is the structure of my project:

.
├── application
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── kotlin
│       │   │   └── com
│       │   │       └── application
│       │   │           ├── ApplicationService.kt
│       │   │           └── Application.kt
│       │   └── resources
│       │       └── application.properties
│       └── test
│           └── kotlin
│               └── com
│                   └── application
│                       └── ApplicationServiceTest.kt
├── library
│   ├── pom.xml
│   └── src
│       └── main
│           ├── kotlin
│           │   └── com
│           │       └── application
│           │           ├── LibraryService.kt
│           │           └── Properties.kt
│           └── resources
│               ├── META-INF
│               │   └── spring.factories
│               └── config
│                   └── application.properties
└── pom.xml

library/.../Properties.kt:

@ConfigurationProperties("properties")
class Properties {
    lateinit var name: String
}

library/.../LibraryService.kt:

@Service
@EnableConfigurationProperties(Properties::class)
class LibraryService(private val properties: Properties) {
    fun name() = properties.name
}

library/.../spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.application.LibraryService

library/.../config/application.properties:

properties.name=library

application/.../Application.kt

@SpringBootApplication
class Application

fun main(args: Array<String>) {
    runApplication<Application>(*args)
}

application/.../ApplicationService.kt

@Service
class ApplicationService(private val libraryService: LibraryService) {
    fun call() = libraryService.name()
}

application/.../application.properties

properties.name=application

So, I have the library module where I put application.properties file with default parameter properties.name=library. The library module has Property class injected in LibraryService. LibraryService has the simple method name() that just returns value from property. I also have application module where I use LibraryService in ApplicationService and invoke name() function, but I have application.properties in application module where properties.name=application.

I expect that application's properties.name=application overrides library's properties.name=library and ApplicationService::call must return value application instead of default value library in properties.name in library module. But this does not happen. ApplicationService::call returns value library.

I created simple junit test to reproduce this behaviour (ApplicationServiceTest.kt):

@SpringBootTest
class ApplicationServiceTest {

    @Autowired
    lateinit var applicationService: ApplicationService

    @Test
    fun test() {
        println(applicationService.call())
    }
}

It prints library. I would like to have the following behaviour: library has some several defined default properties, but I want to be able to override some of these properties in application. How to achieve that?

source code: https://github.com/grolegor/maven-multi-module-spring-starter

grolegor
  • 1,260
  • 1
  • 16
  • 22
  • have you looked at: https://stackoverflow.com/questions/52673216/spring-boot-multi-module-unable-to-read-properties-file-from-another-module – JavaBoy Jan 16 '20 at 11:43

1 Answers1

2

Form the documentation

4.2.3. Application Property Files SpringApplication loads properties from application.properties files in the following locations and adds them to the Spring Environment:

1. A /config subdirectory of the current directory

2. The current directory

3. A classpath /config package

4. The classpath root

The list is ordered by precedence (properties defined in locations higher in the list override those defined in lower locations).

So in your case [library] config/application.properties will be used, because it is higher-ordered then [application] application.properties.

Also, you cannot use application.properties twice.

Looking in your repository I would suggest that you remove the /config/application.properties from the library-module and provide default values in your Properties-class

package com.application

import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("properties")
class Properties {
    var name: String = "library"
}

Dirk Deyne
  • 6,048
  • 1
  • 15
  • 32
  • I do not understand why so. Why does `library/.../config/application.properties` have a higher order than `application/.../application.properties`? `library` has added to `application` as a maven dependency. Thus, `library/.../config/application.properties` is in classpath /config package for `application`, right? – grolegor Jan 16 '20 at 12:07
  • @grolegor the order of loading properties has nothing to do with maven. – Dirk Deyne Jan 16 '20 at 12:11
  • I tried to move the `library` application.properties under `resources`-folder, but it does not work for me, unfortunately, `library` does not see any properties in that case, it loads properties only if application.properties is in config directory. – grolegor Jan 16 '20 at 12:24
  • I published the source code on github for convenience: https://github.com/grolegor/maven-multi-module-spring-starter – grolegor Jan 16 '20 at 12:26
  • moved library/config/application.properties to resources (remember to rebuild with maven) – Dirk Deyne Jan 16 '20 at 12:52
  • what am I doing wrong? I moved application.properties and delete `properties.name=application` from `application` module. so it must to load propertry from `library` application.properties, but it does not... I pushed it into my repository here - https://github.com/grolegor/maven-multi-module-spring-starter/tree/feature/properties-under-resources Can you check please? mvn test is failed – grolegor Jan 16 '20 at 13:02
  • you are correct if you don't provide a value for `properties.name` the test will fail. edited my answer: hope it helps – Dirk Deyne Jan 16 '20 at 20:24