I've developed a Spring Web-MVC application. I have some offices in my project. Each user belongs to an office. user.getOfficeType() returns an integer representing the user's office type. If the office type is 1, the user belongs to Office1 and etc.
However I want to inject the authenticated user's office into my service classes:
class MyService{
#Autowired
Office currentOffice;
...
}
I read the Spring docs. I need a session scoped bean to inject it into my service classes.
applicationContext.xml:
<mvc:annotation-driven />
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<context:annotation-config />
<context:component-scan base-package="com.package.controller" />
<context:component-scan base-package="com.package.service" />
...
<bean id="office" class="com.package.beans.Office" scope="session">
<aop:scoped-proxy/>
</bean>
I have three implementations of the Office interface. Once a user requests a resource, I want to be aware of his Office. So I need to inject his session-scoped Office into my service classes. But I don't know how to instantiate it according to the user's office. please help!
I found a solution! I declared an OfficeContext that wraps the Office and also implements it.
#Component
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OfficeContext implements InitializingBean, Office {
private Office office;
#Autowired
private UserDao userDao;
#Autowired
private NoneOffice noneOffice;
#Autowired
private AllOffice allOffice;
#Autowired
private TariffOffice tariffOffice;
#Autowired
private ArzeshOffice arzeshOffice;
public Office getOffice() {
return this.office;
}
#Override
public void afterPropertiesSet() throws Exception {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth.isAuthenticated()) {
String name = auth.getName(); //get logged in username
JUser user = userDao.findByUsername(name);
if (user != null) {
this.office = noneOffice;
} else {
OfficeType type = user.getOfficeType();
switch (type) {
case ALL:
this.office = allOffice;
break;
case TARIFF:
this.office = tariffOffice;
break;
case ARZESH:
this.office = arzeshOffice;
break;
default:
this.office = noneOffice;
}
}
} else {
this.office = noneOffice;
}
}
#Override
public OfficeType getType() {
return office.getType();
}
#Override
public String getDisplayName() {
return office.getDisplayName();
}
}
and in my service classes I injected the OfficeContext.
#Service
public class UserService {
#Autowired
UserDao userDao;
#Autowired
OfficeContext office;
public void persist(JUser user) {
userDao.persist(user);
}
public void save(JUser user) {
userDao.save(user);
}
}
I'm just throwing a different approach
#Configuration
public class SessionScopeBeansConfig {
#Bean
#SessionScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public User user( UserDAO userDAO ) {
return userDAO.getUserByLoginName( SecurityContextHolder.getContext().getAuthentication().getName() );
}
#Bean
#SessionScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public Office office( User user ) {
Office office = <<Code to initialize office>>;
return office;
}
}
This way it's possible to directly inject the Office
class MyService{
#Autowired
Office currentOffice;
...
}
Related
I have a #SessionScope bean that keeps track of the current users role. When I run the application the value is present, however when I run my integration tests the bean is null.
Here's what I have:
#Component
#SessionScope
public UserSessionDataImpl implements UserSessionData {
private String role; // "Admin" or "User"
// getters/setters below
}
// Service
#Service("roleService")
public RoleServiceImpl implements RoleService {
#Autowired
UserSessionData sessionData;
public String getRole(){
return this.sessionData.getRole();
}
public String setRole(String role){
return this.sessionData.setRole(role);
}
}
// API
#Api
public class TicketApi {
#Autowired
private RoleService roleService;
#Autowired
private TicketService TicketService;
#RequestMapping(value = "person/{id}/tickets", method = RequestMethod.GET)
public String getTickets(long personId) {
// only admins can lookup tickets
if(roleService.getRoles.equals("Admin"){
// do logic
}
}
}
// Unit test method
#Before
public void setup(){
roleService.setRole("Admin"); //set role to admin for testing
}
#Test
// Calls TicketApi
public void getTicketsTest(){
mockMvc.perform(
get("/person/{id}/tickets")); // blows up due to null role
}
I am stumped as to why my roleSerivce loses the reference to sessionData. I do see that UserSessionDataImpl does get instantiated multiple times, which I wouldn't think would happen. I'm wondering if the mockMvc call creates a new Session which would cause the extra instantiations. Has anyone else figured this issue out?
I have a model in which I want to inject my service.
My Model
#Configurable
#Entity
#Table(name = "user")
public Class User {
#Autowired
private UserService userService;
{
System.out.println("Trying Service : " + userService.getMyName());
}
}
Here I get always a NullPointerException on 7'th line.
In my spring-context.xml I have :
<context:spring-configured/>
<bean
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean
class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
EDIT
UserService
#Component
public Class UserService {
public String getMyName() { return "it's Me!";}
}
Spring managed components can be wired only into another beans managed by Spring.
However, there is a trick to add service to your POJO if you really need it:
Add UserService as a static field to your POJO with a setter
In UserService after spring initializes the bean, set itself as a field on the POJO (this can be done in #PostConstruct method)
Make a static instance of UserService available:
#Service
public Class UserService {
private static UserService instance;
public static UserService getInstance() { return instance; }
#PostConstruct
void init() { instance = this; }
public String getMyName() { return "it's Me!";}
}
call with:
UserService.getInstance().getMyName()
I have below Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SpringTestConfig.class)
public class UserServiceTest {
#Inject
private UserRepository userRepository;
#Inject
private UserService userService;
#Test
public void testProcessInvoice() throws SQLException {
User user = new User();
user.setFirstName("abc");
when(userRepository.save(any(User.class))).thenReturn(user);
Assert.assertNotNull(userService);
User savedUser = userService.save(user);
Assert.assertEquals("abc", savedUser.getFirstName());
}
}
I have below SpringTestConfig.java
#Configuration
public class SpringTestConfig {
#Bean
public UserService userService() {
return Mockito.mock(UserService.class);
}
#Bean
public UserRepository userRepository() {
return Mockito.mock(UserRepository.class);
}
}
call to User savedUser = userService.save(user); returns null user object. I am not able to figure it out why it is returning null.
EDIT:
UserRepository is JpaRepository, if this is a problem
public interface UserRepository extends JpaRepository<User, Long> {
}
Your UserService is a mock object, and has no defined behavior for dealing with the #save(User) method.
Mocking the object under test is probably not what you are after here. I would recommend your objects under test are instantiated in the test, and injected with the mocks or stubs of the objects that they utilize.
Your configuration needs to return a real UserService:
#Configuration
public class SpringTestConfig {
#Bean
public UserService userService() {
return new UserServiceImpl(); // or whatever your implementation is
}
#Bean
public UserRepository userRepository() {
return Mockito.mock(UserRepository.class);
}
}
Mocks are for collaborators, not for the thing you're testing.
I have problems with autowiring in Spring.
I have dao class for AccessLevel object like this:
Interface:
public interface AccessLevelDAO {
public AccessLevel select(Integer id);
}
It's implementation:
#Repository
public class AccessLevelDAOImpl implements AccessLevelDAO {
private SessionFactory sessionFactory;
#Autowired
public void AccessLevelDAO(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
#Override
#Transactional(propagation = Propagation.SUPPORTS,
isolation = Isolation.READ_UNCOMMITTED)
public AccessLevel select(Integer id) {
return (AccessLevel) currentSession().createCriteria(AccessLevel.class).add(Restrictions.idEq(id)).uniqueResult();
}
}
And service class which using this DAO class:
Interface:
public interface UserServices {
String getUserAccessLevel(String username);
AuthorizationResponseDTO authorize(String username, String password);
}
And implementation:
#Service
public class UserServicesImpl implements UserServices {
#Autowired private AccessLevelDAO accessLevelDAO;
#Autowired private UserDAO userDAO;
#Override
public String getUserAccessLevel(String username) {
User user = userDAO.select(username);
return accessLevelDAO.select(user.getAccessLevel()).getAccessLevel();
}
#Override
public AuthorizationResponseDTO authorize(String username, String password) {
return null;
}
}
When I'm trying to #Autowire accessLevelDAO and userDAO i get error message "Could not autowire. No beans of "AccessLevelDAO" type found".
Spring config includes component scan definition:
<context:annotation-config />
<context:component-scan base-package="com.core"/>
I'm having this problem with passing on data between JSF beans.. What I want to do is when I login, pass the username to a next bean where I can use it. I have found many things about this but I can't get it to work in my project. What I've got is a UserService where I can manage my users. There's a method in here called getUsers(username). Now I'm trying to pass the username so I can retrieve my user-object.
xHtml:
<h:link outcome="changeProfile" value="Change profile">
<f:param name="username" value="#{userBean.username}" />
</h:link>
changeProfileBean:
#Component("changeProfile")
#ManagedBean
#RequestScoped
public class ChangeProfileBean implements Serializable {
private UserService userService;
private User user;
#ManagedProperty("#{param.username}")
private String username;
#PostConstruct
public void init(){
FacesContext facesContext = FacesContext.getCurrentInstance();
this.username = facesContext.getExternalContext().getRequestParameterMap().get("username");
try {
if(username != null){
user = userService.getUser(username);
}
} catch (UserServiceException e) {
e.printStackTrace();
}
}
#Autowired
public ChangeProfileBean(UserService userService) {
this.userService = userService;
}
What happens is that the changeUserbean will be created when the app is starting. And immediately after that runs the #PostConstruct where username obviously equals null. But when I call the changeUserBean it doesn't execute the #PostConstruct anymore..
Does anybody know what I could do?
UserBean:
#Component("userBean")
#Scope("session")
public class UserBean implements Serializable
{
#Autowired
private UserService userService;
#Autowired
private RepairService repairService;
private String username;
private String password;
While you have already the data you need in a broader scope, just inject that backing-bean into changeProfileBean:
#ManagedBean
#RequestScoped
public class ChangeProfileBean implements Serializable {
#ManagedProperty("#{userBean}")
private UserBean userBean;
public UserBean getUserBean(){
return userBean;
}
public void setUserBean(UserBean userBean){
this.userBean = userBean;
}
...
}