I am building a spring based WebApp including a RESTful method call.
I use RESTeasy and jackson to return the username of the current logged in user
(this information is stored in a session bean called "UserBean")
UserBean:
#Component("userBean")
#Scope("session")
public class UserBean implements Serializable {
#Autowired
private InitApp app;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
OverviewBean is the bean that contains the rest method (including the jackson conversion to json):
#Component("overviewBean")
#Scope("view")
#Path("/repairs")
public class OverviewBean {
#Autowired
private InitApp app;
#Autowired
private UserBean userBean;
private List<Repair> openRepairsClient;
private List<Repair> closedRepairsClient;
#PostConstruct
public void fillRepairs() {
try {
String username = userBean.getUsername();
openRepairsClient = app.repairService.findOpenRepairsByClient((Client) app.userService.getUser(userBean.getUsername()));
closedRepairsClient = app.repairService.findClosedRepairsByClient((Client) app.userService.getUser(userBean.getUsername()));
} catch (UserServiceException ex) {
Logger.getLogger(OverviewBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Getters and setters openRepairsClient/closedRepairsClient
#GET
#Path("/getrepairs")
#Produces("application/json")
public String getOpenRepairsInJson() {
String username = userBean.getUsername();
return "test";
}
}
fillRepairs() is able to use userBean without any errors. For example the "String username = userBean.getUsername();" within the try catch returns the username correctly.
My issue is that when getOpenRepairsInJson gets called it throws a nullPointerException
on "String username = userBean.getUsername();". It seems that my userBean is not "linked"
at the moment of the method call. What am I doing wrong?
Thanks in advance!
Related
I have this code, where I send an object to the API:
validateLogin(user:User):Observable<string>{
console.log(JSON.stringify(user));
return this.http.post<string>(`http://localhost:8080/login/login`, user).pipe(
map((resp)=>{
return this.repareString(JSON.stringify(resp));
})
)
}
I don't see anything wrong, but Spring Boot says "required request parameter 'user' for method parameter type String is not present". I've also tried sending it as a JSON object but it says the same. I believe that this is caused by the code in angular, that's why I post it here.
#RestController
#RequestMapping("/login")
public class LoginController {
#PostMapping("/login")
public static String login(#RequestParam String user) throws Exception{
System.out.println(user);
Login l = new ObjectMapper().readValue(user, Login.class);
if(l.checkUser().equals("ok")){
if(l.checkPassword().equals("ok")){
return "logged";
} else {
return l.checkPassword();
}
}
return l.checkUser();
}
}
And the Login class:
public class Login extends Database{
public String email;
public String pass;
public Statement stm;
public Login(String email, String pass) throws Exception{
this.email = email;
this.pass = pass;
this.stm = (Statement) this.con.createStatement();
}
I have tried sending it as a JSON string and I've also tried sending the object properties individually as various params.
Change your controller like this:
#RestController
#RequestMapping("/login")
public class LoginController {
#PostMapping("/login")
public static String login(#RequestBody Login login) throws Exception{
System.out.println(login);
if(login.checkUser().equals("ok")){
if(login.checkPassword().equals("ok")){
return "logged";
} else {
return login.checkPassword();
}
}
return login.checkUser();
}
}
I am trying to apply validations on my SPRING REST-API but i am getting this exception:
Apr 10, 2020 12:05:26 PM org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver doResolveHandlerMethodExceptionWARNING: Failed to invoke #ExceptionHandler method: public com.luv2code.springdemo.exceptionhandling.RestFieldErrorValidation com.luv2code.springdemo.exceptionhandling.GlobalExceptionHandler.processValidationError(org.springframework.web.bind.MethodArgumentNotValidException)org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class com.luv2code.springdemo.exceptionhandling.RestFieldErrorValidation at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:226)
Entity Class:
#Entity#Table(name="customer")
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="first_name")
#NotNull(message = "Firstname is necessary")
#Size(min=1,message="This field is required")
private String firstName;
#Column(name="last_name")
#NotNull(message = "Lastname is necessary")
#Size(min=1,message="This field is required")
private String lastName;
#Column(name="email")
private String email;
// getters and setters
}
FieldValidation Handler classes:
public class RestFieldError {
private String field;
private String message;
public RestFieldError() {
}
// getters and setters
}
and
public class RestFieldErrorValidation {
private List<RestFieldError> fieldErrors = new ArrayList<>();
public RestFieldErrorValidation() {
}
public void addFieldError(String path, String message) {
RestFieldError error = new RestFieldError(path, message);
fieldErrors.add(error);
}
}
RestController Code:
#RestController
#RequestMapping("/api")
public class CustomerRestController {
// autowire the CustomerService
#Autowired
private CustomerService customerService;
#InitBinder
public void initBinder(WebDataBinder dataBinder) {
System.out.println("Entered init binder");
StringTrimmerEditor stringTrimmerEditor = new StringTrimmerEditor(true);
dataBinder.registerCustomEditor(String.class, stringTrimmerEditor);
}
// add the mapping for POST/customers (add a new customer)
#PostMapping("/customers")
#ResponseBody
public Customer addCustomer(#Valid #RequestBody Customer theCustomer) {
System.out.println("theCustomer :"+theCustomer.getFirstName());
theCustomer.setId(0);
customerService.saveCustomer(theCustomer);
return theCustomer;
}
}
Exception handler Class:
#ControllerAdvice
public class GlobalExceptionHandler {
// Adding Validation Support on REST APIs--------------------------------------------------------->
private MessageSource messageSource;
#Autowired
public GlobalExceptionHandler(MessageSource messageSource) {
this.messageSource = messageSource;
}
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public RestFieldErrorValidation processValidationError(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
return processFieldErrors(fieldErrors);
}
private RestFieldErrorValidation processFieldErrors(List<FieldError> fieldErrors) {
RestFieldErrorValidation dto = new RestFieldErrorValidation();
for (FieldError fieldError: fieldErrors) {
String localizedErrorMessage = resolveLocalizedErrorMessage(fieldError);
dto.addFieldError(fieldError.getField(), localizedErrorMessage);
}
return dto;
}
private String resolveLocalizedErrorMessage(FieldError fieldError) {
Locale currentLocale = LocaleContextHolder.getLocale();
String localizedErrorMessage = messageSource.getMessage(fieldError, currentLocale);
//If the message was not found, return the most accurate field error code instead.
//You can remove this check if you prefer to get the default error message.
if (localizedErrorMessage.equals(fieldError.getDefaultMessage())) {
String[] fieldErrorCodes = fieldError.getCodes();
localizedErrorMessage = fieldErrorCodes[0];
}
return localizedErrorMessage;
}
}
Here is the google drive link of the project if you can check the code:
https://drive.google.com/open?id=1QSFVMi3adHGkc7BqXsqAY0P_tO2UfT2I
Here is the Article that i followed:
https://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/
I'm assuming you are using plain Spring here, not Spring Boot.
The question is: To what exactly do you want to convert your RestFieldErrorValidation object? XML? JSON?
For either, you need an appropriate third-party library on your classpath, so Spring can do the conversion automatically.
In the case of JSON, you might want to add this dependency to your project.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
I'm trying to inject a User which should be initialized after a login process, via #Produces. However, after a successful login, the user injected remains null in my Filter called AuthFilter...
All the login process occurs in LoginBean.
Below is my code :
My LoginBean :
#SessionScoped
#Model
public class LoginBean implements Serializable {
#Inject Credentials credentials;
private #EJB UserService das;
private User currentUser;
public static final String LOGIN_LINK = "/login.xhtml";
public String login() {
User nonAuthUser = das.findUser(credentials); // "findUser" returns null if no user found in database;
// otherwise, returns the User
if(nonAuthUser!=null){
currentUser = nonAuthUser;
return urlRedirection;
} else {
// ...
// INFORMING THE FORM SUBMITTER THAT THE LOGIN/PASSWORD
// ARE INCORRECT
// ...
return null;
}
}
public String logout() {
currentUser = null;
return LOGIN_LINK;
}
public UserService getDas() {
return das;
}
#Produces #LoggedIn User getcurrentUser() {
return currentUser;
}
}
Credentials class :
#Model
public class Credentials{
private String login;
private String password;
// ...
// HERE IS PART OF CODE FOR THE GETTERS + SETTERS
// ...
}
User class :
#Entity
public class User implements Serializable {
#Id
#Column
private int id;
#Column
private String login;
#Column
private String firstName;
#Column
private String lastName;
// ...
// HERE IS PART OF CODE FOR THE GETTERS + SETTERS
// ...
}
LoggedIn interface :
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface LoggedIn {}
My Filter :
#WebFilter(filterName = "AuthFilter", urlPatterns = {"*.xhtml"})
public class AuthFilter implements Filter {
#Inject #LoggedIn User currentUser;
public AuthFilter() {}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean isLoggedIn = currentUser != null;
// ...
// HERE IS A PART OF CODE WHICH WILL REDIRECT THE USER:
// - TO THE LOGIN PAGE IF HE'S NOT LOGGED IN
// - TO THE REQUESTED IN THE CONTRARY CASE
// ...
}
#Override
public void destroy() {
}
}
The problem is that the variable isLoggedIn initialized from the method Authfilter.doFilter above always returns false.
After doing some debugging, I've realized that's because the producer (in the LoginBean) is called before the user even submits the login form, initializing the currentUser to null on the 1st place.
What I'd like is to "produce" the currentUser after login in, and not before.
Thanks for all the suggestions to solve this problem.
(Note: I want to work in full CDI)
I'm trying to implement user authorization on java ee 7. For validation entered data I use Bean validation annotations.
#NotNull(message = "Please enter email address")
#Column(name = "email")
private String email;
#NotNull(message = "Please enter password")
#Size(min = 6, max = 255)
#Column(name = "password")
private String password;
Also I have #PrePersist method which hash entered password
#PrePersist
public void updatePassword(String password) {
//some code
}
Here is a method where I register user:
#EJB
private UserService userService;
public void register() {
if (userService.getByEmail(email) == null) {
try {
userService.register(email, password);
//log in if users is created
authController.setEmail(email);
authController.setPassword(password);
authController.login();
} catch (Exception e) {
setErrorMessage("Validation error");
}
} else {
setErrorMessage("Please choose another email address");
}
}
UserService
#Stateless
public class UserService {
#EJB
private UserDAO userDAO;
public void register(String email, String password){
User user = new User();
user.setEmail(email);
user.setPassword(password);
userDAO.create(user);
}
}
The problem is if password is null. At first called updatePassword method but not #NotNull annotation over the password field and thus i get NullPointerException. How to make that at first checks validation and then later other methods. Thanks in advance!
It seems that bean validation is not triggered soon enough.
One way to solve this would be to inject ValidatorFactory into UserService and then validate user object after it is created. Something like this:
#Stateless
public class UserService {
#EJB
private UserDAO userDAO;
#Inject
private ValidatorFactory validatorFactory;
public void register(String email, String password){
User user = new User();
user.setEmail(email);
user.setPassword(password);
Set<ConstraintViolation<User>> constraintViolations = validatorFactory.getValidator().validate(user);
if(constraintViolations.size() > 0){
// handle error
}else{
userDAO.create(user);
}
}
}
this answer could be helpful for clarification
I'm learning Java 6 EE and I have a simple web app.
I have UserBean class that uses CurrencyManager class. CurrencyManager is application scoped and is a managed bean. UserBean is managed bean and session scoped.
Here is my UserBean:
#ManagedBean
#SessionScoped
public class UserBean implements Serializable{
private String username;
private ArrayList<Money> ownedMoney;
private CurrencyManager currencyManager;
private BigDecimal credits;
public UserBean() {
currencyManager = new CurrencyManager();
username = "User";
ownedMoney = new ArrayList<>();
ownedMoney.add(new Money(new BigDecimal(15000), currencyManager.getCurrency("CZK")));
ownedMoney.add(new Money(new BigDecimal(100), currencyManager.getCurrency("USD")));
credits = new BigDecimal(150);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public BigDecimal getCredits() {
return credits;
}
public void setCredits(BigDecimal credits) {
this.credits = credits;
}
public ArrayList<Money> getOwnedMoney() {
return ownedMoney;
}
public void setOwnedMoney(ArrayList<Money> ownedMoney) {
this.ownedMoney = ownedMoney;
}
public CurrencyManager getCurrencyManager() {
return currencyManager;
}
public void setCurrencyManager(CurrencyManager currencyManager) {
this.currencyManager = currencyManager;
}
}
And here my CurrencyManager:
#ManagedBean(name = "currencyManager")
#ApplicationScoped
public class CurrencyManager {
private HashMap<String, Currency> currencies;
public CurrencyManager() {
this.currencies = new HashMap<>();
currencies.put("CZK", new Currency("CZK", new BigDecimal("0.0503")));
currencies.put("GBP", new Currency("GBP", new BigDecimal("0.59")));
currencies.put("EUR", new Currency("EUR", new BigDecimal("1.38")));
currencies.put("USD", new Currency("USD", new BigDecimal("1.0")));
}
public Currency getCurrency(String name){
return currencies.get(name);
}
public java.util.Collection<Currency> getCurrencies() {
return currencies.values();
}
public void setCurrencies(HashMap<String, Currency> currencies) {
this.currencies = currencies;
}
}
The code I posted works fine as is. However I don't want to instantiate CurrencyManager in my UserBean class - that's is why I made it ApplicationScoped, since it should be available at all times.
If I remove the instantiation (first line in UserBean constructor) and change declaration to:
#ManagedProperty(value = "#{currencyManager}")
private CurrencyManager currencyManager;
then the first page that queries ownedMoney property in UserBean throws javax.servlet.ServletException: Cant instantiate class: model.UserBean. with root cause of NullPointerException. GlassFish log showed that the NullPtr occurs in UserBean constructor, when I call getCurrency on currencyManager, here:
ownedMoney.add(new Money(new BigDecimal(15000), currencyManager.getCurrency("CZK")));
Can you tell me what I'm doing wrong?
I just came across the same problem, and found out by chance, that it is not working, if I try with firefox (actually icedove under linux), but well working, if I try with the eclipse build-in browser.
Even so this does not make sense to me, have you tried with different browsers already?