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.
Related
I have developed a project using Hibernate. I am trying to test it using Junit with H2 in memory db but the test case is creating fields in the db that I am using it for development.
Here is my code :
UserDAO.java
public interface UserDAO {
public void addUser(String username, String password);
public List<String> getUsers();
}
UserDAOImpl.java
public class UserDAOImpl implements UserDAO {
public static final Logger LOG = LoggerFactory.getLogger(UserDAOImpl.class);
private static Session session;
private static void beginSession() {
session = DbUtils.getSessionFactory().openSession();
session.beginTransaction();
}
#Override
public void addUser(String username, String password) {
String encryptedPassword = Utils.encrypt(password);
User user = new User(username, encryptedPassword);
beginSession();
try {
session.save(user);
System.out.println(user.getPassword());
session.getTransaction().commit();
} catch (SQLGrammarException e) {
session.getTransaction().rollback();
LOG.error("Cannot save user", e);
} finally {
session.close();
}
}
#Override
public List<String> getUsers() {
beginSession();
List<String> results = new ArrayList<String>();
String hql = "select username from User";
Query query = null;
try {
query = session.createQuery(hql);
results = query.list();
} catch (HibernateException e) {
LOG.error("Cannot execute query", e);
}
return results;
}
}
Files for test cases
SessionFactoryRule.java
public class SessionFactoryRule implements MethodRule {
private SessionFactory sessionFactory;
private Transaction transaction;
private Session session;
#Override
public Statement apply(final Statement statement, FrameworkMethod method, Object test) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
sessionFactory = createSessionFactory();
createSession();
beginTransaction();
try {
statement.evaluate();
} finally {
shutdown();
}
}
};
}
private void shutdown() {
try {
try {
try {
transaction.rollback();
} catch (Exception ex) {
ex.printStackTrace();
}
session.close();
} catch (Exception ex) {
ex.printStackTrace();
}
sessionFactory.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private SessionFactory createSessionFactory() {
Configuration configuration = new Configuration().configure();
configuration.addAnnotatedClass(User.class)
.addAnnotatedClass(Message.class);
configuration.setProperty("hibernate.dialect",
"org.hibernate.dialect.H2Dialect");
configuration.setProperty("hibernate.connection.driver_class",
"org.h2.Driver");
configuration.setProperty("hibernate.connection.url", "jdbc:h2:./data/db");
configuration.setProperty("hibernate.hbm2ddl.auto", "create");
SessionFactory sessionFactory = configuration.buildSessionFactory();
return sessionFactory;
}
public Session createSession() {
session = sessionFactory.openSession();
return session;
}
public void commit() {
transaction.commit();
}
public void beginTransaction() {
transaction = session.beginTransaction();
}
public Session getSession() {
return session;
}`
Here is my test case
UserDAOTest.java
public class UserDAOTest {
#Rule
public final SessionFactoryRule sf = new SessionFactoryRule();
#Test
public void testAddUser() {
Session session = sf.getSession();
UserDAOImpl userDAOImpl = new UserDAOImpl();
String username = "stackoverflow";
String password = "testing";
userDAOImpl.addUser(username, password);
}
}
This test case is updating the fields username and password in the db that I am using while development. How can I stop it and use h2 in-memory db for testing.
You have session = DbUtils.getSessionFactory().openSession() in the UserDAOImpl. This is the reason of using a development database. Your SessionFactoryRule is not used at all.
So what you can to do.
The best choice is use to Spring for Hibernate configuration and unit testing.
Other option is to set sessionFactory to the UserDAOImpl using constructor.
Also, using static here is a really very very bad idea
private static Session session;
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.
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();
}
}
When I used spring aop(aspectJ proxy-target-class="true"), List can receive the parameters from json but it shows that "java.util.hashmap cannot be cast to MyEntity". And I am using SSH framework. The codes are shwon below:
package com.yoyo.aspect;
#Aspect
#Component
#Scope("prototype")
#ParentPackage("json-default")
#Results({#Result(name="result", type="json", params={"root","dataMap"})})
public class LoggerAspect extends SuperAction{
#Autowired
private LoggerService loggerService;
//signature
#Pointcut("execution(String com.yogo.action.admin..*.*(..))")
public void adminLogger(){}
#Pointcut("execution(String com.yogo.action.enterprise..*.*(..))")
public void enterpriseLogger(){}
#Pointcut("execution(String com.yogo.action.product..*.*(..))")
public void productLogger(){}
#Around(value="adminLogger()||enterpriseLogger()||productLogger()")
public Object loggerAround(ProceedingJoinPoint pjp) throws Throwable{
ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
HttpSession session=attr.getRequest().getSession(true);
String className = pjp.getSignature().getDeclaringTypeName();
Method method = ((MethodSignature)pjp.getSignature()).getMethod();
String methodName = method.getName();
Logger log = new Logger();
log.setClassName(className);
log.setMethodName(methodName);
try {
log.setResult("success");
return pjp.proceed();
} catch (Throwable throwable) {
log.setResult("failure");
return RESULT;
} finally {
if(session!=null&&session.getAttribute("AID")!=null){
log.setAid((int)session.getAttribute("AID"));
log.setDatetime(new Date());
loggerService.save(log);
}
}
}
}
package com.yoyo.action.product.property;
#Controller
#Scope("prototype")
#ParentPackage("json-default")
#Namespace("/product")
#Results({#Result(name="result", type="json", params={"root","dataMap"})})
#InterceptorRefs({#InterceptorRef(value="json"), #InterceptorRef(value="defaultStack")})
public class AddOrUpdateProductPropertyAction extends SuperAction /*implements ModelDriven<ProductProperty>*/{
#Autowired
private ProductPropertyService productPropertyService;
private ProductProperty productProperty = new ProductProperty();
private List<ProductProperty> list;
private Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public List<ProductProperty> getList() {
return list;
}
public void setList(List<ProductProperty> list) {
this.list = list;
}
/*#Override
public ProductProperty getModel() {
return productProperty;
}*/
#Action(value="AddOrUpdateProductProperty")
public String addOrUpdateProductProperty() throws Throwable{
int pid = product.getPid();
try {
if(pid!=0&&!"".equals(pid)){
productProperty.setPid(pid);
for(int i=0; i<list.size(); i++){
productProperty.setPpid(list.get(i).getPpid());
productProperty.setPkey(list.get(i).getPkey());
productProperty.setPvalue(list.get(i).getPvalue());
productProperty.setStatus(list.get(i).getStatus());
productPropertyService.saveOrUpdate(productProperty);
}
}else{
setErrorResult(2, "No Product ID");
}
} catch (Exception e){
setErrorResult(1, e.getMessage());
throw new Exception(e);
}
return RESULT;
}
}
And I post the json in the right format to this AddOrUpdateProductProperty(url):
{
"product":{
"pid":"1"
},
"list":[
{
"pkey": "",
"pvalue":"45%",
"status":1
}]
}
the response saying(exception.getMessage):
{"msg":"java.util.HashMap cannot be cast to com.yogo.entity.ProductProperty","flag":1}
If I comment the AOP execution, everything runs well and all the data in "list" can be well received and written in mysql successfully.
//#Around(value="adminLogger()||enterpriseLogger()||productLogger()")
I also checked receiving the data in "list" using println. I found that it can receive it but cannot cast to MyEntity "ProductProperty":
System.out.println(list.get(i));
//this works
System.out.println(list.get(i).getPpid());
//this got error as above
I am not quite familiar with spring aop mechanism, anyone could help? Thank you so much!
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.