Spring 4 mail configuration via java config - spring

Is there some example of how MailSender can be configured via java config?
All examples that I've seen uses xml to create needed beans:
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="mail.mycompany.com"/>
</bean>
<!-- this is a template message that we can pre-load with default state -->
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
<property name="from" value="customerservice#mycompany.com"/>
<property name="subject" value="Your order"/>
</bean>

The code you posted (along with some small improvements to make it more configurable) would be transformed into the following Java config:
#Configuration
public class MailConfig {
#Value("${email.host}")
private String host;
#Value("${email.from}")
private String from;
#Value("${email.subject}")
private String subject;
#Bean
public JavaMailSender javaMailService() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(host);
return javaMailSender;
}
#Bean
public SimpleMailMessage simpleMailMessage() {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom(from);
simpleMailMessage.setSubject(subject);
return simpleMailMessage;
}
}
You should also be aware of the fact that Spring Boot (which you have not mentioned whether or not you are using) can auto-configure an JavaMailSender for you. Check out this part of the documentation

#Configuration
public class AppConfig {
#Value("${mail.host}")
private String host;
#Bean
public JavaMailSender emailService() {
JavaMailSender javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(host);
return javaMailSender;
}
#Component
public class EmailServiceImpl implements EmailService {
#Autowired
public JavaMailSender emailSender;
public void sendSimpleMessage( String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
emailSender.send(message);
}
}

Related

#Autowired Spring service is null in Play Framework 2.6 application

I'm refactoring an application from Play Framework 2.2.x to Play Framework 2.6.x, and in the updated version of the app an #Autowired spring service is null (I didn't use "new" so that Spring would be confused).
AuthentecatedAction class:
#Scope("prototype")
#Component
public class AuthenticatedAction extends Action<Authenticated>
{
private final Logger log = LoggerFactory.getLogger(getClass());
#Autowired
ABCUserService ABCUserService;
#Autowired
AccessTokenService accessTokenService;
#Autowired
AccessTokenValidator accessTokenValidator;
#Override
public CompletionStage<Result> call(Http.Context ctx)
{
AccessToken accessToken;
try {
accessToken = accessTokenService.getAccessTokenFromHeader(ctx._requestHeader().headers());
} catch (Throwable throwable) {
return ResultUtils.handleError(new ValidationException(FORBIDDEN, String.format("Access token service is null. %s", throwable.getMessage())));
}
// Some more code here
}
// Some more code here
}
Here accessTokenService is #Autowired, but it is always null.
AccessTokenService class:
#Service
public class AccessTokenService extends JedisBaseService
{
private final Logger log = LoggerFactory.getLogger(getClass());
#Autowired
private ConfigurationService configurationService;
#Autowired
private EncryptionService encryptionService;
#Inject
public AccessTokenService(JedisPool jedisPool) {
super(jedisPool);
}
// some methods
}
JedisBaseService class:
public class JedisBaseService extends Controller
{
private final Logger log = LoggerFactory.getLogger(getClass());
private JedisPool jedisPool;
#Inject
public JedisBaseService(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
// some methods
// TODO: Check that solution with iserting JedisPool works
// See https://github.com/playframework/play-plugins/tree/master/redis for reference
protected Jedis getJedis()
{
return jedisPool.getResource();
}
}
Please, help me understand why #Autowired in AuthentecatedAction class accessTokenService is always null.
EDIT:
I should probably add, that my build.sbt file contains the line:
// https://mvnrepository.com/artifact/org.springframework/spring-context
"org.springframework" % "spring-context" % "4.3.10.RELEASE"
My routes file contains following lines:
POST /accesstokens #api.controller.accesstoken.AccessTokenController.createAccessToken()
DELETE /accesstokens #api.controller.accesstoken.AccessTokenController.deleteAccessToken()
So, I use dynamic controller dispatching to manage controller instances (by prefixing a controller class name with the # symbol in the routes file).
There is a controller for access tokens:
#Controller
public class AccessTokenController extends ABCController
{
#Autowired
private AccessTokenService accessTokenService;
#Autowired
private ABCUserService ABCUserService;
#Autowired
private ActivityCreationService activityCreationService;
#Autowired
private LiveUpdateService liveUpdateService;
#BodyParser.Of(BodyParser.TolerantJson.class)
#ResponseContentType(type = "accessToken")
public Result createAccessToken() throws ABCControllerException
{
// Implementation
}
public Result deleteAccessToken() throws ABCControllerException
{
// Implementation
}
}
Global object of my application that delegates controller instances management:
public class ABCGlobal
{
private final Logger log = LoggerFactory.getLogger(getClass());
protected static ApplicationContext ctx;
private final ActorSystem system;
#Inject
public ABCGlobal(ActorSystem system) {
this.system = system;
}
public static ApplicationContext getApplicationContext()
{
return ctx;
}
public void onStart(Application app)
{
String springConfigurationName = app.configuration().getString("spring.context");
ctx = new ClassPathXmlApplicationContext(springConfigurationName);
log.info("Loading spring configuration: {}", springConfigurationName);
// Some other code
}
// see: http://typesafe.com/blog/announcing-play-framework-21-the-high-velocit
public <A> A getControllerInstance(Class<A> clazz)
{
return ctx.getBean(clazz);
}
// Some other code
}
Here is the associated conf/components.xml file that is used to configure Spring:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="api, service"/>
<context:property-placeholder location="classpath:application-base.conf" />
<context:property-placeholder location="classpath:application.conf" />
<bean class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean" id="resourceConverterFactory">
<property name="serviceLocatorInterface" value="service.resource.conversion.ResourceConverterFactory">
</property>
</bean>
<bean class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean" id="scraperFactory">
<property name="serviceLocatorInterface" value="service.scraping.ScraperFactory">
</property>
</bean>
<bean id="storageService" class="service.storage.impl.MongoGridFSStorageService"/>
<bean id="configurationService" class="service.configuration.impl.PlayConfigurationService">
<constructor-arg value="com.typesafe.config.Config" name="config">
</constructor-arg>
</bean>
<bean id="mailService" class="service.mail.impl.MailGunApiMailService"/>
</beans>
And in my application-base.conf file I have the following:
# Spring configuration
# ~~~~~
# Define what spring context should be used.
spring.context="components.xml"

Spring data MongoDb cannot convert proxy bean

I'm using Spring AOP with AspectJ and Spring Data MongoDb and am having a world of trouble persisting objects.
In this case, I have an AclEntryDaoImpl that exposes AclEntryImpl. When AclEntryImpl is provided a Principal that is a standard Java object (a "non-Spring" bean), mongoTemplate.save() works as expected. However when Principal is a Spring bean, Mongo is unable to convert the object and results in a MappingException org.springframework.data.mapping.model.MappingException: No id property found on class class com.sun.proxy.$Proxy33. All my objects need to be Spring beans so that (a) I keep my objects decoupled and (b) my AOP (LoggingAspect) is invoked.
Lastly, I cannot take advantage of Spring converters because Mongo sees the target object AclEntryImpl as a proxy com.sun.proxy.$Proxy33 and so Converter<Principal, DBObject> is never invoked.
Any and all help would be greatly appreciated!
Snippets:
Here's my Spring XML configuration:
<beans>
<context:component-scan base-package="a.b" />
<context:property-placeholder location="config.properties" />
<aop:aspectj-autoproxy />
<bean id="loggingAspect" class="a.b.LoggingAspect" />
<mongo:db-factory host="${database.host}" port="${database.port}" dbname="${database.dbname}" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>
<bean id="aclEntryDao" class="a.b.AclEntryDaoImpl">
<lookup-method name="createAclEntry" bean="aclEntry" />
</bean>
</beans>
AclEntryImpl:
#Document
#Component
#Scope("prototype")
public class AclEntryImpl implements AclEntry {
#Id
private String id;
private String service;
#DBRef #Expose
private Principal principal;
#Expose
private boolean accessGranted;
#Expose
private List<Permission> permissions;
#Override #Loggable #MongoSaveReturned
public AclEntry save() {
return this;
}
...getters and setters...
}
AclEntryDaoImpl:
#Repository
public abstract class AclEntryDaoImpl implements AclEntryDao {
#Override #Loggable
public AclEntry addEntry(String serviceName, Principal principal, Permission[] permissions, boolean accessGranted) throws Exception {
AclEntry entry = createAclEntry(); //<-- Spring lookup-method
entry.setService(serviceName);
entry.setPrincipal(principal); //<-- com.sun.proxy.$Proxy33
entry.setAccessGranted(accessGranted);
for (Permission permission : permissions) {
if (!entry.addPermission(permission)) {
return null;
}
}
return entry.save();
}
... other DAO methods ...
}
LoggingAspect:
#Aspect
public class LoggingAspect {
#Autowired
private MongoTemplate mongoTemplate;
#Pointcut("execution(!void a.b..*.*(..))")
public void returningMethods() {}
#AfterReturning(pointcut="returningMethods() && #annotation(MongoSaveReturned)", returning="retVal")
public Object mongoSaveReturnedAdvice(Object retVal) {
Logger logger = null;
try {
logger = getLogger(retVal);
mongoTemplate.save(retVal); //<-- throws MappingException
log(logger, "save: " + retVal.toString());
} catch (Exception e) {
log(logger, "throw: " + e.toString());
}
return retVal;
}
... other logging methods ...
}

Getting jdbcTemplate null in Spring Junit test case

I am writing junit test case for spring 3 restful services. When I am trying to execute it as junit, i am getting JdbcTemplate as null. I am not sure where I did the mistake. Please help me to get out of this...
LoginServiceImpl.java file,
private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
System.out.println("--------------"+jdbcTemplate.toString());
}
private static Map<String, AuthToken> tokenHash = new ConcurrentHashMap<String, AuthToken>();
private static String authTokenDetailsSql = "select * from authtoken where token = :token";
#Override
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseBody
public ServiceBean newAccount(#RequestBody Registration registration) {
String newAccountSql = "INSERT INTO account (email,password,name) VALUES (:email,:password,:name)";
ServiceDataBean<AuthToken> retBean = new ServiceDataBean<AuthToken>();
try {
System.out.println("register service calling.....");
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("email", registration.getEmail());
messageDigest = MessageDigest.getInstance("MD5");
byte[] md5 = new byte[64];
messageDigest.update(registration.getPassword().getBytes("iso-8859-1"), 0, registration.getPassword().length());
md5 = messageDigest.digest();
namedParameters.addValue("password", convertedToHex(md5));
namedParameters.addValue("name", registration.getName());
GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();
// TODO what to do with the updInt also check it's not -1
int updInt = jdbcTemplate.update(newAccountSql, namedParameters, generatedKeyHolder);
long accountId = (Long) generatedKeyHolder.getKeys().get("GENERATED_KEY");
registration.getDevice().setOwner(registration.getId());
fotoframz.register(registration.getDevice());
Login login = new Login();
login.setEmail(registration.getEmail());
login.setPassword(registration.getPassword());
login.setDevice(registration.getDevice());
retBean = (ServiceDataBean<AuthToken>) this.login(login);
System.out.println("form register");
} catch (Throwable e) {
retBean.setStatusCode("001");
e.printStackTrace();
}
return retBean;
}
I am getting jdbctemplate=null at int updInt = jdbcTemplate.update(newAccountSql, namedParameters, generatedKeyHolder);
my applicationContext-test.xml file is in src/test/resources folder..applicationContext-test.xml file
<context:component-scan base-package="net.mss.ff.services" />
<context:property-placeholder location="classpath:/app.properties" />
<!-- <task:annotation-driven /> -->
<context:annotation-config />
<!-- <import resource="apicontroller_v1-servlet.xml"/>
<import resource="applicationContext.xml"/> -->
<bean id="photoService" class="net.mss.ff.services.core.api.impl.PhotoServiceImpl">
<property name="rootStorageFolder" value="${storage.root}" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" />
LoginServiceImplTest
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/applicationContext-test.xml"})
public class LoginServiceImplTest {
LoginServiceImpl loginServiceObj = new LoginServiceImpl();
Device deviceMock;
#Autowired
private Fotoframz fotoframz;
/*private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}*/
#Before
public void setUp() throws Exception {
//loginServiceObj = new LoginServiceImpl();
}
#After
public void tearDown() throws Exception{
}
/**
* Test method for {#link net.mss.ff.services.core.api.impl.LoginServiceImpl#newAccount(net.mss.ff.services.core.beans.Registration)}.
*/
#Test
public void testNewAccount() {
Registration mockRegObj = new Registration();
deviceMock = new Device();
deviceMock.setActive(false);
deviceMock.setHeight(45);
//deviceMock.setId(4568);
deviceMock.setName("Android");
deviceMock.setOwner(1111);
deviceMock.setPlatform("Windows NT");
deviceMock.setUuid("522601");
deviceMock.setVersion("1.0");
deviceMock.setWidth(76);
mockRegObj.setEmail("bbb#gmail.com");
/*mockRegObj.setId(399);*/
mockRegObj.setName("bbb");
mockRegObj.setPassword("BBB");
mockRegObj.setDevice(deviceMock);
loginServiceObj.newAccount(mockRegObj);
//assertEquals("New Account Creation", "", "");
}
}
anything needs to modify in test class, please let me know..
In your test the LoginServiceImpl loginServiceObj = new LoginServiceImpl();
is not instantiated by spring, thus no annaotions will be applied. You need to autowire it, or inject it some other way. Spring 3.2 makes this kinda thing super easy and nice to use.
The rest of my answer is still good adivce :
You have not declared or instantiated the jdbctemplate in your java code. And you have not defined it in your xml file.
You need this
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="dateSource"/>
</property>
</bean>
and then this as instance variable (assuming your using annoations)
#Resource(name = "jdbcTemplate")
private JdbcTemplate jdbcTemplate;
As #NimChimpsky mentioned you need to define your jdbcTemplate in your bean xml file and then in your instance variable you can also do.
#Autowired
private JdbcTemplate jdbcTemplate;

Spring JavaMailSenderImpl throws an TypeMismatchException

I configured JavaMail with Spring framework using JavaMailSenderImpl in my application.Actually I tried to load mailing properties from database and done little bit changes at spring config.xml file.
But i got error
"Initialization of bean failed; nested exception is
org.springframework.beans.TypeMismatchException: Failed to convert
property value of type [com.core.springexamples.UCMSMailImpl] to
required type [org.springframework.mail.MailSender] for property
'mailSender'; nested exception is java.lang.IllegalArgumentException:
Cannot convert value of type [com.core.springexamples.UCMSMailImpl] to
required type [org.springframework.mail.MailSender] for property
'mailSender': no matching editors or conversion strategy found"
whatever changes are implemented in my application,those are mentioned in below.
Step 1:
<bean id="javaMailImpl" class="org.springframework.mail.javamail.JavaMailSenderImpl"></bean>
Step 2:-
<bean id="mailSender" class="com.core.springexamples.UCMSMailImpl" scope="prototype" init-method="configuredProperties">
<property name="javaMailImpl" ref="javaMailImpl"></property>
</bean>
com.core.springexamples.UCMSMailImpl:-
public class UCMSMailImpl {
private JavaMailSenderImpl javaMailImpl;
private ConfigDAO configDAO;
public void configuredProperties(){
System.out.println("UCMSMailImpl::configuredProperties");
Properties props=new Properties();
String[] mildata=configDAO.getMailingPropData();
props.put("mail.smtp.auth", mildata[0]);
props.put("mail.smtp.starttls.enable", mildata[2]);
props.put("mail.smtp.host", mildata[3]);
props.put("mail.smtp.port", mildata[4]);
props.put("mail.smtp.host", mildata[5]);
props.put("username", mildata[6]);
props.put("password",mildata[7]);
getJavaMailImpl().setJavaMailProperties(props);
}
public JavaMailSenderImpl getJavaMailImpl() {
return javaMailImpl;
}
public void setJavaMailImpl(JavaMailSenderImpl javaMailImpl) {
this.javaMailImpl = javaMailImpl;
}
public void setConfigDAO(ConfigDAO configDAO){
this.configDAO=configDAO;
}
public ConfigDAO getConfigDAO(){
return configDAO;
}
Step 3:-I am trying send the mail from MailSender.send using UCMSMailImpl java class.I refered the UCMSMailImpl bean.
<bean id="sendMail" class="com.core.springexamples.JavaMailing">
<property name="mailSender" ref="mailSender"></property>
</bean>
public class JavaMailing {
private MailSender mailSender;
public void sendMail(String from,String to,String text,String subject){
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(to);
message.setSubject(subject);
message.setText(text);
mailSender.send(message);
}
/**
* #return the mailSender
*/
public MailSender getMailSender() {
return mailSender;
}
/**
* #param mailSender the mailSender to set
*/
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
Step 4:- I trying to test the sendMail bean
ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext-mail.xml");
JavaMailing m=(JavaMailing)context.getBean("sendMail");
m.sendMail("john.ch#gmail.com", "john.c#gmail.com", "TEST MAIL", "TEST MAIL");
But i got exception is TypeMismatchException: Failed to convert property value of type [com.core.springexamples.UCMSMailImpl] to required type [org.springframework.mail.MailSender] for property
Please help me.
You cannot assign a class to an interface, if it doesn't implement the interface. UCMSMailImpl does not implement MailSender. Keep the rest as it is and change your UCMSMailImpl like this:
public class UCMSMailImpl implements MailSender {
private JavaMailSenderImpl javaMailImpl;
private ConfigDAO configDAO;
// do your property initialization
// ...
// implement interface methods
void send(SimpleMailMessage simpleMessage) throws MailException {
this.javaMailImpl.send(simpleMessage);
}
void send(SimpleMailMessage[] simpleMessages) throws MailException {
this.javaMailImpl.send(simpleMEssages);
}
}
If you cannot change UCMSMailImpl, extend it:
public class MyUCMSMailImpl extends UCMSMailImpl implements MailSender {
void send(SimpleMailMessage simpleMessage) throws MailException {
this.getgetJavaMailImpl().send(simpleMessage);
}
void send(SimpleMailMessage[] simpleMessages) throws MailException {
this.getgetJavaMailImpl().send(simpleMEssages);
}
}
and change your configuration:
<bean id="mailSender" class="your.package.MyUCMSMailImpl" scope="prototype" init-method="configuredProperties">
<property name="javaMailImpl" ref="javaMailImpl"></property>
</bean>

Null pointer when autowiring the bean into JSF Managed bean

I have developed a Email service using Spring Java mail and Velocity Template like below.
Email.java
#Component
public class Email {
private JavaMailSender mailSender;
private VelocityEngine velocityEngine;
#Autowired
private ApplReviewService applReviewService;
#Autowired
private UserService userService;
public void setUserService(UserService userService ) {
this.userService=userService;
}
public UserService getuserService() {
return userService;
}
#Autowired
#Required
public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public VelocityEngine getVelocityEngine() {
return velocityEngine;
}
#Autowired
#Required
public void setVelocityEngine(VelocityEngine velocityEngine) {
this.velocityEngine = velocityEngine;
}
// Method to send Email.
}
My Spring.xml
<context:component-scan base-package="com.test.common"/>
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
</bean>
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<value>
resource.loader=class
class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
</value>
</property>
</bean>
#ManagedBean(name="person")
#SessionScoped
Public class Person{
#Autowired
private Email email ; // getter and setter for this.
}
I am trying autowire my Email class into Jsf managedBean but I am getting null pointer exception. Where I am going wrong.
You cannot inject a Spring bean like that in a JSF managed bean. Change it to
#ManagedBean(name="person")
#SessionScoped
Public class Person{
#ManagedProperty(value="#{email}")
private Email email ; // getter and setter for this.
}
See also:
#Scope("request") not working

Resources