I have 2 entities User and Status. I can load users list and can see its sql(log) in console
(select this_.id as id0_0_,
this_.cl_point_id as cl2_0_0_,
this_.date_ll as date3_0_0_,
this_.date_reg as date4_0_0_,
this_.name as name0_0_,
this_.passw_salt as passw6_0_0_,
this_.status_id as status7_0_0_,
this_.passw as passw0_0_, this_.login
as login0_0_ from users this_)
.
But when I load Status the list is empty and there is no sql(log) in console. I can't find where is the problem?
User.java
package tj.eskhata.pos.domain;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
#Entity
#Table(name="users")
public class User implements DomainObject {
#Id
private Long id;
#Column(name="name")
private String fullname;
#Column(name="cl_point_id")
private Long clPointId;
#Column(name="login")
private String wiaUsername;
#Column(name="passw")
private String wiaPassword;
#Column(name="status_id")
private Long statusId;
#Column(name="date_reg")
private Date dateReg;
#Column(name="date_ll")
private Date dateLl;
#Column(name="passw_salt")
private String passwSalt;
public User() {
}
public User(String username, String password, String fullname,
boolean isAdmin) {
this.id=Long.valueOf(1);
this.wiaUsername = username;
this.wiaPassword = password;
this.fullname = fullname;
}
public String getFullname() {
return fullname;
}
public String getWiaPassword() {
return wiaPassword;
}
public String getWiaUsername() {
return wiaUsername;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
public void setWiaPassword(String password) {
this.wiaPassword = password;
}
public void setWiaUsername(String username) {
this.wiaUsername = username;
}
public Long getId() {
return id;
}
public Long getClPointId() {
return clPointId;
}
public Long getStatusId() {
return statusId;
}
public Date getDateReg() {
return dateReg;
}
public Date getDateLl() {
return dateReg;
}
public String getPasswSalt() {
return passwSalt;
}
public void getClPointId(Long clPointId_) {
this.clPointId=clPointId_;
}
public void setStatusId(Long statusId_) {
this.statusId=statusId_;
}
public void setDateReg(Date dateReg_) {
this.dateReg=dateReg_;
}
public void setDateLl(Date dateLl_) {
this.dateLl=dateLl_;
}
public void setPasswSalt(String passwSalt_) {
this.passwSalt=passwSalt_;
}
public boolean isAdmin() {
return false;
}
}
Status.java
package tj.eskhata.pos.domain;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
#Entity
#Table(name="status")
public class Status implements DomainObject {
public Status() {
}
public Status(Long id) {
this.id = id;
}
public Status(Long id, String code, String name, String fullName,
String color) {
this.id = id;
this.code = code;
this.name = name;
this.fullName = fullName;
this.color = color;
}
#Id
private Long id;
public void setId( Long id_) {
this.id=id_;
}
public Long getId() {
return this.id;
}
#Column(name = "code")
private String code;
public void setCode( String code_) {
this.code=code_;
}
public String getCode() {
return this.code;
}
#Column(name = "name")
private String name;
public void setName( String name_) {
this.name=name_;
}
public String getName() {
return this.name;
}
#Column(name = "full_name")
private String fullName;
public void setFullName( String fullName_) {
this.name=fullName_;
}
public String getFullName() {
return this.fullName;
}
#Column(name = "color")
private String color;
public void setColor( String color_) {
this.color=color_;
}
public String getColor() {
return this.color;
}
}
*
UserDaoImpl.java:
package tj.eskhata.pos.dao.hibernate;
import tj.eskhata.pos.dao.UserDao;
import tj.eskhata.pos.domain.User;
public class UserDaoImpl extends AbstractHibernateDaoImpl<User>
implements UserDao {
public UserDaoImpl() {
super(User.class);
}
}
StatusDaoImpl.java:
package tj.eskhata.pos.dao.hibernate;
import tj.eskhata.pos.dao.StatusDao;
import tj.eskhata.pos.domain.Status;
public class StatusDaoImpl extends AbstractHibernateDaoImpl<Status>
implements StatusDao {
public StatusDaoImpl() {
super(Status.class);
}
}
UserDao.java:
package tj.eskhata.pos.dao;
import tj.eskhata.pos.domain.User;
public interface UserDao extends Dao<User> {
}
StatusDao.java:
package tj.eskhata.pos.dao;
import tj.eskhata.pos.domain.Status;
public interface StatusDao extends Dao<Status> {
}
AbstractHibernateDaoImpl.java:
package tj.eskhata.pos.dao.hibernate;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import tj.eskhata.pos.dao.Dao;
import tj.eskhata.pos.domain.DomainObject;
public abstract class AbstractHibernateDaoImpl<T extends DomainObject>
implements Dao<T> {
private Class<T> domainClass;
private SessionFactory sf;
public AbstractHibernateDaoImpl(Class<T> domainClass) {
this.domainClass = domainClass;
}
public SessionFactory getSessionFactory() {
return sf;
}
public void setSessionFactory(SessionFactory sf) {
this.sf = sf;
}
public void delete(T object) {
getSession().delete(object);
}
#SuppressWarnings("unchecked")
public T load(long id) {
return (T) getSession().get(domainClass, id);
}
public void save(T object) {
getSession().saveOrUpdate(object);
}
#SuppressWarnings("unchecked")
public List<T> findAll() {
Criteria criteria = getSession().createCriteria(domainClass);
List<T> r=(List<T>) criteria.list();
return r;
}
public int countAll() {
Criteria criteria = getSession().createCriteria(domainClass);
criteria.setProjection(Projections.rowCount());
return (Integer) criteria.uniqueResult();
}
public Session getSession() {
// presumes a current session, which we have through the
// OpenSessionInViewFilter; doesn't work without that
return sf.getCurrentSession();
}
}
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jndi="http://www.springframework.org/schema/jndi"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/jndi
http://www.springframework.org/schema/jndi/spring-jndi.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:application.properties</value>
</property>
<property name="systemPropertiesModeName">
<value>SYSTEM_PROPERTIES_MODE_OVERRIDE</value>
</property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>${jdbc.driver}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<property name="minPoolSize">
<value>${c3p0.minPoolSize}</value>
</property>
<property name="maxPoolSize">
<value>${c3p0.maxPoolSize}</value>
</property>
<property name="checkoutTimeout">
<value>20000</value>
</property>
<property name="maxIdleTime">
<value>${c3p0.maxIdleTime}</value>
</property>
<property name="idleConnectionTestPeriod">
<value>${c3p0.idleConnectionTestPeriod}</value>
</property>
<property name="automaticTestTable">
<value>${c3p0.automaticTestTable}</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>tj.eskhata.pos.domain.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
<bean id="wicketApplication"
class="tj.eskhata.pos.PosApplication">
</bean>
<bean id="UserDao"
class="tj.eskhata.pos.dao.hibernate.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="CountryDao"
class="tj.eskhata.pos.dao.hibernate.CountryDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="StatusDao"
class="tj.eskhata.pos.dao.hibernate.StatusDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="GenericDao"
class="tj.eskhata.pos.dao.hibernate.GenericDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="DiscountsService" class="tj.eskhata.pos.services.DiscountsServiceImpl">
<property name="userDao" ref="UserDao" />
<property name="countryDao" ref="CountryDao" />
<property name="statusDao" ref="StatusDao" />
<property name="genericDao" ref="GenericDao" />
</bean>
</beans>
DiscountService:
package tj.eskhata.pos.services;
import java.util.List;
import org.springframework.transaction.annotation.Transactional;
import tj.eskhata.pos.domain.Country;
import tj.eskhata.pos.domain.Status;
import tj.eskhata.pos.domain.User;
public interface DiscountsService {
<T> T load(Class<T> type, long id);
List<User> findAllUsers();
void saveUser(User user);
void deleteUser(User user);
List<Country> findAllCountries();
void saveCountry(Country country);
void deleteCountry(Country country);
List<Status> findAllStatuses();
void saveStatus(Status status);
void deleteStatus(Status status);
}
package tj.eskhata.pos.services;
import java.util.List;
import tj.eskhata.pos.dao.CountryDao;
import tj.eskhata.pos.dao.GenericDao;
import tj.eskhata.pos.dao.StatusDao;
import tj.eskhata.pos.dao.UserDao;
import tj.eskhata.pos.domain.Country;
import tj.eskhata.pos.domain.Status;
import tj.eskhata.pos.domain.User;
public class DiscountsServiceImpl implements DiscountsService {
private UserDao userDao;
private CountryDao countryDao;
private StatusDao statusDao;
private GenericDao genericDao;
public DiscountsServiceImpl() {
}
public <T> T load(Class<T> type, long id) {
return genericDao.load(type, id);
}
public List<User> findAllUsers() {
return userDao.findAll();
}
public void saveUser(User user) {
userDao.save(user);
}
public void deleteUser(User user) {
userDao.delete(user);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public List<Country> findAllCountries() {
return countryDao.findAll();
}
public void saveCountry(Country country) {
countryDao.save(country);
}
public void deleteCountry(Country country) {
countryDao.delete(country);
}
public CountryDao getCountryDao() {
return countryDao;
}
public void setCountryDao(CountryDao countryDao) {
this.countryDao = countryDao;
}
public List<Status> findAllStatuses() {
return statusDao.findAll();
}
public void saveStatus(Status status) {
statusDao.save(status);
}
public void deleteStatus(Status status) {
statusDao.delete(status);
}
public StatusDao getStatusDao() {
return statusDao;
}
public void setStatusDao(StatusDao statusDao) {
this.statusDao = statusDao;
}
public GenericDao getGenericDao() {
return genericDao;
}
public void setGenericDao(GenericDao genericDao) {
this.genericDao = genericDao;
}
}
The Status entity looks fine (it has an #Entity annotation, it has a default no-arg constructor, it has an #Id), I can't spot anything obvious.
So I would:
double check the startup logs to check for any complaint.
use the Hibernate Console (if you are using Eclipse) or any equivalent to load the Status using raw HQL or Criteria.
write a unit test anyway.
Oh, by the way, this is unrelated but you shouldn't have such things in your User entity:
#Column(name="status_id")
private Long statusId;
These Long look like foreign keys. When using an ORM, you should have objects and associations between objects, not ids. Something like this:
#ManyToOne
private Status status;
Same remark for clPointId.
You are IMHO thinking "too relational" and "not enough object". I might be wrong but having foreign key attributes in an entity is a strong hint.
I have changed #Column(name="status_id") private Long statusId; to #ManyToOne private Status status; Now I receiving the ERROR: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: #OneToOne or #ManyToOne on tj.eskhata.pos.domain.User.status references an unknown entity: tj.eskhata.pos.domain.Status
This message clearly shows that something goes wrong with Status that isn't recognized as an Entity (and thus can't be referenced in an association, preventing the session factory from being instantiated). This is usually due to a configuration or mapping problem. So:
Do you declare entities somewhere (in hibernate.cfg.xml or in persistence.xml)? If yes, did you declare Status? If you are using classpath scanning, is Status scanned?
Double-check the mapping, check that the column names really exist (it's unclear if you are using an existing physical model).
Activate logging (Spring Logging, Hibernate Logging), this is helpful during development and will help to find the problem.
Related
I am creating a website using Spring MVC and for persistence I am using Spring Data JPA with Hibernate 4 as my JPA provider. Validation is being handled at present with Hibernate Validator. I have a problem whereby my validators are being called twice and I can't figure out why. The main reason this is a problem is because the second time round, dependencies are not being autowired into the validator and I am getting a null pointer exception.
The following is the sequence of calls leading up to the failure:
The registration form is submitted and first the NotDefaultSectValidator is called and completes successfully for the 'whereDidYouHearAboutUs' field on the user object.
The UniqueUsernameValidator is called next and completes successfully for the 'username' field validation.
The 'addUserFromForm' method on the controller starts and finds no errors in the bindingResults object.
The 'addUser' method is then called on the UserService class. This method reaches the line 'userRepository.save(user);' but never then runs the 'print.ln' line immediate afterwards. Stepping over this line takes be back to the 'NotDefaultSectValidator' breakpoint. This completes for the second time and I re-enter the second validator 'UniqueUsernameValidator '. Here I get a null pointer exception because for some reason Spring fails to Autowire in the DAO this second time.
Can anyone shed light on why the validators are being called twice and in particular, why stepping over line 'userRepository.save(user);' goes back into these validators?
Many thanks
Here is my user.java class
package com.dating.domain;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.joda.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;
import com.dating.annotation.NotDefaultSelect;
import com.dating.annotation.UniqueUsername;
#Entity
#Table(name = "dating.user")
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username", unique = true)
#NotEmpty
#Pattern(regexp = "^[a-zA-Z0-9]*$")
#UniqueUsername
private String username;
#Column(name = "password", nullable = false)
#NotEmpty
#Size(min = 8)
private String password;
#Column(name = "first_name", nullable = false)
#NotEmpty
private String firstName;
#Column(name = "last_name", nullable = false)
#NotEmpty
private String lastName;
#Transient
private String fullName;
#Column(name = "email", nullable = false)
#NotEmpty
#Email
private String email;
#Column(name = "gender", nullable = false)
#NotEmpty
private String gender;
#Column(name = "date_of_birth", nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
#DateTimeFormat(pattern = "dd/MM/yyyy")
private LocalDate dateOfBirth;
#Column(name = "join_date", nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate joinDate;
#Column(name = "where_did_you_hear_about_us", nullable = false)
#NotDefaultSelect
private String whereDidYouHearAboutUs;
#Column(name = "enabled")
private boolean enabled;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "dating.user_roles", joinColumns = { #JoinColumn(name = "user_id", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "role_id", nullable = false, updatable = false) })
private Set<Role> roles = new HashSet<Role>();
#Column(name = "created_time", nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate createdTime;
#Column(name = "modification_time", nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate modificationTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName() {
return firstName + " " + lastName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public LocalDate getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(LocalDate dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public LocalDate getJoinDate() {
return joinDate;
}
public void setJoinDate(LocalDate joinDate) {
this.joinDate = joinDate;
}
public String getWhereDidYouHearAboutUs() {
return whereDidYouHearAboutUs;
}
public void setWhereDidYouHearAboutUs(String whereDidYouHearAboutUs) {
this.whereDidYouHearAboutUs = whereDidYouHearAboutUs;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public void addRole(Role role) {
roles.add(role);
}
public LocalDate getCreatedTime() {
return createdTime;
}
public void setCreatedTime(LocalDate createdTime) {
this.createdTime = createdTime;
}
public LocalDate getModificationTime() {
return modificationTime;
}
public void setModificationTime(LocalDate modificationTime) {
this.modificationTime = modificationTime;
}
#PreUpdate
public void preUpdate() {
modificationTime = new LocalDate();
}
#PrePersist
public void prePersist() {
LocalDate now = new LocalDate();
createdTime = now;
modificationTime = now;
}
}
The relevant method in my registration controller:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String addUserFromForm(#Valid User user,
BindingResult bindingResult, RedirectAttributes ra) {
if (bindingResult.hasErrors()) {
return "user/register";
}
userService.addUser(user);
// Redirecting to avoid duplicate submission of the form
return "redirect:/user/" + user.getUsername();
}
My service class:
package com.dating.service.impl;
import javax.transaction.Transactional;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.dating.domain.Role;
import com.dating.domain.User;
import com.dating.repository.RoleRepository;
import com.dating.repository.UserRepository;
import com.dating.repository.specification.UserSpecifications;
import com.dating.service.UserService;
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
#Transactional
#Override
public void addUser(User user) {
user.setJoinDate(new LocalDate());
user.setEnabled(true);
Role role = roleRepository.findByName(Role.MEMBER);
if (role == null) {
role = new Role();
role.setName(Role.MEMBER);
}
user.addRole(role);
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
user.setPassword(encoder.encode(user.getPassword()));
userRepository.save(user);
System.out.println("User Saved");
}
#Override
public User getUserByUsername(String username) {
return userRepository.findByUsername(username);
}
#Override
public Iterable<User> getAllUsers() {
return userRepository.findAll();
}
#Override
public void updateDetails(User user) {
userRepository.save(user);
}
#Override
public Iterable<User> lastNameIsLike(String searchTerm) {
return userRepository.findAll(UserSpecifications
.lastNameIsLike(searchTerm));
}
}
My NotDefaultSelect validator:
package com.dating.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import com.dating.annotation.NotDefaultSelect;
public class NotDefaultSelectValidator implements
ConstraintValidator<NotDefaultSelect, String> {
#Override
public void initialize(NotDefaultSelect constraint) {
}
#Override
public boolean isValid(String selectedValue, ConstraintValidatorContext ctx) {
if (selectedValue == null) {
return false;
}
if (selectedValue.equals("") || selectedValue.equals("0")
|| selectedValue.equalsIgnoreCase("default")
|| selectedValue.equalsIgnoreCase("please select")) {
return false;
}
return true;
}
}
My uniqueUsername validator:
package com.dating.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.beans.factory.annotation.Autowired;
import com.dating.annotation.UniqueUsername;
import com.dating.repository.UserRepository;
public class UniqueUsernameValidator implements
ConstraintValidator<UniqueUsername, String> {
#Autowired
private UserRepository userRepository;
#Override
public void initialize(UniqueUsername constraint) {
}
#Override
public boolean isValid(String username, ConstraintValidatorContext ctx) {
if (username == null || userRepository.findByUsername(username) == null) {
return true;
}
return false;
}
}
My UserRepository:
package com.dating.repository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import com.dating.domain.User;
//Spring Data JPA Marker interfaces being extended for automatic CRUD repository creation
public interface UserRepository extends CrudRepository<User, Long>, JpaSpecificationExecutor<User> {
//Automatic query creation from method name
public User findByUsername(String username);
}
Lastly my persistence-context.xml file
<!-- Data source properties -->
<util:properties id="dataSourceSettings" location="classpath:datasource.properties" />
<!-- Pooled data source using BoneCP -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"
destroy-method="close">
<property name="driverClass" value="#{dataSourceSettings['jdbc.driverClass']}" />
<property name="jdbcUrl" value="#{dataSourceSettings['jdbc.url']}" />
<property name="username" value="#{dataSourceSettings['jdbc.username']}" />
<property name="password" value="#{dataSourceSettings['jdbc.password']}" />
<property name="idleConnectionTestPeriodInMinutes" value="60" />
<property name="idleMaxAgeInMinutes" value="240" />
<property name="maxConnectionsPerPartition" value="30" />
<property name="minConnectionsPerPartition" value="10" />
<property name="partitionCount" value="3" />
<property name="acquireIncrement" value="5" />
<property name="statementsCacheSize" value="100" />
<property name="releaseHelperThreads" value="3" />
</bean>
<!-- JPA entity manager factory bean -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.dating.domain" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">#{dataSourceSettings['hibernate.dialect']}</prop>
<prop key="hibernate.hbm2ddl.auto">#{dataSourceSettings['hibernate.hbm2ddl.auto']}
</prop>
<prop key="hibernate.show_sql">#{dataSourceSettings['hibernate.show_sql']}</prop>
<prop key="hibernate.format_sql">#{dataSourceSettings['hibernate.format_sql']}</prop>
<prop key="hibernate.use_sql_comments">#{dataSourceSettings['hibernate.use_sql_comments']}
</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<context:annotation-config />
<jpa:repositories base-package="com.dating.repository"/>
Maybe the second validation is done by hibernate when you are sending your bean to the datastore. To turn it off add this to your persistence.xml:
<property name="javax.persistence.validation.mode" value="none"/>
https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/configuration.html says:
By default, Bean Validation (and Hibernate Validator) is activated. When an entity is created, updated (and optionally deleted), it is validated before being sent to the database. The database schema generated by Hibernate also reflects the constraints declared on the entity.
You can fine-tune that if needed:
AUTO: if Bean Validation is present in the classpath, CALLBACK and DDL are activated.
CALLBACK: entities are validated on creation, update and deletion. If no Bean Validation provider is present, an exception is raised at initialization time.
DDL: (not standard, see below) database schemas are entities are validated on creation, update and deletion. If no Bean Validation provider is present, an exception is raised at initialization time.
NONE: Bean Validation is not used at all
The first one is obviously done by your Spring controller because of #Valid annotation.
You can just add this property in your application.property files to disable hibernate validation spring.jpa.properties.javax.persistence.validation.mode=none
Error:
Caused by: java.lang.ClassNotFoundException: WebApplication1.SourcePackages.Domain.UserService
Here is part of the the dispatcher-servlet.xml code
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
<bean id="UserService" class="WebApplication1.SourcePackages.Domain.UserService" />
<context:component-scan base-package="WebApplication1.SourcePackages.Controller" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
And here are screenshot of the files:
UserController
package Controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import Service.UserService;
import Domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/userRegistration.htm")
#SessionAttributes("user")
public class UserController {
private UserService userService;
#Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
#RequestMapping(method = RequestMethod.GET)
public String showUserForm(ModelMap model)
{
User user = new User();
model.addAttribute(user);
return "userForm";
}
#RequestMapping(method = RequestMethod.POST)
public String onSubmit(#ModelAttribute("user") User user) {
userService.add(user);
return "UserSuccess";
}
}
User.java
package Domain;
/**
*
* #author fiona
*/
public class User {
private String name;
private String password;
private String gender;
private String country;
private String aboutYou;
private String[] community;
private Boolean mailingList;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getAboutYou() {
return aboutYou;
}
public void setAboutYou(String aboutYou) {
this.aboutYou = aboutYou;
}
public String[] getCommunity() {
return community;
}
public void setCommunity(String[] community) {
this.community = community;
}
public Boolean getMailingList() {
return mailingList;
}
public void setMailingList(Boolean mailingList) {
this.mailingList = mailingList;
}
}
UserService.java
package Service;
import Domain.User;
public class UserService {
public void add(User user) {
//Persist the user object here.
System.out.println("User added successfully");
}
}
This is occurring because you have included the folder structure "WebApplication1.SourcePackages" in the class name for the bean and in the package name for component scan.
It is not a package name. "WebApplication1" is the name of the NetBeans project. "SourcePackages" is the name of the structure which contains all Java packages and classes for the project.
In your Spring config file, you just need to provide the fully qualified class name which is the package name for the class followed by the class name.
Sample provided below
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
<bean id="userService" class="Service.UserService" />
<context:component-scan base-package="Controller" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
Please, help me fix this problem.
[RMI TCP Connection(3)-127.0.0.1] WARN
org.springframework.web.context.support.XmlWebApplicationContext -
Exception encountered during context initialization - cancelling
refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in ServletContext
resource [/WEB-INF/mvc-dispatcher-servlet.xml]: Invocation of init
method failed; nested exception is
org.hibernate.service.UnknownUnwrapTypeException: Cannot unwrap to
requested type [javax.sql.DataSource]
my mvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.springapp.mvc"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/company</property>
<property name="hibernate.connection.username">Kate</property>
<property name="hibernate.connection.password">Ant0987M#+</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="show_sql">false</property>
<mapping class="com.springapp.mvc.User"/>
</session-factory>
</hibernate-configuration>
User.java
package com.springapp.mvc;
import javax.persistence.*;
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "firstname")
private String firstName;
#Column(name = "lastname")
private String lastName;
#Column(name = "email")
private String email;
public User() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String name) {
this.firstName = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
UserController.java
package com.springapp.mvc;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#Controller
public class UserController {
#Autowired
private UserRepository userRepository;
static final Logger logger = LogManager.getLogger("MyLogger");
#RequestMapping(value = "/", method = {RequestMethod.GET, RequestMethod.HEAD})
public String listUsers(ModelMap model) {
logger.info("in meth listUsers");
logger.trace("trace in listUsers");
model.addAttribute("user", new User());
model.addAttribute("users", userRepository.findAll());
return "users";
}
#RequestMapping(value = "/add", method = {RequestMethod.POST, RequestMethod.HEAD})
public String addUser(#ModelAttribute("user") User user, BindingResult result) {
logger.info("in meth addUser");
userRepository.save(user);
return "redirect:/"/* + userRepository.getClass().getName()*/;
}
#RequestMapping("/delete/{userId}")
public String deleteUser(#PathVariable("userId") Long userId) {
logger.info("in meth deleteUser");
userRepository.delete(userRepository.findOne(userId));
return "redirect:/";
}
#RequestMapping(value = "/api/users", method = {RequestMethod.GET, RequestMethod.HEAD})
public
#ResponseBody
String listUsersJson(ModelMap model) throws JSONException {
JSONArray userArray = new JSONArray();
for (User user : userRepository.findAll()) {
JSONObject userJSON = new JSONObject();
userJSON.put("id", user.getId());
userJSON.put("firstName", user.getFirstName());
userJSON.put("lastName", user.getLastName());
userJSON.put("email", user.getEmail());
userArray.put(userJSON);
}
return userArray.toString();
}
}
UserRepository.java
package com.springapp.mvc;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.Repository;
import java.util.List;
public interface UserRepository extends Repository <User, Long> {
public <S extends User> S save(S entity);
public User findOne(Long aLong);
public List<User> findAll();
public void delete(User entity);
}
In your configuration, Remove the hibernate. from the config
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/company</property>
<property name="hibernate.connection.username">Kate</property>
<property name="hibernate.connection.password">Ant0987M#+</property>
Corrected configuration
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/company</property>
<property name="connection.username">Kate</property>
<property name="connection.password">Ant0987M#+</property>
I have an application that currently uses relational DBs but could later move on to NoSQL DBs. In this case, I am trying to build my POJOs in such a way that it could be used for both type of DBs (relational and NoSQL). I have the following entities as defined below.
Base class:
package net.breezeware.runway.idm.entity;
import java.io.Serializable;
public abstract class SpringDataUser implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
protected long id;
protected String firstName;
protected String lastName;
protected String middleInitial;
protected String email;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getMiddleInitial() {
return middleInitial;
}
public void setMiddleInitial(String middleInitial) {
this.middleInitial = middleInitial;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("User ==> ");
sb.append("id = " + id + "; ");
sb.append("suemail = " + email + "; ");
sb.append("lastname = " + lastName + "; ");
sb.append("firstname = " + firstName + "; ");
sb.append("middleInitial = " + middleInitial);
return sb.toString();
}
}
JPA class:
package net.breezeware.runway.idm.entity.jpa;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import net.breezeware.runway.idm.entity.SpringDataUser;
#XmlRootElement
#Entity
#Table(name = "spring_data_user")
public class SpringDataUserJpa extends SpringDataUser {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
#Id
public long getId() {
return id;
}
#Override
public void setId(long id) {
this.id = id;
}
#Column(name = "last_name")
#Override
public String getLastName() {
return lastName;
}
#Override
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Column(name = "email")
#Override
public String getEmail() {
return email;
}
#Override
public void setEmail(String suemail) {
this.email = suemail;
}
#Column(name = "first_name")
#Override
public String getFirstName() {
return firstName;
}
#Override
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column(name = "middle_initial")
#Override
public String getMiddleInitial() {
return middleInitial;
}
#Override
public void setMiddleInitial(String middleInitial) {
this.middleInitial = middleInitial;
}
}
Mongo Class:
package net.breezeware.runway.idm.entity.mongo;
import net.breezeware.runway.idm.entity.SpringDataUser;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "spring_data_users")
public class SpringDataUserMongo extends SpringDataUser {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public long getId() {
return id;
}
#Override
public void setId(long id) {
this.id = id;
}
#Override
public String getEmail() {
return email;
}
#Override
public void setEmail(String email) {
this.email = email;
}
#Override
public String getLastName() {
return lastName;
}
#Override
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Override
public String getFirstName() {
return firstName;
}
#Override
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Override
public String getMiddleInitial() {
return middleInitial;
}
#Override
public void setMiddleInitial(String middleInitial) {
this.middleInitial = middleInitial;
}
}
I am planning to build a DAO to access records using these entities. I would like to define a generic DAO and then extend that for different storage types as shown below.
Generic DAO:
package net.breezeware.runway.idm.dao;
import java.util.List;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
#NoRepositoryBean
public interface SpringDataUserRepository<SpringDataUser> extends PagingAndSortingRepository<SpringDataUser, Long> {
List<SpringDataUser> findByEmail(String email);
List<SpringDataUser> findByLastName(String lastName);
}
JPA DAO:
package net.breezeware.runway.idm.dao.jpa;
import net.breezeware.runway.idm.dao.SpringDataUserRepository;
import net.breezeware.runway.idm.entity.jpa.SpringDataUserJpa;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;
#Repository
#Profile("jpa")
public interface SpringDataUserJpaRepository extends SpringDataUserRepository<SpringDataUserJpa> {
}
Mongo DAO:
package net.breezeware.runway.idm.dao.mongo;
import net.breezeware.runway.idm.dao.SpringDataUserRepository;
import net.breezeware.runway.idm.entity.mongo.SpringDataUserMongo;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Repository;
#Repository
#Profile("mongo")
public interface SpringDataUserMongoRepository extends SpringDataUserRepository<SpringDataUserMongo> {
}
As you have noticed, I am trying to get help from spring-data's automatic DAO implementation generation feature as defined below.
Application Context File:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- Load all the property files required in the App. Files with prefix
'override' are used to set properties based on the environment. -->
<context:property-placeholder
location="classpath:runway.properties" />
<bean id="tejasCarestationProps"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:conf/runwayidm.properties</value>
</list>
</property>
</bean>
<context:annotation-config />
<context:component-scan base-package="net.breezeware" />
<tx:annotation-driven />
<!-- NOTE: JNDI is NOT used to set DB properties. 'jdbc/AlstomDataSource
can be set in the context.xml file Tomcat's 'conf' directory. It was done
as an exercise to see if it works! -->
<!-- <jee:jndi-lookup id="runwayDataSource" jndi-name="jdbc/AlstomDataSource"
expected-type="javax.sql.DataSource" /> -->
<bean id="runwayDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${database.driverClassName}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="runwayDataSource" />
<property name="packagesToScan">
<list>
<!-- FIXME: Having the top level & wild cards in the package
value does not work. -->
<!-- <value>net.breezeware.alstom.groupcontrol</value> -->
<value>net.breezeware</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="${hibernate.dialectClass}" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<jpa:repositories base-package="net.breezeware" entity-manager-factory-ref="entityManagerFactory"/>
<!-- ######################### Mongo DB ######################### -->
<mongo:mongo host="${mongodb.host}" port="${mongodb.port}" />
<mongo:db-factory id="mongoDbFactory" host="${mongodb.host}"
port="${mongodb.port}" dbname="${mongodb.dbname}" username="${mongodb.username}"
password="${mongodb.password}" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>
I have included the Service class that uses the DAO to access the stores:
package net.breezeware.runway.idm.service.impl;
import java.util.List;
import net.breezeware.runway.idm.dao.SpringDataUserRepository;
import net.breezeware.runway.idm.entity.SpringDataUser;
import net.breezeware.runway.idm.service.api.IdmService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
public class IdmServiceImpl implements IdmService {
#Autowired
SpringDataUserRepository<SpringDataUser> springDataUserRepository;
#Transactional
public SpringDataUser saveSpringDataUser(SpringDataUser user) {
// return springDataUserRepository.save(user);
return null;
}
#Transactional
public List<SpringDataUser> findSpringDataUsersByLastName(String lastName) {
return springDataUserRepository.findByLastName(lastName);
}
#Transactional
public List<SpringDataUser> findAllSpringDataUsers() {
return (List<SpringDataUser>) springDataUserRepository.findAll();
}
}
I have the following Application file that serves as the entry point to the App:
package net.breezeware.runway.idm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
#Configuration
#ImportResource(value = {"classpath:applicationContext.xml"})
#EnableAutoConfiguration
#ComponentScan
public class IdmApplication {
public static void main(String[] args) throws Exception {
Logger logger = LoggerFactory.getLogger(IdmApplication.class);
SpringApplication.run(IdmApplication.class, args);
logger.info("Inside main method of IdmApplication");
}
}
Here is he code I have to test the service functionality.
package net.breezeware.runway.idm;
import net.breezeware.runway.idm.entity.SpringDataUser;
import net.breezeware.runway.idm.entity.jpa.SpringDataUserJpa;
import net.breezeware.runway.idm.service.api.IdmService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;
//#ContextConfiguration({"classpath:**/applicationContext.xml"})
// #EnableAutoConfiguration
// #ComponentScan
#ActiveProfiles(profiles = {"jpa"})
// #WebAppConfiguration
#SpringApplicationConfiguration(classes = IdmApplication.class)
public class IdmServicesJpaTest extends AbstractTestNGSpringContextTests {
Logger logger = LoggerFactory.getLogger(IdmServicesJpaTest.class);
#Autowired
private IdmService idmService;
#Test
public void createSpringDataUserTest() {
logger.info("========== createSpringDataUserTest() ==========");
SpringDataUser user = new SpringDataUserJpa();
try {
user.setId(1);
user.setEmail("mark#gmail.com");
user.setFirstName("mark");
user.setLastName("adams");
user.setMiddleInitial("");
logger.info("SpringDataUser to be saved = " + user);
SpringDataUser savedUser = idmService.saveSpringDataUser(user);
logger.info("Saved User = " + savedUser);
} catch (Exception e) {
logger.info("Exception Occured = " + e);
}
}
}
I would like to use the 'Profile' feature in Spring to choose the DAO implementation in run-time. I expect the code to work, but unfortunately I have trouble getting the DAO interfaces to be autowired into Service classes. It seems like the DAO/Repository implementations for the SpringDataUserRepository is not not created by Spring-Data. Here is the error in my log file when I try to run the test.
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:70)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:109)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:111)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'idmServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: net.breezeware.runway.idm.dao.SpringDataUserRepository net.breezeware.runway.idm.service.impl.IdmServiceImpl.springDataUserRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [net.breezeware.runway.idm.dao.SpringDataUserRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:107)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
... 38 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: net.breezeware.runway.idm.dao.SpringDataUserRepository net.breezeware.runway.idm.service.impl.IdmServiceImpl.springDataUserRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [net.breezeware.runway.idm.dao.SpringDataUserRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
... 53 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [net.breezeware.runway.idm.dao.SpringDataUserRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1100)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
... 55 more
I just could not get the DAOs instantiated/autowired into the Service class. I have tried different settings like marking the base entity Object 'SpringDataUser' with #MarkedSuperclass and such, but nothing seems to work.
Please let me know if I am missing something. I have spent a considerable amount of time on StackOverflow to find an answer but could not find one that solves my problem.
Thanks in advances.
I am creating a website using Spring MVC and for persistence I am using Spring Data JPA with Hibernate 4 as my JPA provider. Validation is being handled at present with Hibernate Validator. I have a problem whereby my validators are being called twice and I can't figure out why. The main reason this is a problem is because the second time round, dependencies are not being autowired into the validator and I am getting a null pointer exception.
The following is the sequence of calls leading up to the failure:
The registration form is submitted and first the NotDefaultSectValidator is called and completes successfully for the 'whereDidYouHearAboutUs' field on the user object.
The UniqueUsernameValidator is called next and completes successfully for the 'username' field validation.
The 'addUserFromForm' method on the controller starts and finds no errors in the bindingResults object.
The 'addUser' method is then called on the UserService class. This method reaches the line 'userRepository.save(user);' but never then runs the 'print.ln' line immediate afterwards. Stepping over this line takes be back to the 'NotDefaultSectValidator' breakpoint. This completes for the second time and I re-enter the second validator 'UniqueUsernameValidator '. Here I get a null pointer exception because for some reason Spring fails to Autowire in the DAO this second time.
Can anyone shed light on why the validators are being called twice and in particular, why stepping over line 'userRepository.save(user);' goes back into these validators?
Many thanks
Here is my user.java class
package com.dating.domain;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.joda.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;
import com.dating.annotation.NotDefaultSelect;
import com.dating.annotation.UniqueUsername;
#Entity
#Table(name = "dating.user")
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username", unique = true)
#NotEmpty
#Pattern(regexp = "^[a-zA-Z0-9]*$")
#UniqueUsername
private String username;
#Column(name = "password", nullable = false)
#NotEmpty
#Size(min = 8)
private String password;
#Column(name = "first_name", nullable = false)
#NotEmpty
private String firstName;
#Column(name = "last_name", nullable = false)
#NotEmpty
private String lastName;
#Transient
private String fullName;
#Column(name = "email", nullable = false)
#NotEmpty
#Email
private String email;
#Column(name = "gender", nullable = false)
#NotEmpty
private String gender;
#Column(name = "date_of_birth", nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
#DateTimeFormat(pattern = "dd/MM/yyyy")
private LocalDate dateOfBirth;
#Column(name = "join_date", nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate joinDate;
#Column(name = "where_did_you_hear_about_us", nullable = false)
#NotDefaultSelect
private String whereDidYouHearAboutUs;
#Column(name = "enabled")
private boolean enabled;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "dating.user_roles", joinColumns = { #JoinColumn(name = "user_id", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "role_id", nullable = false, updatable = false) })
private Set<Role> roles = new HashSet<Role>();
#Column(name = "created_time", nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate createdTime;
#Column(name = "modification_time", nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate modificationTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName() {
return firstName + " " + lastName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public LocalDate getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(LocalDate dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public LocalDate getJoinDate() {
return joinDate;
}
public void setJoinDate(LocalDate joinDate) {
this.joinDate = joinDate;
}
public String getWhereDidYouHearAboutUs() {
return whereDidYouHearAboutUs;
}
public void setWhereDidYouHearAboutUs(String whereDidYouHearAboutUs) {
this.whereDidYouHearAboutUs = whereDidYouHearAboutUs;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public void addRole(Role role) {
roles.add(role);
}
public LocalDate getCreatedTime() {
return createdTime;
}
public void setCreatedTime(LocalDate createdTime) {
this.createdTime = createdTime;
}
public LocalDate getModificationTime() {
return modificationTime;
}
public void setModificationTime(LocalDate modificationTime) {
this.modificationTime = modificationTime;
}
#PreUpdate
public void preUpdate() {
modificationTime = new LocalDate();
}
#PrePersist
public void prePersist() {
LocalDate now = new LocalDate();
createdTime = now;
modificationTime = now;
}
}
The relevant method in my registration controller:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String addUserFromForm(#Valid User user,
BindingResult bindingResult, RedirectAttributes ra) {
if (bindingResult.hasErrors()) {
return "user/register";
}
userService.addUser(user);
// Redirecting to avoid duplicate submission of the form
return "redirect:/user/" + user.getUsername();
}
My service class:
package com.dating.service.impl;
import javax.transaction.Transactional;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.dating.domain.Role;
import com.dating.domain.User;
import com.dating.repository.RoleRepository;
import com.dating.repository.UserRepository;
import com.dating.repository.specification.UserSpecifications;
import com.dating.service.UserService;
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
#Transactional
#Override
public void addUser(User user) {
user.setJoinDate(new LocalDate());
user.setEnabled(true);
Role role = roleRepository.findByName(Role.MEMBER);
if (role == null) {
role = new Role();
role.setName(Role.MEMBER);
}
user.addRole(role);
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
user.setPassword(encoder.encode(user.getPassword()));
userRepository.save(user);
System.out.println("User Saved");
}
#Override
public User getUserByUsername(String username) {
return userRepository.findByUsername(username);
}
#Override
public Iterable<User> getAllUsers() {
return userRepository.findAll();
}
#Override
public void updateDetails(User user) {
userRepository.save(user);
}
#Override
public Iterable<User> lastNameIsLike(String searchTerm) {
return userRepository.findAll(UserSpecifications
.lastNameIsLike(searchTerm));
}
}
My NotDefaultSelect validator:
package com.dating.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import com.dating.annotation.NotDefaultSelect;
public class NotDefaultSelectValidator implements
ConstraintValidator<NotDefaultSelect, String> {
#Override
public void initialize(NotDefaultSelect constraint) {
}
#Override
public boolean isValid(String selectedValue, ConstraintValidatorContext ctx) {
if (selectedValue == null) {
return false;
}
if (selectedValue.equals("") || selectedValue.equals("0")
|| selectedValue.equalsIgnoreCase("default")
|| selectedValue.equalsIgnoreCase("please select")) {
return false;
}
return true;
}
}
My uniqueUsername validator:
package com.dating.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.beans.factory.annotation.Autowired;
import com.dating.annotation.UniqueUsername;
import com.dating.repository.UserRepository;
public class UniqueUsernameValidator implements
ConstraintValidator<UniqueUsername, String> {
#Autowired
private UserRepository userRepository;
#Override
public void initialize(UniqueUsername constraint) {
}
#Override
public boolean isValid(String username, ConstraintValidatorContext ctx) {
if (username == null || userRepository.findByUsername(username) == null) {
return true;
}
return false;
}
}
My UserRepository:
package com.dating.repository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import com.dating.domain.User;
//Spring Data JPA Marker interfaces being extended for automatic CRUD repository creation
public interface UserRepository extends CrudRepository<User, Long>, JpaSpecificationExecutor<User> {
//Automatic query creation from method name
public User findByUsername(String username);
}
Lastly my persistence-context.xml file
<!-- Data source properties -->
<util:properties id="dataSourceSettings" location="classpath:datasource.properties" />
<!-- Pooled data source using BoneCP -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"
destroy-method="close">
<property name="driverClass" value="#{dataSourceSettings['jdbc.driverClass']}" />
<property name="jdbcUrl" value="#{dataSourceSettings['jdbc.url']}" />
<property name="username" value="#{dataSourceSettings['jdbc.username']}" />
<property name="password" value="#{dataSourceSettings['jdbc.password']}" />
<property name="idleConnectionTestPeriodInMinutes" value="60" />
<property name="idleMaxAgeInMinutes" value="240" />
<property name="maxConnectionsPerPartition" value="30" />
<property name="minConnectionsPerPartition" value="10" />
<property name="partitionCount" value="3" />
<property name="acquireIncrement" value="5" />
<property name="statementsCacheSize" value="100" />
<property name="releaseHelperThreads" value="3" />
</bean>
<!-- JPA entity manager factory bean -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.dating.domain" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">#{dataSourceSettings['hibernate.dialect']}</prop>
<prop key="hibernate.hbm2ddl.auto">#{dataSourceSettings['hibernate.hbm2ddl.auto']}
</prop>
<prop key="hibernate.show_sql">#{dataSourceSettings['hibernate.show_sql']}</prop>
<prop key="hibernate.format_sql">#{dataSourceSettings['hibernate.format_sql']}</prop>
<prop key="hibernate.use_sql_comments">#{dataSourceSettings['hibernate.use_sql_comments']}
</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<context:annotation-config />
<jpa:repositories base-package="com.dating.repository"/>
Maybe the second validation is done by hibernate when you are sending your bean to the datastore. To turn it off add this to your persistence.xml:
<property name="javax.persistence.validation.mode" value="none"/>
https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/configuration.html says:
By default, Bean Validation (and Hibernate Validator) is activated. When an entity is created, updated (and optionally deleted), it is validated before being sent to the database. The database schema generated by Hibernate also reflects the constraints declared on the entity.
You can fine-tune that if needed:
AUTO: if Bean Validation is present in the classpath, CALLBACK and DDL are activated.
CALLBACK: entities are validated on creation, update and deletion. If no Bean Validation provider is present, an exception is raised at initialization time.
DDL: (not standard, see below) database schemas are entities are validated on creation, update and deletion. If no Bean Validation provider is present, an exception is raised at initialization time.
NONE: Bean Validation is not used at all
The first one is obviously done by your Spring controller because of #Valid annotation.
You can just add this property in your application.property files to disable hibernate validation spring.jpa.properties.javax.persistence.validation.mode=none