3

I have issue with reading the values from the application.properties file and get the following errors,

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.7.RELEASE:run (default-cli) on project wedding-card: An exception occurred while running. null: InvocationTargetException: Error creating bean with name 'weddingCardConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'aws.s3.access.key' in value "${aws.s3.access.key}" -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.7.RELEASE:run (default-cli) on project wedding-card: An exception occurred while running. null
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)


Caused by: org.apache.maven.plugin.MojoExecutionException: An exception occurred while running. null
    at org.springframework.boot.maven.AbstractRunMojo$IsolatedThreadGroup.rethrowUncaughtException (AbstractRunMojo.java:512)
    at org.springframework.boot.maven.RunMojo.runWithMavenJvm (RunMojo.java:94)
    at org.springframework.boot.maven.AbstractRunMojo.run (AbstractRunMojo.java:244)


Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run (AbstractRunMojo.java:543)
    at java.lang.Thread.run (Thread.java:748)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'weddingCardConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'aws.s3.access.key' in value "${aws.s3.access.key}"
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties (AutowiredAnnotationBeanPostProcessor.java:380)

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'aws.s3.access.key' in value "${aws.s3.access.key}"

The pom.xml file is provided:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wedcard</groupId>
    <artifactId>wedding-card</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>wedding-card</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.16</version>
        </dependency>

        <dependency>
            <groupId>com.stripe</groupId>
            <artifactId>stripe-java</artifactId>
            <version>10.0.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk</artifactId>
            <version>1.11.163</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.jhonnymertz</groupId>
            <artifactId>java-wkhtmltopdf-wrapper</artifactId>
            <version>1.1.11-RELEASE</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
<!--        <resources>-->
<!--            <resource>-->
<!--                <directory>resources</directory>-->
<!--                <targetPath>${project.build.outputDirectory}</targetPath>-->
<!--                <includes>-->
<!--                    <include>application.properties</include>-->
<!--                </includes>-->
<!--            </resource>-->
<!--        </resources>-->
    </build>

    <repositories>
        <repository>
            <id>spring.io</id>
            <url>https://repo.spring.io/plugins-release/</url>
        </repository>
    </repositories>

</project>

The configuration source file is here:

@Configuration
@EnableSwagger2
@EnableScheduling
//@PropertySource(value = "classpath:application.properties")
public class WeddingCardConfiguration implements WebMvcConfigurer {
//    @Value("${spring.mail.host}")
//    private String smtpMailHost;
//    @Value("${spring.mail.port}")
//    private int smtpMailPort;
//    @Value("${spring.mail.username}")
//    private String mailUsername;
//    @Value("${spring.mail.password}")
//    private String mailPassword;

    @Value("${aws.s3.access.key}")
    private String awsS3AccessKey;
    @Value("${aws.s3.access.secret}")
    private String awsS3AccessSecret;
    @Value("${aws.s3.bucket.region.name}")
    private String awsBucketRegionName;


    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build();
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*");
    }

//    @Bean
//    public JavaMailSender javaMailSender() {
//        JavaMailSenderImpl sender = new JavaMailSenderImpl();
//        Properties prop = new Properties();
//        prop.put("mail.smtp.auth", "true");
//        prop.put("mail.smtp.starttls.enable", "true"); //TLS
//        sender.setJavaMailProperties(prop);
//        sender.setHost(smtpMailHost);
//        sender.setPort(smtpMailPort);
//        sender.setUsername(mailUsername);
//        sender.setPassword(mailPassword);
//
//        return sender;
//    }

    @Bean
    public AmazonS3 awsS3Client() {
        AWSCredentials credentials = new BasicAWSCredentials(awsS3AccessKey, awsS3AccessSecret);

        return AmazonS3ClientBuilder
                .standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withRegion(awsBucketRegionName)
                .build();
    }
}

The project has standard file structure provided:

enter image description here

I have tried to provide the property source information to the configuration class but still get the same error:

@Configuration
@EnableSwagger2
@EnableScheduling
@PropertySource(value = "classpath:application.properties")
public class WeddingCardConfiguration implements WebMvcConfigurer {


}

I have also tried to provide explicitly the resources info to the pom file:

     <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>resources</directory>
                <targetPath>${project.build.outputDirectory}</targetPath>
                <includes>
                    <include>application.properties</include>
                </includes>
            </resource>
        </resources>
    </build>

I keep getting the same error. Whats the issue here and how to solve it?

ps: The email config values are commented purposefully and the error is not related to that

Harsh
  • 350
  • 1
  • 4
  • 13
Arefe
  • 11,321
  • 18
  • 114
  • 168
  • Where do you include the `application-aws.properties`? – Alex R May 24 '20 at 06:06
  • It's not able to retrieve s3 access key. – Amit kumar May 24 '20 at 06:08
  • @Amitkumar Yes, is see that, he needs to have a `@PropertySource(value = "classpath:application-aws.properties")` somewhere. – Alex R May 24 '20 at 06:11
  • ^ I would not recommend that as it override Spring Boot profile functionality. Use default properties defined in application.properties and then enable the aws profile with `SPRING_PROFILES_ACTIVE` environment variable. This will will combine the properties from the two files and make them available to the application, with aws taking precedence. – julz256 May 24 '20 at 06:25
  • @AlexR this is correct, thank you so much. – Arefe May 24 '20 at 08:49

2 Answers2

2

Check that those properties are actually defined in application.properties. There is also an application-aws.properties file, if the properties are only in that file then you will need to tell Spring Boot to enable the aws profile with SPRING_PROFILES_ACTIVE=aws, or add the aws properties with empty values in application.properties.

If no Spring Boot profile is activated, it will only use the properties defined in application.properties.

If you enable the aws profile, it will use use properties from application.properties as defaults, and then any matching properties defined in application-aws.properties will override those from application.properties if defined.

If what you are trying to do it only use those AWS properties when deployed to AWS, then you might need to make a Configuration object that holds those properties in it(which is a better practice than including properties with @Value in code), and make the AmazonS3 bean creation conditional on those properties being set.

Given that your project structure is a standard Maven structure, convention over configuration should apply and there should be no need to try and explicitly include application.properties with additional class path configuration. I.e everything under /src/main/resources should be available on the class path and to the application at runtime.

julz256
  • 2,222
  • 1
  • 15
  • 12
-1

I needed to add a bean in the configuration file that would read the extra properties file,

    @Bean
    public PropertyPlaceholderConfigurer properties() {
        final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
//        ppc.setIgnoreUnresolvablePlaceholders(true);
        ppc.setIgnoreResourceNotFound(true);

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

        resourceLst.add(new ClassPathResource("application.properties"));
        resourceLst.add(new ClassPathResource("application-local.properties"));

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

Afterwards, its working fine.

Arefe
  • 11,321
  • 18
  • 114
  • 168
  • I'd really discourage this. Your production environment will now have property values from your local spring profile, probably not desirable, I'm not sure you will be able to reply on Spring property order and precedence rules. Spring profiles is the standard way of switching which set of properties to use and which to exclude based on a profile you say to use(and will also load the correct files based on the profile). Have a look here: https://www.baeldung.com/spring-profiles. Likely all you needed to do was activate your `local` profile, to load the correct files and props. – julz256 May 24 '20 at 23:49