5

I have two spring boot apps. The first is an API library that's pulled into the second (a web application) as a dependent jar.

The first, is an API library that houses functions to create "cases" in an IBM solution. It's a standalone type jar that has a service class that exposes methods like getCaseXMLForDocId(String docId) or createCaseForAgreementNumber(String agreementNumber)

The first library called CaseInvocationAPI has an application.properties file which has several properties. For example:

caseinvocation.query.fetchNonProcessedCaseXml=SELECT Id, CaptureSource, AgreementNumber, CaptureSourceID FROM CaseInvocation WHERE ProcessIndicator IN (0, 2)

The service class has a method which makes a query, grabbing that query string from a member variable that's populated with a property from the application.properties file:

  @Value("${caseinvocation.query.fetchNonProcessedCaseXml}")
  private String selectNonProcessedQueryString;

The second SpringBoot app is a webapplication that has REST controllers. These controllers expose endpoints that call the CaseInvocationAPI library, specifically the CaseInvocationService class.

The problem I am having is that when the SpringBoot WEBAPPLICATION starts up, the context configuration blows up with the following error:

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'caseinvocation.query.fetchNonProcessedCaseXml' in string value "${caseinvocation.query.fetchNonProcessedCaseXml}"
    at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
    at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
    at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:219)
    at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:193)
    at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:813)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1039)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
    ... 45 common frames omitted

It appears that when the WebApp starts up, when it's trying to build the classes from the dependent jar, those properties are not being found.

I didn't think I had to copy each and every property out of the dependent jar application.properties file into an application.properties file in the Webapp project.

Why isn't the WebApp project (CaseInvocationWebApp) picking up the application.properties file from the dependent jar file (CaseInvocationAPI)?

I checked the compiled jar file (CaseInvocationAPI) and the application.properties file is there in the jar.

jeremy
  • 111
  • 2
  • 6
  • Oh and if I copy the following line: ``` caseinvocation.query.fetchNonProcessedCaseXml=SELECT Id, CaptureSource, AgreementNumber, CaptureSourceID FROM CaseInvocation WHERE ProcessIndicator IN (0, 2) ``` From the application.properties file in the API jar project and put it into the WebApp project, the property is found and set. But I shouldn't have to copy all the properties from one file to the other, right? Shouldn't springboot simply pull in the applications.property file from the dependent jar on the classpath? – jeremy Nov 01 '19 at 18:20
  • 1
    Does your second jar (the REST webapp) have an application.properties too? If so, it will load this file and ignore the other in the first jar, since you're starting the application from the second. Take a look at this [question](https://stackoverflow.com/questions/33229793/how-to-add-multiple-application-properties-files-in-spring-boot), it looks similar to what you are trying to do. – Paschoal Nov 01 '19 at 18:42
  • Yes. Both jars have an application.properties file. I did not realize that it overwrote one with the other. That's good to know. Thanks for the answer! – jeremy Nov 01 '19 at 18:55

2 Answers2

2

Looks like the problem was related to the fact that both the child jar and the webapp have application.properties files. I wasn't aware that the parent WebApp application.properties sort of overwrites the others (ignoring all others really).

Special thanks to Paschoal for his response.

You can see details on the answer here: Adding multiple application.properties files

jeremy
  • 111
  • 2
  • 6
2

There are 3 ways (that I can think of) you can approach this:

  1. The dependency, API library, should not have an application.properties since it's a library and not an executable Spring boot application in itself. You only define the properties in your web application's application.properties, even for the API library. But, here the assumption is that you have access to the API library jar.

  2. You can redefine all the properties in web application's application.properties essentially overriding them.

  3. Explicitly configure the Spring boot application to use both the application.properties files, each for different set of properties. Caveat: The file names must be different, as config location is classpath for both.

@SpringBootApplication
public class WebApplication {

  public static void main(String[] args) {
    SpringApplication app = new SpringApplicationBuilder(WebApplication.class)
        .properties("spring.config.location=classpath:api-application.properties,classpath:application.properties")
    app.run(args);
  }
}
priyank-sriv
  • 1,094
  • 6
  • 12
  • doesn't work for me. First you're missing.build at the end of the line. Second, and more crucially, this adds a property called "spring.config.location" to the environment, but doesn't actually load any properties from that source. – Rhubarb Apr 09 '20 at 17:24