I am building a java REST application. Therefor I am using jboss on a wildfly 8 server.
The following code causes this exception: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
#Path("/users")
#Stateless
public class UsersEndpoint {
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response create(User user) {
try {
this.checkUsername(user.getUsername());
this.checkEmail(user.getEmail());
return Response.ok(userDAO.create(user)).build();;
} catch (IOException e) {
return Response.status(Response.Status.NOT_ACCEPTABLE)
.entity(e.getMessage())
.build();
} catch (Exception e) {
return Response.status(Response.Status.NOT_ACCEPTABLE)
.entity(e.getMessage())
.build();
}
}
#POST
#Path("username")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.TEXT_HTML)
public Response username(String username) {
try {
this.checkUsername(username);
return Response.ok().build();
} catch (Exception e) {
return Response.status(Response.Status.NOT_ACCEPTABLE)
.entity(entity)
.build();
}
}
#POST
#Path("email")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.TEXT_HTML)
public Response email(String email) {
try {
this.checkEmail(email);
return Response.ok().build();
} catch (Exception e) {
return Response.status(Response.Status.NOT_ACCEPTABLE)
.entity(this.validator.validateError(null, e))
.build();
}
}
private void checkUsername(String username) throws IOException {
try {
userDAO.get(username);
throw new IOException("Username is taken allready.");
}
catch (IOException e) { throw e; }
catch (Exception e) { System.out.println("Username can be used"); }
}
private void checkEmail(String email) throws IOException {
try {
userDAO.getByEmail(email);
throw new IOException("Email is taken allready.");
}
catch (IOException e) { throw e; }
catch (Exception e) { System.out.println("Email can be used"); }
}
}
The public Response email(String email) and public Response username(String username) functions are working fine. The Problem seems to be the call of both functions through the public Response create(User user) function:
...
try {
this.checkUsername(user.getUsername());
this.checkEmail(user.getEmail());
...
So now when I have a correct username but a duplicate email the exception JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context) is going to be thrown in the userDAO.getByEmail(email). When I have a duplicate username instead the IOException("Username is taken allready.") is going to be thrown as expected.
When I change the order of those functions to:
...
try {
this.checkEmail(user.getEmail());
this.checkUsername(user.getUsername());
...
the same problem occurs but in userDAO.get(username) and with a correct email and a duplicate username.
EDIT
When I am removing throw new IOException("Username is taken allready."); in private void checkUsername(String username) throws IOException { } the second DAO call is working fine. So the problem seems to be the Exception that is thrown. How can I solve that?
My UserDAO
public interface UserDAO {
public User create(User user) throws Exception;
public User get(String username) throws Exception;
public User getByEmail(String email) throws Exception;
}
My UserBean
#Stateless
#Remote(UserDAO.class)
public class UserBean implements UserDAO {
// Injected database connection:
#PersistenceContext private EntityManager em;
#Override
public User create(User user) throws Exception {
em.persist(user);
return user;
}
#Override
public User get(String username) throws Exception {
return em.createNamedQuery(User.QUERY_USERNAME, User.class)
.setParameter("userName", username)
.getSingleResult();
}
#Override
public User getByEmail(String email) throws Exception {
return em.createNamedQuery(User.QUERY_EMAIL, User.class)
.setParameter("email", email)
.getSingleResult();
}
}
Related
I register a DateTimeFormatterRegistrar in my class implements WebMvcConfigurer like this:
#Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
In the rest controller, i try to parse client GET params to an object:
#GetMapping("/api/url/path")
public APIResponse getPersonAttendList(#Valid SampleVO vo){}
SampleVO include field LocalDateTime time. If client offered wrong format of time param, the binding will be failed. Server will return 500, and print some log like this:
>ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] 175 - Servlet.service() for
servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;
nested exception is java.time.format.DateTimeParseException
My question is, how to catch this exception, and return 400 to the client? It seems ControllerAdvice is not working.
In my project I am using #RestControllerAdvice to handle such cases, an example would be,
#RestControllerAdvice
public class MyCustomExceptionsHandler {
#ExceptionHandler({HttpMessageNotReadableException.class})
public ResponseEntity handleException(HttpMessageNotReadableException httpMessageNotReadableException) {
//return the response entity you need here with the correct error
}
}
This is something that is working for me.
You should be able to catch this with a "try{}, catch(){}, and finally{}". You would try the code and then catch the exception, then return a 400 error to the client.
try {
//your code
} catch (java.time.format.DateTimeParseException e) {
//Return 400 here
} finally {
//Other code here
}
I'm sorry. I made a mistake here. First, i design to return client all response like
#Getter
#Setter
#AllArgsConstructor
public class APIResponse {
private Integer status;
private String msg;
private Object data;
#NotNull
public static APIResponse fromData(Object data) {
return new APIResponse(0, "", data);
}
#NotNull
public static APIResponse fromError(#NotNull BaseError err) {
return new APIResponse(err.getStatus(), err.getMsg(), null);
}
#NotNull
public static APIResponse fromError(#NotNull BaseError err, Object data) {
return new APIResponse(err.getStatus(), err.getMsg(), data);
}
#NotNull
public static APIResponse fromEmpty() {
return new APIResponse(0, "", null);
}
}
I made a global error catch like this:
#RestControllerAdvice
#Slf4j
public class ErrorWrapper {
private String getErrMsg(BindingResult bindingResult) {
StringBuilder stringBuilder = new StringBuilder();
for (FieldError error : bindingResult.getFieldErrors()) {
stringBuilder.append(error.getDefaultMessage()).append(";");
}
String msg = stringBuilder.toString();
log.debug("valid error:{}", msg);
return msg;
}
/**
* Bean validation error
* #see javax.validation.Valid
* #see org.springframework.validation.Validator
* #see org.springframework.validation.DataBinder
*/
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public APIResponse paramNotValidHandler(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
return APIResponse.fromError(new ParamError(getErrMsg(bindingResult)));
}
#ExceptionHandler(BindException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public APIResponse paramBindErrorHandler(BindException e) {
BindingResult bindingResult = e.getBindingResult();
return APIResponse.fromError(new ParamError(getErrMsg(bindingResult)));
}
#ExceptionHandler(MethodArgumentTypeMismatchException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
private APIResponse paramConvertErrorHandler(MethodArgumentTypeMismatchException e) {
log.debug("valid error:", e);
return APIResponse.fromError(new ParamError("argument error:%s", e.getCause().getMessage()));
}
#ExceptionHandler(ServletRequestBindingException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
private APIResponse paramBindErrorHandler(ServletRequestBindingException e) {
return APIResponse.fromError(new ParamError("param bind error"));
}
#ExceptionHandler(InvalidPropertyException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public APIResponse invalidProperty(InvalidPropertyException e) {
return APIResponse.fromError(new ParamError(e.getPropertyName() + " format error"));
}
#ExceptionHandler(PermissionError.class)
#ResponseStatus(HttpStatus.FORBIDDEN)
private APIResponse permissionErrorHandler(PermissionError e) {
log.debug("not allowed:", e);
return APIResponse.fromError(e);
}
#ExceptionHandler(HttpRequestMethodNotSupportedException.class)
#ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
private APIResponse methodError() {
return APIResponse.fromError(new ClientError("HTTP Method error"));
}
#ExceptionHandler(MaxUploadSizeExceededException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
private APIResponse fileTooLarge() {
return APIResponse.fromError(new ClientError("file is too big"));
}
#ExceptionHandler(MissingServletRequestPartException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
private APIResponse badRequest(MissingServletRequestPartException e) {
return APIResponse.fromError(new ClientError("file not exist"));
}
#ExceptionHandler(HttpMessageConversionException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
private APIResponse badRequest(HttpMessageConversionException e) {
return APIResponse.fromError(new ClientError("can't parse"));
}
#ExceptionHandler(ClientAbortException.class)
private APIResponse clientAbortHandler(ClientAbortException e) {
return null;
}
#ExceptionHandler(ClientError.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
private APIResponse clientErrorHandler(ClientError e) {
log.debug("bad request:", e);
return APIResponse.fromError(e);
}
#ExceptionHandler(ServerError.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
private APIResponse serverErrorHandler(ServerError e) {
log.error("server error:" + e.getMsg(), e);
return APIResponse.fromError(e);
}
#ExceptionHandler(DataIntegrityViolationException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
private APIResponse duplicateKeyError(DataIntegrityViolationException e) {
log.debug("duplicate source:", e);
return APIResponse.fromError(new ClientError("db unqiue key error"));
}
#ExceptionHandler(Exception.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
private APIResponse unknownErrorHandler(Exception e) {
String tips = "unknown error:";
if (e.getCause() != null) {
tips += e.getCause().getMessage();
} else if (e.getMessage() != null) {
tips += e.getMessage();
} else {
tips += e.toString();
}
log.error(tips, e);
return APIResponse.fromError(new ServerError());
}
So, if no catcher matched above, the last one will return 500.
There are so many exceptions for spring boot, i don't know how to catch them all and return 400 without missing any one.
If you want to catch all spring's exceptions in your controller advice then you need to catch Exception.class and then check the class name of the exception.
#Slf4j
#RestControllerAdvice(basePackages = "com.your.package.name")
public class ErrorWrapper {
#ExceptionHandler(Exception.class)
public APIResponse handleException(Exception ex, WebRequest request) {
if (ex.getClass().getCanonicalName().startsWith("org.springframework.")) {
return APIResponse.fromError(new ClientError(ex.getMessage()));
}
return APIResponse.fromError(new ServerError());
}
}
Surround this statement(DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar()) in try catch block .
try{
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
} catch (Exception e) {
e.printStacktrace();
}
I dont know why i cannot call getAll() class in ManagerBase class from UserDAO, but with other class it still be ok
Hibernate code here
protected Session getCurrentSession() throws Exception {
if (session == null){ //check session null
if (sessionFactory == null){ //build sessionFactory if it null
if(sessionFactoryConfigPath == null || sessionFactoryConfigPath.equals("")){
sessionFactory = new Configuration().configure().buildSessionFactory();
}else{
sessionFactory = new Configuration().configure(this.sessionFactoryConfigPath).buildSessionFactory();
}
}
session = sessionFactory.getCurrentSession();
}
return session;
}
ManagerBase code
public abstract class ManagerBase<T> extends HibernateUtil {
private Class<T> persistentClass;
public ManagerBase() throws Exception {
super();
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments().getClass();
}
public ManagerBase(String sessionFactoryConfigPath) throws Exception {
super(sessionFactoryConfigPath);
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments().getClass();
}
public Class<T> getPersistentClass() {
return this.persistentClass;
}
public List<T> getAll() {
List<T> list = null;
try {
beginTransaction();
list = getCurrentSession().createCriteria(this.persistentClass).list();
commitAndClose();
} catch (Exception ex) {
System.out.println("getAll Error \n" + ex);
}
return list;
}
UserDAO code here.....
code
public class UserDAO extends ManagerBase<User> {
public UserDAO() throws Exception {
}
public List<User> getAllUser() {
try {
List<User> user = getAll();
return user;
} catch (Exception ex) {
System.out.println("Get All User Error \n" + ex);
return null;
}
}
}
Any body please help me, in the console board that show only Begin and commit and it doesnt has any HQL code.
In my spring project I want to save students information in mysql database.
If there is any error then it will display in jsp page within corresponding input box.
so,I have:-
StudentDao class
public interface StudentDao {
public void add ( Student student );
}
StudentDaoImpl class
public class StudentDaoImpl implements StudentDao {
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
public void add( Student student){
sessionFactory.getCurrentSession().save(student);
}}
StudentService class
public interface StudentService {
Student add(String name, String email) throws SQLException,
DataAccessException,
DataIntegrityViolationException,
ConstraintViolationException{
}
StudentServiceImpl class
public class StudentServiceImpl implements StudentService {
#Autowired
private StudentDao studentDao;
#Transactional(propagation = Propagation.REQUIRED)
public Student add(String name, String email) throws SQLException,
DataAccessException,
DataIntegrityViolationException,
ConstraintViolationException{
Student student = new Student(name,email);
studentDao.add(student);
return student;
}
}
controller class
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String doAdd(#Valid #ModelAttribute("student") Student student,BindingResult result,HttpServletRequest request,
HttpServletResponse response,Model model){
validator.validate(student, result);
if (result.hasErrors()) {
return "signup";
}
#SuppressWarnings("unused")
Student student1;
try{
try {
student1= studentService.add(student.getName(), student.getEmail());
} catch (ConstraintViolationException e) {
model.addAttribute("email", "already exists");
e.printStackTrace();
return "signup";
} catch (DataAccessException e) {
model.addAttribute("email", "already exists");
e.printStackTrace();
return "signup";
} catch (SQLException e) {
model.addAttribute("email", "already exists");
e.printStackTrace();
return "signup";
}
}catch (DataIntegrityViolationException e)
{
model.addAttribute("email", "already exists");
e.printStackTrace();
return "signup";
}
return "signup";
}
but the problem is in my database email field is unique.so, for duplicate entry I am getting log message:
WARN JDBCExceptionReporter:100 - SQL Error: 1062, SQLState: 23000
JDBCExceptionReporter:101 - Duplicate entry 'df#gmail.com' for key 'unique_index2'
org.hibernate.exception.ConstraintViolationException: could not insert: [com.myweb.model.Student]
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'df#gmail.com' for key 'unique_index2'
I want to place this error to jsp view email field that email already exists I used throws block in service class and try-catch block in controller class..though why the error is not showing in jsp view?
So, you are using spring with hibernate..
and the exception is: ConstraintViolationException
thats why its:
org.hibernate.exception.ConstraintViolationException
just add:
<h1>${email}</h1>
you can use other tag to display that message.
Just write below Syntax in ConstraintViolationException not in Ever Exception.
Syntax of :
model.addAttribute("any variable name", "Your Message/Value");
As you have defined
model.addAttribute("email", "already exists");
So on jsp side
you will get email variable message/value as ${email}
just add
${email} el variable in your jsp page.
if i have something like this:
public User findUserByEmail(String email) throws CustomerNotFoundException{
List<User> users = new ArrayList<User>();
users = sessionFactory.getCurrentSession().createQuery("from User where email = ?").setParameter(0,email).list();
if (users.size() > 0) {
return users.get(0);
} else {
throw new CustomerNotFoundException();
}
}
And in this moment i want to check the returned findUserByEmail(String email) method whether it return the User object or CustomerNotFoundException in the end.
I tried in this way
private boolean searchCustomer(String email) throws CustomerNotFoundException{
if (hibernateDao.findUserByEmail(email).getClass() == User.class) {
....
} else { .... }
}
Is it a good way or are there betters?
No. Nonononono.
Use the catch keyword to catch the Exception.
try {
User thingie = hibernateDao.findUserByEmail(email);
}
catch (CustomerNotFoundException cnfe) {
// TODO some logic on failure
}
Also remove the throws statement from your searchCustomer method's signature if you're using a try / catch mechanism and not rethrowing the Exception.
I have the following situation with Java persistence:
public ReturnCodes startWork() {
sessionBackup = (BaseService<Backup>) ctx.lookup("XYZ/BackupServiceImpl/local");
Backup backup = new Backup();
backup.setStatus(BackupStatus.EXECUTING);
....
sessionBackup.save(Backup) //at this point is not actualy saved into DB
....//try to connect somewhere
if ( !ConnectSuccess) {
sessionBackup.remove(backup);
return ReturnCodes.REQUESTABORT
}
....
}
#Stateless
public class BackupServiceImpl extends BaseServiceImpl<Backup> implements
BaseService<Backup>
{
#Override
protected Class<Backup> getEntityClass()
{
return Backup.class;
}
}
And the save and remove methods of BaseServiceImpl:
public abstract class BaseServiceImpl<T extends Serializable> implements
BaseService<T>
{
protected EntityManagerFactory emf;
public T save(T entity)
{
EntityManager em = emf.createEntityManager();
em.persist(entity);
return entity;
}
public void remove(T entity)
{
EntityManager em = emf.createEntityManager();
try
{
final Method method = getEntityClass().getMethod("getId");
final String id = (String) ((T) method.invoke(entity));
entity = em.find(getEntityClass(), id);
em.remove(entity);
}
catch (final Exception ex)
{
logger.log(Level.WARNING, "Unexpected error", ex);
}
}
}
I don't want to save into the DB in case ConnectSuccess fails, but the remove method fails to find the entity (because is not yet into the DB), and after returning ReturnCodes.REQUESTABORT the entity is saved.
How can I cancel the save?
In general in this case you do a setRollbackOnly().
You may also throw an exception which will trigger the rollbackonly.
See http://www.developerscrappad.com/547/java/java-ee/ejb3-x-jpa-when-to-use-rollback-and-setrollbackonly/
By the way doing this in your code:
catch (final Exception ex)
{
logger.log(Level.WARNING, "Unexpected error", ex);
}
is too broad and will block rollback functionality.