Java Play 2.5.10 how to inject play-jongo - java

I've the following model:
public class Users {
public static PlayJongo jongo = Play.current().injector().instanceOf(PlayJongo.class);
public static MongoCollection users() {
return jongo.getCollection("DB.users");
}
..
..
public static Users authenticate(String email, String password) {
Users user = users().findOne("{email: #, removed: false}", email).as(Users.class);
if (user != null) {
if (HomeController.checkPassword(password, user.password)) {
return user;
}
}
return null;
}
..
I use that in my controllers as:
public Result authenticate() {
DynamicForm requestData = Form.form().bindFromRequest();
String email = requestData.get("email").trim();
String password = requestData.get("password").trim();
Users user = Users.authenticate(email, password);
if (user == null) {
flash("danger", "Incorrect email or password.");
return redirect(routes.HomeController.login());
}
session("email", user.getEmail());
session("role", user.getRole());
session("fullname", user.getLastname() + " " + user.getFirstname());
session("id", user.getId().toString());
return redirect(routes.HomeController.index());
}
I tried a lot of combination to use injection with play-jongo without result. E.g.
#Inject
public PlayJongo jongo;
public MongoCollection users() {
return jongo.getCollection("DocBox.users");
}
I enter in a loop of static/non-static referenced context errors. If I remove all static declaration, I'm unable to call Users.method. If I try to inject Users to a controller
public class HomeController extends Controller {
#Inject
public Users users;
.
.
and try to call a Users method:
Users user = users.authenticate(email, password);
I receive a org.jongo.marshall.MarshallingException.
My brain is definitively goes overheating, someone can explain me how to use Injection with play-jongo?

I solve the problem. Now I've a UsersRepository that contains the methods that operate on the mongo collection (authenticate, addUser, et al.). And a Users object that only contains the actual data fields (firstname, lastname, email, etc.).
After that I can inject UsersRepository into my controller and use that one instance everywhere.
Thanks to Greg Methvin, Tech Lead - Play Framework

Related

AutoWired JPA Repository is null in some method of controller

I have a JPARepository like this
#Repository
public interface RestaurantRepo extends JpaRepository<Restaurant, String> {
Optional<Restaurant> findByName(String name);
Optional<List<Restaurant>> findAllByMerchantId(String merchantId);
}
I then have a controller where I am initializing the Repository like this
#Autowired
RestaurantRepo restaurantRepo;
Then I have one method where I am using the Repository like this
#PreAuthorize("hasRole('ROLE_SUPER_ADMIN')")
#GetMapping("/disable")
public ResponseEntity<CustomResponse> disableUser(String username, boolean disable) {
Restaurant restaurant = restaurantRepo.findById(username).get();
restaurant.setDisabled(disable);
CustomResponse er = new CustomResponse();
er.setStatus("Successful");
if (disable) {
er.setMessage("Restaurant is disabled");
} else {
er.setMessage("Restaurant is enabled");
}
restaurantRepo.save(restaurant);
return new ResponseEntity<>(er, new HttpHeaders(), HttpStatus.OK);
}
Whenever I hit this api, it works fine.
Then I have another method like this
#PreAuthorize("hasAnyRole('ROLE_SUPER_ADMIN','ROLE_RESTAURANT')")
#GetMapping("/get")
private ResponseEntity<Restaurant> getRestaurant(Principal principal) {
String username = principal.getName();
System.out.println("username "+username); //prints the valid username
System.out.println("RestRepo "+restaurantRepo); //prints null
Restaurant restaurant;
Optional<Restaurant> opt = restaurantRepo.findById(username); //prints Exception here
if (opt.isPresent()) {
restaurant = opt.get();
return new ResponseEntity<>(restaurant, HttpStatus.OK);
} else {
restaurant = new Restaurant();
return new ResponseEntity<>(restaurant, HttpStatus.NOT_FOUND);
}
}
Here I get a NullPointerException in this line Optional<Restaurant> opt = restaurantRepo.findById(username);
The username is a valid username, and so when I print the restaurantRepo I get null.
I am confused as to why the variable is not null in one method while it is null in another method. Any help would be appreciated. Thanks
Im not sure. But try to change the access modifier in the second method to public.
Please refer this thread
Also use constructor injection instead of #Autowired annotation.

Create default user at runtime in spring mvc using postContruct java

Need to create default user profile when my Web Application [Spring MVC] starts:
--using postConstruct
-- Create default user on start up
-- do not create same user in next run
-- Default user like admin with some other information like First Name, Last Name,DOB etc. and it should be stored in database.
Of-course I have to follow proper mvc pattern like controller, model, service, repository, spring-configuration,spring-security configuration.
Please do not post code in spring-boot or JSON.
Any help will be highly appreciated and thanks in advance.
The question have simple solution after lot of research I have concluded that using #PostConstruct anything can be create at initializing phase of the application.
Hare is What I have found:
#Component
public class DbInit {
#Autowired
private UserRepository userRepository;
#PostConstruct
private void postConstruct() {
User admin = new User("admin", "admin password");
User normalUser = new User("user", "user password");
userRepository.save(admin, normalUser);
}
}
A reference from : https://www.baeldung.com/spring-postconstruct-predestroy
Thanks to this site a grate place to learn.
Create a class call SecurityUtil like below.
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import java.util.HashSet;
import java.util.Set;
public class SecurityUtil {
public static User getFirstTimeUser() {
User defaultUser = new User();
defaultUser.setActive(true);
defaultUser.setUserId("admin");
defaultUser.setFirstName("First Time");
defaultUser.setLastName("Admin");
defaultUser.setId(0L);
defaultUser.setPassword(new Md5PasswordEncoder().encodePassword("admin", Constants.SALT));
//Set<Role> roles = new HashSet<Role>();
Role role = new Role();
role.setId(0L);
role.setRoleName("ROLE_ADMIN");
//roles.add(role);
defaultUser.setRole(role);
return defaultUser;
}
Then call this method from Userservice class which is implemented from Spring's UserDetails.
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserFilter filter = new UserFilter();
filter.setUserId(username);
List<User> users = userDAO.find(filter);
if (users != null && users.size() == 1) {
return users.get(0);
} else {
if (userDAO.count() == 0) {
return getFirstTimeUser();
} else {
throw new UsernameNotFoundException("Username Not Found Exception");
}
}
}

Is there any way creating dynamic #ServerEndpoint address in Java?

For example, I have a room
public class Room {
private int id;
private Set<User> users;
}
So I want it to be endpoint for my websocket application. But there may be a lot of rooms and I want each of them could have own URI (for example, rooms/1, rooms/2 etc.)
Evidently, #ServerEnpoint annotaion allows only constants. So, is there any way to make it?
Something like this:
#ServerEndpoint(value = "/rooms/{roomnumber}")
public class....
static Map<String, Session> openSessions = ...
#OnOpen
public void onConnectionOpen(final Session session, #PathParam("roomnumber") final String roomnumber,
...
//store roomnumber in session
session.getUserProperties().put("roomnumber", roomnumber);
openSessions.put( String.valueOf(session.getId()), session )
To only send messages to specific roomnumbers/clients:
// check if session corresponds to the roomnumber
for (Map.Entry<String, Session> entry : openSessions.entrySet()) {
Session s = entry.getValue();
if (s.isOpen() && s.getUserProperties().get("roomnumber").equals(roomnumber_you_want_to_address)) {
...
And when a client disconnects:
#OnClose
public void onConnectionClose(Session session) {
openSessions.remove(session.getId());
}
You can use this per function to map requests with different variables in the same controller
#RequestMapping(value = "/endpoint/{endpointVariable}", method = RequestMethod.GET)
public ReturnDTO getReturnDTO(<params>){
// Here the variable, endpointVariable, will be accessible
// In my experiences its always been an integer, but I'm sure a string
// would be possible. check with debugger
}
http://www.journaldev.com/3358/spring-mvc-requestmapping-annotation-example-with-controller-methods-headers-params-requestparam-pathvariable

List with Bean in spring

I having an user details class inside that i placed address class to store the multiple addressess for each user details class. I am using Spring 4.0 for that. Below given the code:
UserDetails class:
#Component("userDetails")
public class UserDetails {
#Resource(name="address")
#Autowired
private List<Address> address;
public List<Address> getAddress() {
return address;
}
#Autowired
public void setAddress(List<Address> address) {
this.address = address;
}
}
Address Class:
#Component("address")
public class Address {
private String area;
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
}
In this example, Address.area value need to pass in the run time and then i need to create an object for Address class. Then it need to add in the List address variable present inside UserDetails class. Likewise i need to add n number object in the arrayList then i need to create an object for UserDetails class.
I tried the below code:
public class AppMain {
public static void main(String args[]){
AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Address address = (Address)context.getBean("address");
//setting first value:
address.setArea("XXX");
Address address1 = (Address)context.getBean("address");
//setting second value
address1.setArea("YYY");
UserDetails userDetails = (UserDetails)context.getBean("userDetails");
System.out.println("User Size: "+application.getAddress().size());
System.out.println("User Details : "+application.getAddress().get(0).getArea());
System.out.println("User Details : "+application.getAddress().get(1).getArea()); // getting ArrayIndexOutOfBoundException in this line
}
}
partial Output:
User Size: 1
User Details : YYY
Expected Output:
User Size: 2
User Details : XXX
User Details : YYY
Could you please help with this.
It's not entirely clear to me why you would want to create what appear to be domain objects using Spring but it looks like that's what you're doing from your code.
Spring has the concept of Scope that controls what happens when you retrieve a bean from an ApplicationContext. The default Scope is singleton which means you only get a one instance of the bean within the ApplicationContext. This means that your calls context.getBean("address") always return the same object.
As for the wiring that you've performed using the #Component annotation; this occurs when the classpath is scanned (normally when the application starts). At this time Spring instantiates a single instance of each class marked with #Component, that's one Address and one UserDetails. Spring is smart enough to add the single Address to a List before setting the address field but that's all it does.
Your code then retrieves this objects from the ApplicationContext setting the area on the same object twice, hence why the debug statements print as they do.
This explains what's going on with your code, but leaves the question of how to fix it unanswered.
As I said, I can't understand why you would used Spring to build what appears to be a domain model. Domain models, in terms of the instances of each class, are not typically known ahead of time and therefore Spring is not the appropriate tool to use to create such a model (Spring is typically used to wire together the application itself).
You should modify the domain classes' constructors like this:
public Address
{
private String area;
public Address(String area)
{
this.area = area;
}
...
}
public UserDetails
{
private List<Address> addresses;
public UserDetails(Address... addresses)
{
this.addresses = Arrays.asList(addresses);
}
...
}
And then the main method can be re-written:
public static void main(String[] args)
{
UserDetails userDetails = new UserDetails(
new Address("XXX"),
new Address("YYY"),
);
System.out.println("User Size: " + application.getAddress().size());
System.out.println("User Details: " + application.getAddress().get(0).getArea());
System.out.println("User Details: " + application.getAddress().get(1).getArea());
}
Notice that you are getting the same bean twice, so it's impossible that you get two injections in the UserDetails List:
Address address = (Address)context.getBean("address");
...
Address address1 = (Address)context.getBean("address");
Something like this should work:
#Configuration
public class AppConfig{
#Bean
public UserDetails userDetails(){
return new UserDetails();
}
#Bean
public Address addressXXX(){
return new Address();
}
#Bean
public Address addressYYY(){
return new Address();
}
}
Then your code:
Address address = (Address)context.getBean("addressXXX");
//setting first value:
address.setArea("XXX");
Address address1 = (Address)context.getBean("addressYYY");
//setting second value
address1.setArea("YYY");
UserDetails userDetails = (UserDetails)context.getBean("userDetails");
System.out.println("User Size: "+application.getAddress().size());
System.out.println("User Details : "+application.getAddress().get(0).getArea()); //--->XXX
System.out.println("User Details : "+application.getAddress().get(1).getArea()); //--->YYY

Testing the behavior of void method

Suppose I have the following service object
public class UserService {
#Autowired
private UserDao dao;
public void addUser(String username, String password) {
if (username.length() < 8 ) {
username = username + "random" ; // add some random string
}
User user = new User(username, password);
dao.save(user);
}
}
I want to test the behaviour of the method "addUser" when username length is less 8 and when the username is more than 8 char. How do approach in unit test UserService.addUser(...), and verify it? I am aware using assert(), but the value "password" is not available outside the addUser(...) method.
I use JUnit and Mockito.
I came up a solution, after some re-visit the problem again after some months.
The idea is to observed the object user that is being passed to UserDao. We can inspect the value of the username by doing this, hence the unit test code:
#RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
#Mock
private UserDao dao;
#InjectMock
private UserService service;
#Test
public void testAddingUserWithLessThan8CharUsername () {
final String username = "some";
final String password = "user";
doAnswer(new Answer<Object>() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
Object[] args = invocationOnMock.getArguments();
User toBeSaved = (User) args[0];
Assert.assertEquals(username + "random", toBeSaved.getPassword());
return null;
}
}).when(userDao).save(Matchers.any(User.class));
service.addUser(username, password);
}
}
Guillaume actually had the closest answer, but he answered using jMock. However, he gave me the idea on how to accomplish this, so I think he deserves some credit too.
You are testing side-effects, but fortunately, everything you need is passed to the dao.save(). First, create a UserDao (either with or without Mockito), then you can use ReflectionTestUtils to set the dao in the UserService, then you can test the values which are passed to dao.save().
Something like:
private class TestUserDao extends UserDao {
private User savedUser;
public void save(User user) {
this.savedUser = user;
}
}
#Test public void testMethod() {
UserService userService = new UserService();
TestUserDao userDao = new TestUserDao();
ReflectionTestUtils.setField(userService, "dao", userDao);
userService.addUser("foo", "bar");
assertEquals("foo", userDao.savedUser.username.substring(0, 3));
assertEquals("bar", userDao.savedUser.password);
}
Or you can user Mockito to mock out the Dao if you want.
Use a mocking framework. The example below uses JMock2, but it would be similar with EasyMock, Mockito, etc.
Also, you need to extract the username generation to something like UsernameGenmerator to be able to mock it. You need another specific test for the username generator.
private final Mockery mockery = new Mockery();
private final UserDao mockDao = mockery.mock(UserDao.class);
private final UsernameGenerator mockUserNameGenerator = mockery.mock(UsernameGenerator.class);
#Test
public void addUserUsesDaoToSaveUser() {
final String username = "something";
final String generatedUsername = "siomething else";
final String password = "a password";
mockery.checking(new Expectations() {{
oneOf(mockUsernameGenerator).generateUsername(username);
will(returnValue(generatedUsername));
oneOf(mockDao).save(new User(generatedUsername, password)); // assumes your User class has a "natueral" equals/hashcode
}});
UserService userService = new UserService();
userService.addUser(username, password);
}
And for UsernameGenerator you need test on length of the returned username:
#Test
public void leavesUsernameUnchangedIfMoreThanEightChars() {
final String username = "123456789";
final UsernameGenerator usernameGenerator = new UsernameGenerator();
assertEquals(username, userGenerator.generateUsername(username));
}
#Test
public void addsCharactersToUsernameIfLessThanEightChars() {
final String username = "1234567";
final UsernameGenerator usernameGenerator = new UsernameGenerator();
assertEquals(8, userGenerator.generateUsername(username).length());
}
Of course, depending on your "random" method, you may want to test its specific behaviour too. Apart from that, the above provide sifficient coverage for your code.
It would all depend on how your DAO's save method is implemented.
If you are actually storing to a hard-coded repository, then you will probably need to query the repository itself for the values you are intereseted in.
If you have an underlying interface which is called, then you should be able to set up a callback method and retrieve the actual value which is being saved.
I have never used Mockito so I couldn't give you exact code which does this article should address that:
Using Mockito, how do I intercept a callback object on a void method?
Consider extracting user name generation logic as dependency from UserService.
interface UserNameGenerator {
Strign generate();
}
Wire UserNameGenerator same as UserDao. And change the code to:
public class UserService {
#Autowired
private UserDao dao;
#Autowired
private UserNameGenerator nameGenerator;
public void addUser(String username, String password) {
if (username.length() < 8 ) {
username = nameGenerator.generate();
}
User user = new User(username, password);
dao.save(user);
}
}
Next create the default implementation of UserNameGenerator and move name generating logic there.
Now you can easily check behavior by mocking UserNameGenerator and UserDao.
To check use case when username is length is less than 8
String username = "123";
String password = "pass";
String generatedName = "random";
// stub generator
when(nameGenerator.generate()).thenReture(generatedName);
// call the method
userService.addUser(username, password);
// verify that generator was called
verify(nameGenerator).generate();
verify(userDao).save(new User(generatedName, password));
To check use case when username is length is greater than 8
String username = "123456789";
String password = "pass";
String generatedName = "random";
// call the method
userService.addUser(username, password);
// verify that generator was never called
verify(nameGenerator, never()).generate();
verify(userDao).save(new User(username, password));
Easiest way is to extract the part where you have the user name correction logic
if (username.length() < 8 ) {
username = username + "random" ; // add some random string
}
into a method and test the return value of that method.
public string GetValidUsername(string userName){
if (username.length() < 8 ) {
return username + "random" ; // add some random string
}
return username;
}
with this you can pass different types of username and test the behavior of your code.

Categories