#Autowired Spring service is null in Play Framework 2.6 application - spring

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"

Related

Load particular bean using Spring SPEL method

I have a requirement to load specific bean on a condition which i am reading from config properties .
I have two beans so i am trying to load it as below
public interface MediatorInt {
public void init();
}
class A implements MediatorInt {
init() { It does some task }
}
class B implements MediatorInt {
init(){ It does some task }
}
public class MasterNewGenImpl {
#Autowired
#Qualifier("config")
private Configuration config;
#Autowired
MediatorInt mediatorInt;
private final Logger logger = Logger.getLogger(getClass());
public void startService() {
mediatorInt.init();
}
}
<context:component-scan base-package="com.ca"/>
<bean id="config" class="com.ca.configuration.ConfigImplementation"/>
<bean id="masterSlave" class="com.ca.masterslave.A"/>
<bean id="systemState" class="com.ca.masterslave.B"/>
<bean id="masterSlaveNewGen" class="com.ca.masterslave.MasterNewGenImpl">
<property name = "mediatorInt" value="#{config.getMediatorMode() == 'true' ? 'systemState' : 'masterSlave'}" />
</bean>
But the bean is not getting loaded .
Can you please help if any error in the syntax or the method of using it .

Spring Boot #Transactional not working when on #Service class (instead of controller)

I thought it was best practice to put the #Transactional annotation on the service layer classes and not on the controllers (see f.e. Why we shouldn't make a Spring MVC controller #Transactional?). But this not working on my Spring Boot application. Why is that?
The registerAction method in the controller (see code below) performs multiple service calls. When f.e. the mailService.sendActivationMail(...) fails, I want to rollback the inserted user from the userService.registerUser(...) call. Do I need to put the #Transactional annotation on the controller class or not?
My Spring Boot application correctly uses transactions when the #Transactional annotation is set on the controller class:
AuthController.java
#RestController
#RequestMapping("/api/auth")
#Transactional
public class AuthController {
#Autowired
private UserService userService;
#Autowired
private ProfileService profileService;
#Autowired
private MailService mailService;
#RequestMapping(path = "register", method = RequestMethod.POST)
public Profile registerAction(#Valid #RequestBody Registration registration) {
ApiUser user = userService.registerUser(registration);
Profile profile = profileService.createProfile(user, registration);
mailService.sendActivationMail(user);
return profile;
}
}
but transactions don't work when the #Transactional annotation is set on the Service classes instead (and not on the controller):
UserService.java
#Service
#Transactional
public class UserService {
#Autowired
private ApiUserRepository userRepository;
public ApiUser registerUser(Registration registration) {
...
userRepository.save(user);
...
}
}
My configuration classes:
SpringApiApplication.java
#SpringBootApplication
public class SpringApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApiCommonApplication.class, args);
}
}
ApiConfiguration.java
#Configuration
#EnableJpaAuditing
#EnableTransactionManagement
public class ApiConfiguration {
#Autowired
private ApiProperties properties;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public UsernameCanonicalizer usernameCanonicalizer() {
return new UsernameCanonicalizer();
}
#Bean
public EmailCanonicalizer emailCanonicalizer() {
return new EmailCanonicalizer();
}
#Bean
public ApiTokenHandler activationTokenHandler() {
return new StandardApiTokenHandler(properties.getActivationTokenDuration());
}
}
#M.Deinum got me on the right track. Spring (boot) doesn't automatically wrap your controller calls in a transaction like other frameworks do. So you have to either add a #Transactional annotation to your controller, or move the code from the controller class to a service class.
Moving the code from the controller class to a service class is the better thing to do since (amongst other things) makes the code better testable. So that's what I did.
AuthenticationService.java
#Service
public class AuthenticationService {
#Autowired
private UserManager userManager;
#Autowired
private ProfileManager profileManager;
#Autowired
private MailManager mailManager;
#Transactional
public Profile registerUser(Registration registration) {
ApiUser user = userManager.registerUser(registration);
Profile profile = profileManager.createProfile(user, registration);
mailManager.sendActivationMail(user);
return profile;
}
...
}
AuthController.java
#RestController
#RequestMapping("/api/auth")
public class AuthController {
#Autowired
private AuthenticationService authenticationService;
#RequestMapping(path = "register", method = RequestMethod.POST)
#ApiOperation(value = "Registers a user")
public Profile register(#Valid #RequestBody Registration registration) {
return authenticationService.registerUser(registration);
}
...
}
You can place the #Transactional annotation before an interface definition, a method on an interface, a class definition, or a public method on a class. However, the mere presence of the #Transactional annotation is not enough to activate the transactional behavior.
The #Transactional annotation is simply metadata that can be consumed by some runtime infrastructure that is #Transactional-aware and that can use the metadata to configure the appropriate beans with transactional behavior.
In the preceding example, the <tx:annotation-driven/> element switches on the transactional behavior.
// Below is the service class that we want to make transactional
#Transactional
public class DefaultEmployeeService implements EmployeeService {
void insertEmployee(Employee Employee);
void updateEmployee(Employee Employee);
}
XML Configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" ...>
<!-- this is the service object that we want to make transactional -->
<bean id="employeeService" class="service.DefaultEmployeeService"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
Some points that you can try:
Do all above mentioned configurations.
Remove #Transactional configuration from Controller.
Reference the Service object along with Transaction manager bean.
More Details: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html

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 ...
}

spring 2.5.6 DI issue in jsf application

i get NPE(null pointer exception) each time when i try to insert data into database. help me to resolve this issue. i have import all the necessary libraries which are requried for spring.
this is my applicationContext.xml file where i have configure all the beans.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="personService" class="com.ecommerce.assignment.service.PersonService">
<property name="personDAO" ref="personDAO" />
</bean>
<bean id="personBean" class="com.ecommerce.assignment.bean.PersonBean" />
<bean id="personDAO" class="com.ecommerce.assignment.dao.PersonDAO" />
</beans>
this is interface of person DAO.
public interface IPersonDAO {
public void addPerson(Person instance);
}
this personDAO class implementing IpersonDAO interface and its unimplemented methods.
public class PersonDAO implements IPersonDAO {
#Override
public void addPerson(Person instance) {
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction().begin();
session.saveOrUpdate(instance);
session.getTransaction().commit();
session.close();
}
}
this is interface personService.
public interface IPersonService {
public void addPerson(Person instance);
}
public class PersonService implements IPersonService,Serializable {
private IPersonDAO personDAO;
public IPersonDAO getPersonDAO() {
return personDAO;
}
public void setPersonDAO(IPersonDAO personDAO) {
this.personDAO = personDAO;
}
#Override
public void addPerson(Person instance) {
getPersonDAO().addPerson(instance);
}
}
public class PersonBean implements Serializable {
private static final long serialVersionUID = 1L;
private String emailAddress;
private String password;
private String username;
#ManagedProperty(value = "#{personService}")
private IPersonService iPersonService;
public void addPerson(){
try{
Person person = new Person();
person.setUsername(getUsername());
person.setEmailAddress(getEmailAddress());
person.setPassword(getPassword());
iPersonService.addPerson(person);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
As your person bean is managed by Spring, you should use #Autowired annotation to make dependency injection, or inject it via XML, as you did for PersonService. You can as well declare the bean as #Component and #Scope.
You error is in injecting service in a bean by using JSF's #ManagedProperty annotation that works solely within JSF context, that is, with JSF managed beans, annotated with #ManagedBean, or declared via XML.

How do I autowire a field when running Spring4JUnitRunner test?

I'm using Spring 3.1.0.RELEASE. I'm having trouble autowiring a private variable from a Spring4JUnitRunner class. My JUnit class is ...
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "file:src/main/webapp/WEB-INF/dispatcher-servlet.xml" })
public class RegistrationControllerTest {
#Autowired
private ApplicationContext applicationContext;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private HandlerAdapter handlerAdapter;
private RegistrationController controller;
#Before
public void setUp() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
// I could get the controller from the context here
controller = new RegistrationController();
final RegistrationValidation registrationValidation = new RegistrationValidation();
controller.setRegistrationValidation(registrationValidation);
}
Not sure if its relevant, but here's my dispathcer-servlet.xml file ...
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- Enable annotation driven controllers, validation etc... -->
<mvc:annotation-driven />
<context:component-scan base-package="com.myco.eventmaven" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/messages" />
</bean>
</beans>
Here is my controller. The "usersDao" field is null during my test, causing NullPointerExceptions (works fine when I run it as a normal webapp in JBoss) ...
#Controller
#RequestMapping("/registrationform.jsp")
public class RegistrationController {
private static Logger LOG = Logger.getLogger(RegistrationController.class);
#Autowired
private RegistrationValidation registrationValidation;
#Autowired
private UsersDao usersDao;
public void setRegistrationValidation(
RegistrationValidation registrationValidation) {
this.registrationValidation = registrationValidation;
}
// Display the form on the get request
#RequestMapping(method = RequestMethod.GET)
public String showRegistration(Map model) {
LOG.debug("called GET method.");
final Registration registration = new Registration();
model.put("registration", registration);
return "user/registrationform";
}
// Process the form.
#RequestMapping(method = RequestMethod.POST)
public String processRegistration(Registration registration, BindingResult result) throws NoSuchAlgorithmException, UnsupportedEncodingException {
String nextPage = "user/registrationform";
// set custom Validation by user
registrationValidation.validate(registration, result);
if (result.hasErrors()) {
return nextPage;
} else {
// Save the user to the database.
if (usersDao.saveUser(registration)) {
nextPage = "user/registrationsuccess";
} // if
} // if
return nextPage;
}
The class of the member field, usersDao, is annotated with the #Component annotation ...
#Component("usersDao")
public class UsersDaoImpl implements UsersDao {
What additional configuration do I need to add to properly autowire the dao object in my JUnit class? Thanks, -
You're getting the null because you're instantiating RegistrationController yourself, instead of getting the bean from Spring. You almost figured that out for yourself:
// I could get the controller from the context here
controller = new RegistrationController();
You could, and you should. Remove those two lines, and use the following on the field declartion:
#Autowired
private RegistrationController controller;

Resources