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
Related
I want to use #Transactional annotation in the save() method of UserService(concrete class) as follows:
#Service
public class UserService {
#Transactional
public Long save(User userCommand, BindingResult result) {
...
}
}
I will use this service in MyRealm by autowiring.
public class MyRealm extends AuthorizingRealm {
#Autowired
private UserService userService;
}
However, it fails with the following error:
java.lang.IllegalArgumentException: Can not set n.r.c.s.user.UserService field n.r.c.s.realm.MyRealm.userService to com.sun.proxy.$Proxy48
Of course, it works if I remove the #Transational annotation.
My transaction manager setting is as follows:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Please, let me know what's wrong with my code?
Do I need to set up something like proxy?
When proxying is enabled you need to use interfaces, not implementations.
#Service
public class UserService implements SomeInterface {
#Transactional
public Long save(User userCommand, BindingResult result) {
...
}
}
public class MyRealm extends AuthorizingRealm {
#Autowired
private SomeInterface userService;
}
If you do not want to do this, you can always check your AOP config. you are probably doing proxy for a proxy somewhere.
Below are my classes and xml:
#Component
#Service("ApplicationService")
public class ApplicationServiceImpl implements ApplicationService{
public ApplicationDao getApplicationDao() {
return applicationDao;
}
public void setApplicationDao(ApplicationDao applicationDao) {
this.applicationDao = applicationDao;
}
#Autowired
private ApplicationDao applicationDao;
// some methods..
}
#Service
public interface ApplicationService {
// methods...
}
#Component
#Repository("ApplicationDao")
public class ApplicationDaoImpl implements ApplicationDao {
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
// other methods...
}
public interface ApplicationDao {
// methods...
}
xml file:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven/>
<context:component-scan base-package="com" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- <property name="dataSource" ref="dataSource" /> -->
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<bean id="ApplicationDao" class="com.dao.impl.ApplicationDaoImpl"/>
<bean id="ApplicationService" class="com.service.impl.ApplicationServiceImpl"/>
Here autowiring is not working.in ApplicationServiceImpl, I am getting applicationDao as null. Have not tested sessionFactory in ApplicationDaoImpl.
I know that if I am using #Component then bean declaration in xmnl is not required.
You should not instantiate service like that..
At the time of application loading, spring container will create all instances defined in spring.xml or annotated classes and it's dependencies..
So you have to access them with the following example code..
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
ApplicationService applicationService = (ApplicationService) applicationContext.getBean("ApplicationService");
Since ApplicationService is having property that is ApplicationServiceDAOImpl, it's already been created by spring container and will return you..
But in case of directly instantiating manually by you, you are just creating instance of ApplicationService but not for ApplicationServiceDAOImpl.. so it obviously returns null
I'm currently using this approach only to access beans or services..
update for comment
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
applicationContext = arg0;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
Hope it helps,
try a change like this:
import org.springframework.beans.factory.annotation.Qualifier;
#Autowired
#Qualifier("ApplicationDao")
private ApplicationDao applicationDao;
this give spring a hint.
If you are using annotations in your application, you should denote it using a tag :
<mvc:annotation-driven />
Add this line in application context xml above component scan tag.
Also, if you are using annotations, remove ApplicationDao and ApplicationService bean declarations from xml.
And don't mark you service and dao classes with both #Component and #Service or #Repository annotations. No need to mark them #Component there. Remove it.
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);
}
}
If I specify what should be injected into a property, like
<property name="xxx" ref="some_bean" />
or
<property name="xxx">
<bean .../>
</property>
then I have to write a setter method.
May I use some annotation to avoid this like #autowired?
You can do this with constructor injection. 3 main ways to do this:
XML:
<bean id="beanA" class="com.BeanA">
<constructor-arg ref="beanB"/>
</bean>
<bean id="beanB" class="com.BeanB"/>
JavaConfig:
#Configuration
public class MyConfig {
#Bean
public BeanA beanA() {
return new BeanA(beanB());
}
#Bean
public BeanB beanB() {
return new BeanB();
}
}
Autowiring:
#Component
public class BeanA {
private final BeanB beanb;
// This assumes that there is a BeanB in your application context already
#Autowired
public BeanA(final BeanB beanB) {
this.beanB = beanB;
}
}
You can take Autowiring even further, and wire directly to the field:
#Component
public class BeanA {
// This assumes that there is a BeanB in your application context already
#Autowired
private final BeanB beanb;
}
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 ...
}