Reputation: 227
I will show you a little code and then I will ask a question.
SendEmail.java
package com.goode;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
@Component
@NoArgsConstructor
@Data
@AllArgsConstructor
public class SendEmail {
@Value("${email.username}")
private String username;
@Value("${email.password}")
private String password;
@Value("${email.fullAddress}")
private String fullAddress;
@Value("${email.host}")
private String host;
@Value("${email.port}")
private String port;
public boolean send(String toEmail, String subject, String message){
Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", host);
props.put("mail.smtp.port", port);
Session session = Session.getInstance(props,
new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
try {
Message createMessage = new MimeMessage(session);
createMessage.setFrom(new InternetAddress(fullAddress));
createMessage.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(toEmail));
createMessage.setSubject(subject);
createMessage.setText(message);
Transport.send(createMessage);
return true;
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
{
PropertySourcesPlaceholderConfigurer o = new PropertySourcesPlaceholderConfigurer();
o.setLocation(new ClassPathResource("application.properties"));
return o;
}
}
RootConfig.java
package com.goode.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableJpaRepositories( basePackages = {"com.goode.repository"})
@PropertySource(value = { "classpath:application.properties" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
@ComponentScan(basePackages = {"com.goode.service", "com.goode.repository", "com.goode.controller", "com.goode.business", "com.goode"})
public class RootConfig {
@Autowired
private Environment environment;
@Autowired
private DataSource dataSource;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabase(Database.POSTGRESQL);
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.goode.business");
factory.setDataSource(dataSource());
factory.setJpaProperties(jpaProperties());
return factory;
}
private Properties jpaProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return properties;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
return txManager;
}
}
application.properties
jdbc.driverClassName = org.postgresql.Driver
jdbc.url = jdbc:postgresql://localhost:5432/GoodE
jdbc.username = postgres
jdbc.password = postgres
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
hibernate.show_sql = true
hibernate.format_sql = true
email.username = xx //I replce real data to xx just to this post
email.password = xx
email.fullAddress = [email protected]
email.host = xx
email.port = xx
When I try call a send method from SendEmail console shows error:
java.lang.NullPointerException: null
in line:
props.put("mail.smtp.host", host);
So annotation @Value doesn't inject any value from application.properties to private variable in SendEmail. Why is that?
In RootConfig.java I used @Autowired, Environment and @PropertySource but I read somewhere that you can use @PropertySource only in @Configuration class so I tried find another way -> I found @Value, but I have no idea why data from application.properties are not injecting to variable. I put PropertySourcesPlaceholderConfigurer in SendEmail because I read it's necessary. I am not sure this is the right place for it but placing this in another class e.g. RootConfig didn't help. May you have any advice where should I search for bug?
Upvotes: 0
Views: 3237
Reputation: 3814
This line:
@PropertySource(value = { "classpath:application.properties" })
is unnecessary because all values from application.properties
are picked up by default. That being said, you also don't need PropertySourcesPlaceholderConfigurer
for that.
Make sure that when calling your send
method, that you are not instantiating your SendEmail
class as new SendEmail()
because that will not work as @Value
works only inside of the spring application context.
You must either do an @Autowired
or constructor injection (the latter being recommended).
Also this:
@ComponentScan(basePackages = {"com.goode.service", "com.goode.repository", "com.goode.controller", "com.goode.business", "com.goode"})
Can be replaced by this:
@ComponentScan(basePackages = {"com.goode.*"})
Upvotes: 2