Cannot call any method outside my controller in Spring - java

Situation:
Using Spring MVC I prompt a user in my view to enter some information into the form.
I bind that information to a form object (like normal).
I successfully get data back to my controller (confirmed) via log dump.
The Problem:
Now I'm in the controller with all the data the user entered into the form (bound to a form object).
I take that same object with data in it and I try to pass it to my service class method to use the data in a way I need it to.
The problem is that as soon (as soon) as my controller calls the service method it throws an exception. It doesn't even reach a 'log.info' (which is the first line of code in that method).
This should absolutely be working and I'm very taken back as to why it isn't. It seems like a very simple matter. i.e.(get the data back to my controller; use that data in a call to a service method).
CONTROLLER
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerAccount(#ModelAttribute User user, Locale locale,
Model model) {
String theView = "";
try{
logger.info("User submitted Registration Form");
user.setPaidStatus("ACTIVE");
user.setUserRole("SUBSCRIBER");
logger.info(user.toString()); //Proving all the data is available.
userService.createNewUser(user); //This is the call to my service
//method. As soon as it reaches it it exceptions out right away.
//userDao.createNewUser(userDto); //just to see if it does the same
//thing elsewhere - (it does)
model.addAttribute("command", new User());
theView = "login";
} catch(SaveMyFavsException se){
logger.info(se.getCmdCode() + ", Message: " + se.getCmdMsg());
model.addAttribute("command", new User());
model.addAttribute("error", se.getCmdCode() + ", Message: " +
se.getCmdMsg());
return "register";
} catch(Exception e){
logger.info(e.getLocalizedMessage());
model.addAttribute("command", new User());
model.addAttribute("error", e.getLocalizedMessage());
return "register";
}
return theView;
}
SERVICE CLASS (See createNewUser())
#Component
public class UserService implements UserServiceInterface{
#Autowired
UserDaoInterface userDao;
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
public void createNewUser(User user){
int result = 0;
try{
//FAILS BEFORE MAKING IT HERE (automatically ends up in the second Catch block for Exception with no message)
logger.info("Entered createNewUser() service");
logger.info("User ID: " + user.getUserId());
result = userDao.createNewUser(user);
logger.info("New User DAO Complete - Rows Inserted: " + result);
} catch(SaveMyFavsException se){
throw new SaveMyFavsException(se.getCmdCode(), se.getCmdMsg());
} catch(Exception e){
logger.info("General Exception occurred during service to create new user... Trace: " + e.getLocalizedMessage());
throw new SaveMyFavsException(2000015, "General Exception occurred during service to create new user... Trace: " + e.getLocalizedMessage());
}
}

You're not seeing the full error message because you're eating the full stack trace. Change your logger to:
logger.info("General Exception occurred during service to create new user.", e);

Please share the code which inject the userService to the controller. This seems to be an issue with the bean injection.

Related

How to handle Spring Data JPA deletes when deleting by PK that does not exist?

What is the best way to handle errors when using Spring's Jpa Repository deleteById(Long id) method?
By default the deleteById(), checks to see if the ID has an existing row in the database, if it doesn't it throws a org.springframework.dao.EmptyResultDataAccessException because it expects a row size of 1.
I first tried to use my Exception Handler to pick up on this exception, which worked fine but the message exposes my package and class name to the user when Spring returns the error message.
#ExceptionHandler(EmptyResultDataAccessException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
protected ResponseEntity<RestApiError> handleEmptyResultDataAccessException(EmptyResultDataAccessException ex, HttpServletRequest request) {
RestApiError error = new RestApiError(HttpStatus.BAD_REQUEST, Map.of("message", ex.getMessage()), request.getRequestURI());
return new ResponseEntity<>(error, error.getHttpStatus());
}
ex.getMessage() returns:
No class net.demo.customerservice.model.CustomerLocation
entity with id 7 exists!
Instead I decided to catch EmptyResultDataAccessException, and then throw more useful exception and message where I call deleteById();
My current code:
public void delete(Long id) {
try {
repository.deleteById(id); // call Spring's Data JPA repository method deleteById
} catch (EmptyResultDataAccessException ex) {
throw new EntityNotFoundException("Location with ID: [" + id + "] was not found");
}
}
This works great, and returns a good error message to the user but it seems like a hack.
Is there any better way to handle the EmptyResultDataAccessException? I could also use the existsById() method before calling the delete method, but then I am using two queries.
Generally it's better to avoid catching exceptions throughout the code. If you can delegate exception handling to another class, you can handle errors consistently across your application in one place. You could use #ControllerAdvice for this:
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ExceptionHandler(EmptyResultDataAccessException.class)
public ResponseEntity<> handleRecordNotFound(EmptyResultDataAccessException ex) {
LOG.trace("Record not found: {}", ex.getMessage());
RestApiError error = new RestApiError(HttpStatus.BAD_REQUEST, Map.of("message", "Record not found"), request.getRequestURI());
return new ResponseEntity<>(error, error.getHttpStatus());
}
}
The client knows which entity it requested to delete, so there's no need to include the id in the error message returned to the client. You could log the message with he id to the log file.

How to avoid "a different object with the same id.."?

I am using:
Web App (a filter opens session. DAO uses getCurrentSession())
Hibernate
Spring (AOP configuration over Service)
xml configuration for all
DTO between Mbean and Service
Well, I have two methods (business service):
service.findUser(..DTO..)
service.updateUser(..DTO..)
update throws org.hibernate.NonUniqueObjectException exception.
How can I avoid that?
I need to use update, not merge.
Thanks in advance.
//MBean.java method
public void testUpdateUser(ActionEvent e) {
System.out.println(name);
ServiceResponse<UserDto> serviceResponse = super.getPrincipalService().findUser(name);
UserDto userDto = serviceResponse.getResponseList().get(0);
//update some properties here
serviceResponse = super.getPrincipalService().updateUser(userDto);
LOG.info("" + serviceResponse);
}
//Service.java: update method
public ServiceResponse<UserDto> updateUser(UserDto userDto) {
LOG.info("");
ServiceResponse<UserDto> serviceResponse = new ServiceResponse<UserDto>();
try {
User user = this.getGlobalMapper().map(userDto, User.class);
//
this.getUserDao().update(user);
userDto = this.getGlobalMapper().map(user, UserDto.class);
serviceResponse.getResponseList().add(userDto);
serviceResponse.setOperationCodeResponse(ServiceResponseCode.OK);
serviceResponse.getMessages().add("Operacion OK");
} catch (Exception e) {
serviceResponse.getMessages().add(e.getMessage());
serviceResponse.setOperationCodeResponse(ServiceResponseCode.MODEL_ERROR);
LOG.error("", e);
}
return serviceResponse;
}
//Exception result
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.softlogia.copi.model.domain.User#155]
at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:696)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:296)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:241)
at org.hibernate.event.internal.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:55)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireUpdate(SessionImpl.java:705)
at org.hibernate.internal.SessionImpl.update(SessionImpl.java:697)
at org.hibernate.internal.SessionImpl.update(SessionImpl.java:693)
I am assuming you are using pure Hibernate as ORM; simply put, regardless of the status of your db, you have in your current Hibernate session different copies of the same row. To resolve this you can:
1) flush() the hibernate session after every writing operation on db (insert or update)
OR
2) In your update metod call merge() instead of saveOrUpdate()

AngularJS ngWebscoket not send message to all user

I am using ngWebsocket for listening user actions and update all users page according to current action not just page that who send action.
And I make a end point in java who catch all actions and send message all open sessions. but when i testing, end point find sessions and send message to all of them but message just come to person who send action.
my java code like
#OnMessage
public String onMessage(Session session, String message) { Gson gson = new Gson();
SocketMessage sm = gson.fromJson(message, new SocketMessage().getClass());
if (sm.getEvent().equals("teklif")) {
Set<Session> openSessions = session.getOpenSessions();
for (Session openSession : openSessions) {
try {
openSession.getBasicRemote().sendText("{\"event\":\"teklif\",\"data\":" + sm.getData() + "}");
} catch (Exception ioe) {
System.out.println(ioe.getMessage());
}
}
}
return message;
}`
when i debug Set<Session> openSessions = session.getOpenSessions(); it show me two session and send message to all remote. And I listen in my controller
$rootScope.ws.$on('teklif', function (data) { console.log(data);
});
it is shown only person who emit the message
note : I send message like this -->$rootScope.ws.$emit('teklif', data.content);
How can I make this socket that all user listen all actions ?
Thanks in advance.
Your are using Session.getOpenSessions(). The Javadoc states:
Return a copy of the Set of all the open web socket sessions that
represent connections to the same endpoint to which this session
represents a connection. The Set includes the session this method is
called on. These sessions may not still be open at any point after the
return of this method. For example, iterating over the set at a later
time may yield one or more closed sessions. Developers should use
session.isOpen() to check.
So it does not give you the set of all client sessions connected to your endpoint.
Instead you need to keep track of all session connected to your endpoint for yourself and iterate over that set. Here is an example.
I found my problem what is it .
#OnMessage
public String onMessage(Session session, String message) {
Gson gson = new Gson();
SocketMessage sm = gson.fromJson(message, new SocketMessage().getClass());
if (sm.getEvent().equals("teklif")) {
//SoncketTestMessage fromJson = gson.fromJson(test.getData(), SoncketTestMessage.class);
Set<Session> openSessions = session.getOpenSessions();
for (Session openSession : openSessions) {
try {
SocketResponse rsp = new SocketResponse();
rsp.setEvent("teklif");
rsp.setData(gson.toJson(sm.getData()));
//openSession.getBasicRemote().sendText("{\"event\":\"teklif\",\"data\":" + sm.getData() + "}");
openSession.getBasicRemote().sendText(gson.toJson(rsp, SocketResponse.class));
} catch (Exception ioe) {
System.out.println(ioe.getMessage());
}
}
}
return null;
}
i made a mistake at
openSession.getBasicRemote().sendText("{\"event\":\"teklif\",\"data\":" + sm.getData() + "}");
i just changed sm.getData and send right json format then it send to all user.
It send just to owner before because of that function return message and it is at right format and only owner get the return. Now all user are getting the message.

JGroups on Receive ClassNotFoundException

So I am trying to send a message across the cluster, the message will contain a User object which is a Serializable class.
When I send a String or an int it works perfectly, the message is sent without a problem and all channels on the cluster receive it.
When I try to send my own object User it gives me this exception;
Dec 7, 2013 3:55:19 PM org.jgroups.logging.JDKLogImpl error
SEVERE: JGRP000019: failed passing message to receiver: %s
java.lang.IllegalArgumentException: java.lang.ClassNotFoundException: User
at org.jgroups.Message.getObject(Message.java:378)
at AuctionImpl$ReceiverClass.receive(AuctionImpl.java:151)
at org.jgroups.JChannel.up(JChannel.java:738)
This is my receive code;
public void receive(Message msg) {
User user = (User) msg.getObject();
System.out.println("Username: " + user.getUsername());
}
The odd thing is I can create a new instance of User inside the receive and get no problems. for example;
public void receive(Message msg) {
User user = new User("Test", "Test");
User user = (User) msg.getObject();
System.out.println("Username: " + user.getUsername());
}
Anyone got any ideas?
Take a look at the ClassNotFoundException: your User class is not on the classpath when running your program.

Jersey: Returns 204 Status Instead of 500

I have a Jersey web service with the following a resource class:
#Stateless
#Path("/provision")
public class ProvisionResource
{
private final Logger logger = LoggerFactory.getLogger(ProvisionResource.class);
#EJB
private ProvisionService provisionService;
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/subscriber")
public SubscriberAccount querySubscriberAccount(
#QueryParam("accountNum") String accountNum)
{
logger.debug("Entering querySubscriberAccount()");
final SubscriberAccount account;
try
{
account = provisionService.querySubscriber(accountNum);
if (account != null)
{
logger.debug("Retreived account = " + account);
}
else
{
logger.debug("No account was found for " + accountNum);
}
}
catch (IllegalArgumentException ex)
{
logger.error("Illegal argument while executing query for subscriber account",
ex);
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}
catch (Exception ex)
{
logger.error("Unexpected exception while executing query for subscriber account",
ex);
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
logger.debug("Exiting querySubscriberAccount()");
return account;
}
.... snip ....
}
The provisionService.querySubscriber throws an exception which is caught by the second catch statement in the querySubscriberAccount method (we see the log statement in the file). However, the client is receiving a 204 status instead of the expected 500 error.
I did find this issue which is similar to mine: http://java.net/jira/browse/JERSEY-41 but is quite old and for Jersey 1.3.1. We are using version 1.9.1.
Has anyone else seen this issue and hopefully figured out what the problem is?
I have created a bug http://java.net/jira/browse/JERSEY-1062 for this issue. Please consider voting for it if you are experiencing the same problem.

Categories