4

I have a common Spring Boot project used by other Spring Boot projects. So, I have a multi-module setup.

The common project uses Java Mail and I want configure it in the common project.

Per Spring Boot doc,

If spring.mail.host and the relevant libraries (as defined by spring-boot-starter-mail) are available, a default JavaMailSender is created if none exists.

So, here's my library.yml file,

---
spring:
    mail:
        host: mobile.example.com
        port: 25

And here's my gradle file:

plugins {
    id 'java'
    id 'eclipse'
    id 'maven-publish'
    id 'io.spring.dependency-management' version '1.0.3.RELEASE'
}

repositories {
   mavenCentral()
   mavenLocal()
}

group = 'com.example.test'
version = '1.0.0'

jar {
   baseName = 'boot-library-test'
   version = '1.0.0'
}

dependencies {

    compile('org.springframework.boot:spring-boot-starter')
    compile('org.springframework.boot:spring-boot-starter-mail')
    testCompile('org.springframework.boot:spring-boot-starter-test')
 }

 dependencyManagement {
     imports { mavenBom('org.springframework.boot:spring-boot-
     dependencies:1.5.4.RELEASE') }
  }

So, I think I've met the prerequisites for spring to create the JavaMailSender. Right?

I have this configuration class:

package com.example.library;

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;

@Configuration
public class LibraryApplicationConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer dataProperties() {
      PropertySourcesPlaceholderConfigurer 
propertySourcesPlaceholderConfigurer = new 
PropertySourcesPlaceholderConfigurer();
      YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
      yaml.setResources(new ClassPathResource("library.yml"));
      propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
      return propertySourcesPlaceholderConfigurer;
    }
} 

Here's where I want Spring Boot to wire JavaMailSender:

package com.example.library.mail;

import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;

@Component
public class Mail {

    private final JavaMailSender javaMailSender;

    public Mail(JavaMailSender javaMailSender) {
        this.javaMailSender = javaMailSender;
   }

   public JavaMailSender getJavaMailSender() {
        return javaMailSender;
    }    
}

Here's my test config:

package com.example.library;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages="com.example.library")
public class LibraryTestConfiguration {
}

And the test itself:

package com.example.library;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.library.mail.Mail;

@RunWith(SpringRunner.class)
@SpringBootTest(classes=LibraryTestConfiguration.class)
public class LibraryTest {

    @Autowired
    private Mail mail;

     @Test
     public void contextLoads() {
         assertThat(mail.getJavaMailSender()).isNotNull();
     }
}

But the test fails with

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

If I change library.yml to application.yml (and remove PropertySourcesPlaceholderConfigurer bean), it works. (I have all the code here so you should get the same result if you try.) But since this is a library, I can't name the file application.yml since it will conflict with other Spring Boot projects that use this library. Furthermore, I want to use a yml file not a properties file (so I cannot use @PropertySource).

How can I have Spring Boot create and wire JavaMailSender in a library project using yml props?

James
  • 2,876
  • 18
  • 72
  • 116
  • I believe this may be a Spring Boot bug. As a workaround, I'm explicitly defining a `JavaMailSender` bean in a `@Configuration` class. Hopefully, it's not a bug though and someone knows a way to solve. Has anyone been able to reproduce the issue using the complete code above? – James Nov 21 '17 at 15:02

0 Answers0