4

Situation

I have a fat .jar of a Spring boot application. I've externalized my configuration with an application.properties file. This file is in the same folder as the .jar, and I'm starting the .jar from the command line from within the same folder (with the command "java -jar $jarFileName").

Then an exception is thrown:

nested exception is org.springframework.beans.TypeMismatchException: 
Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is 
java.lang.NumberFormatException: For input string: "${elasticsearch.port}"

As you can see, instead of reading the value from the properties file, it just sets the string as the text in the @Value annotation, which looks like this:

@Value("${elasticsearch.port}")
private int elkPort;

The class this happens in is annotated with @Component. According to Spring docs: externalized configuration, spring should read an application.properties file outside of the jar.

When the same application.properties file is placed in src/main/resources it works fine, so the configuration file seems correct.

Any ideas why it won't load the external configuration file?

EDIT 1 I've also tried running it with --spring.config.location=file:application.properties and --spring.config.location=file:/full/path/to/application.properties but with the same result as above.

EDIT 2: classpath attempt Also tried classpath instead of file, the same as the commands above but file replaced with classpath. Lastly tried without either, so just --spring.config.location=/path/to/file; again both with relative and full path to the application.properties. All attempts gave the same result/exception.

EDIT 3 My annotated application:

@SpringBootApplication
public class ApplicationName {

    public static void main(String[] args) {
        SpringApplication.run(ApplicationName.class, args);
    }
}

EDIT 4 Tried adding a PropertySourcesPlaceholderConfigurer as follows:

@Configuration
public class PropertyConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

And then for each @Value I added a default value; it still only resolves to the default values instead of to the application.properties values.

Oromë
  • 199
  • 2
  • 16
  • Is the file readable? Does it have the correct permissions so that your application can actually read the file. – M. Deinum May 01 '18 at 13:42
  • Yes it is. Just to make sure that wasn't the error, I gave every used read-access to it, and ran the jar as administrator as well. – Oromë May 01 '18 at 13:46
  • What does your `@SpringBootApplication` annotated class look like. You aren't trying to load the file yourself using `@PropertySource` are you? – M. Deinum May 01 '18 at 13:49
  • No I'm not, and I've added my `@SpringBootApplication` class to the main post. – Oromë May 01 '18 at 14:29
  • Don't add a `PropertySourcesPlaceholderConfigurer` Spring Boot takes care of that. If it doesn't work something in your application is disabling the regular behavior. – M. Deinum May 02 '18 at 05:50

3 Answers3

1

Alright after quite some struggles, I've found the solution. I was close with PropertySourcesPlaceholderConfigurer but not quite there yet; this is the full class now:

@Configuration
public class PropertyConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        final PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();

        ppc.setIgnoreResourceNotFound(true);

        final List<Resource> resources = new ArrayList<>();

        resources.add(new FileSystemResource("relative/path/to/application.properties"));

        ppc.setLocations(resources.toArray(new Resource[]{}));

        return ppc;
    }
}

EDIT

To demonstrate the issue, I've created a repository to show the problem, see here: https://github.com/Locitao/test-external-properties

Oromë
  • 199
  • 2
  • 16
  • That shouldn't be needed as that is already done by Spring Boot. The fact that it doesn't work means you must have something in your class(path) that disable the regular behavior. – M. Deinum May 02 '18 at 05:49
  • I've made a barebones repository that mimics my own project as closely as possible, in terms of dependencies, to demonstrate the problem. I have no idea what causes the issue, but its present in the demo as well, see here: https://github.com/Locitao/test-external-properties – Oromë May 02 '18 at 07:27
  • Why are you using shadowjar? You are basically working around Spring Boot with that plugin... You should be using the Spring Boot plugin. – M. Deinum May 02 '18 at 08:21
  • Removing that (and the customization of the jar) and just use the regular way of building the jar using the Spring Boot plugin works like a charm. So basically remove the shadow plugin and jar customizations and just use `gradle clean build` to get an executable jar. You are trying to outsmart Spring Boot and in the proces destroying the way it works. – M. Deinum May 02 '18 at 08:33
  • Actually, when using `gradle clean build` or `gradle clean assemble` I come back to a previous issue I had: https://stackoverflow.com/questions/50040181/provider-not-a-subtype-inside-docker-container – Oromë May 02 '18 at 08:59
  • That can be but the fact is you are still trying to be smarter then the frameworks you are using. From what I see the only thing you want to do is add additional external dependencies to your Spring Boot application. What you should be doing is configure your application to use the `PropertiesLauncher` and in your docker entry point use the `loader.path` to add external dependencies. See https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html#executable-jar-property-launcher-features – M. Deinum May 02 '18 at 09:05
0

As it says on mentioned page, you should specify external config location

    $ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

Try without file keyword --spring.config.location=/full/path/application.properties

Pavel M
  • 104
  • 2
  • Tried that, both with relative and full paths to the configuration file; as well as with `classpath` and `file`; all combinations of those gave the same error. – Oromë May 01 '18 at 13:38
0

I just took my application.properties out of an Eclipse Spring Boot project and it failed. Then I put the file in a cfg folder in the root of the project and added program argument:

--spring.config.location=cfg/application.properties

and it worked again. Mayby if you try a relative path (no leading /) to the file (without the "file:") it will work.

Jan Larsen
  • 831
  • 6
  • 13