LazyInitializationException Spring and Hibernate - spring

I am getting this exception nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.ibm.ro.model.Location.subLocations, could not initialize proxy - no Session.
I do get that upon accessing the collection, the transaction has already been closed that's why the code is throwing this exception. Here is my sample code
#Entity
#Table(name="location")
public class Location extends BaseEntity {
private static final long serialVersionUID = 1L;
private String name;
private List<Location> subLocations;
private Location location;
#Column(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "location")
public List<Location> getSubLocations() {
return subLocations;
}
public void setSubLocations(List<Location> subLocations) {
this.subLocations = subLocations;
}
#ManyToOne(fetch = FetchType.LAZY)
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
#Override
public String toString() {
return "Location [name=" + name + ", subLocations=" + subLocations
+ "]";
}
}
Here is my DAO:
#Repository("locationDao")
public class LocationDao implements ILocationDao{
#Autowired
private SessionFactory sessionFactory;
#Override
public List<Location> getAll() {
Session sess = getSession();
return sess.createCriteria(Location.class).setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY).list();
}
}
Then here is my service :
#Service("locationService")
#Transactional
public class LocationService implements ILocationService{
#Autowired
ILocationDao dao;
#Override
public List<Location> getAll() {
return dao.getAll();
}
}
Here is the controller where the exception is being thrown:
#Controller
public class BaseController {
#Autowired
ILocationService service;
private static final String VIEW_INDEX = "index";
private final static org.slf4j.Logger logger = LoggerFactory.getLogger(BaseController.class);
#RequestMapping(value = "/", method = RequestMethod.GET)
public String location(ModelMap model) {
logger.debug(service.getAll().toString());
return VIEW_INDEX;
}
}
What can I do to fix the problem without using OpenSessionInViewFilter?

You can iterate your Location inside your service (where you still have your transaction) and call Hibernate.initialize on the elements, the force initialization of a persistent collection.
#Override
public List<Location> getAll() {
List<Location> locations = dao.getAll();
for (Location location : locations ) {
Hibernate.intialize(location.getSubLocations())
}
return locations;
}

Related

Error creating bean with name 'clienteRestController': Unsatisfied dependency expressed through field 'clientService';

Error creating bean with name 'clienteRestController': Unsatisfied dependency expressed through field 'clientService'.
Error creating bean with name 'clientServiceImpl': Unsatisfied dependency expressed through field 'clientDao'.
Error creating bean with name 'IClienteDao': Invocation of init method failed.
nested exception is java.lang.IllegalArgumentException: Not a managed type: class java.lang.Package
I am use eclipse with spring boot project with MySQL Database, when i run the project i see this error, i see some solves in stack Overflow but not worked , can any body help, thanks
#Entity
#Table(name = "package")
public class Package implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int count;
#Column(precision=18, scale=2) /** Number (16, 2) **/
private double price;
#Column(name = "createAt")
#Temporal(TemporalType.TIMESTAMP)
private Date createAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Date getCreateAt() {
return createAt;
}
public void setCreateAt(Date createAt) {
this.createAt = createAt;
}
private static final long serialVersionUID = 1L;
}
Controller "ClienteRestController":
#CrossOrigin(origins = {"http://localhost:4200"})
#RestController
#RequestMapping("/apiHorsesClub")
public class ClienteRestController {
#Autowired
private IClienteService clientService;
#GetMapping("clients")
public List<Package> index()
{
return clientService.findAll();
}
}
DAO layer "clientDao":
public interface IClienteDao extends CrudRepository<Package, Long>{
}
Service layer "IClienteService" :
public interface IClienteService {
public List<Package> findAll();
}
implementation the service "ClientServiceImpl " :
#Service
public class ClientServiceImpl implements IClienteService {
#Autowired
private IClienteDao clientDao;
#Override
#Transactional(readOnly = true)
public List<Package> findAll() {
return (List<Package>) clientDao.findAll();
}
}
Thanks all, i resolved the problem.
the problem in name of the entity "Package", its reserved in Java 😂

null values inserted while auditing

My AuditListener
public class EmployeeAuditListeners {
#PrePersist
public void prePersist(Employee employee){
perform(employee,Action.INSERTED);
}
#PreUpdate
public void preUpdate(Employee employee){
perform(employee,Action.UPDATED);
}
#PreRemove
public void preRemove(Employee employee){
perform(employee,Action.DELETED);
}
#Transactional
public void perform(Employee emp, Action action){
EntityManager em = BeanUtil.getBean(EntityManager.class);
CommonLogs commonLogs = new CommonLogs();
commonLogs.setQuery("new query");
em.persist(commonLogs);
}
}
and My Auditable.class
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
public abstract class Auditable<U> {
#CreatedBy
protected U createdBy;
#CreatedDate
#Temporal(TemporalType.TIMESTAMP)
protected Date createdDate;
#LastModifiedBy
protected U lastModifiedBy;
#LastModifiedDate
#Temporal(TemporalType.TIMESTAMP)
protected Date lastModifiedDate;
}
My CommonLogs.class
#Entity
#EntityListeners(AuditingEntityListener.class)
public class CommonLogs extends Auditable<String> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String query;
public CommonLogs() {
}
public CommonLogs(String query) {
this.query = query;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
My Employee.java class
#Entity
#EntityListeners(EmployeeAuditListeners.class)
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
and I have a simple Rest Controller
#RestController
#RequestMapping("/api")
public class EmployeeController {
#Autowired
private EmployeeRepository employeeRepository;
#PostMapping("/employees")
public Employee createEmployee(#RequestBody Employee employee){
return employeeRepository.save(employee);
}
}
I want to log it on my table (common_logs) every time i perform some crud operations on my Employee Entity.
the above given example is working to some extent as it successfully stores employee and invokes EmployeeAuditListeners.
but now while saving CommongLog entity i expect it's parent class Auditable to automatically insert createdBy, createdDate etc. for now only query and id is inserted on common_logs table and remaining columns are null.
You can review the documentation for Auditing in here.
To enable the automatic Auditing, you must add the annotation #EnableJpaAuditing in your Application class:
#SpringBootApplication
#EnableJpaAuditing
class Application {
static void main(String[] args) {
SpringApplication.run(Application.class, args)
}
}
If you want the fields #CreatedBy and #LastModifiedBy too, you will also need to implement the AuditorAware<T> interface. For example:
class SpringSecurityAuditorAware implements AuditorAware<User> {
public User getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
return ((MyUserDetails) authentication.getPrincipal()).getUser();
}
}

springboot exceptionhandling without controller class

How to handle exception handling in Spring Boot 1.5.4 without controller class? Currently, I have only entity & repository class as below.
Task.class: (entity)
#Entity
#Table(name = "task")
public class Task implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Length(min = 1)
private String name;
public Task() {
}
public Task(String name) {
this.name = name;
}
public Task(Long id, String name) {
this.name = name;
}
public long getId() {
return id;
}
public String getName(){
return name;
}
}
Repository.class:
public interface TaskRepository extends PagingAndSortingRepository<Task, Long> {
}
POST method: return 200 ok
http://localhost:8080/tasks
{
"name" : "test"
}
But,
{
"name" : ""
}
returns 500 , instead of 400 error.
Pls let me know, if any way to handle this exception without a controller class.
You could use a global #ExceptionHandler with the #ControllerAdvice annotation. Basically, you define which Exception to handle with #ExceptionHandler within the class with #ControllerAdvice annotation, and then you implement what you want to do when that exception is thrown.
Like this:
#ControllerAdvice(basePackageClasses = RepositoryRestExceptionHandler.class)
public class GlobalExceptionHandler {
#ExceptionHandler({ValidationException.class, JsonParseException.class})
public ResponseEntity<Map<String, String>> yourExceptionHandler(Exception e) {
Map<String, String> response = new HashMap<String, String>();
response.put("message", "Bad Request");
return new ResponseEntity<Map<String, String>>(response, HttpStatus.BAD_REQUEST);
}
}
See also: http://www.ekiras.com/2016/02/how-to-do-exception-handling-in-springboot-rest-application.html

ElementCollection and "failed to lazily initialize a collection of role" exception

I'm very new to Spring and I'm trying to figure out how to use #ElementCollection.
I have the following classes:
#Embeddable
public class Phone {
private String type;
private String areaCode;
#Column(name="P_NUMBER")
private String number;
public Phone() {
}
public Phone(String type, String areaCode, String number) {
super();
this.type = type;
this.areaCode = areaCode;
this.number = number;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getAreaCode() {
return areaCode;
}
public void setAreaCode(String areaCode) {
this.areaCode = areaCode;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "EMP_ID")
private long id;
#ElementCollection//(fetch=FetchType.EAGER)
#CollectionTable(name = "PHONE", joinColumns = #JoinColumn(name = "OWNER_ID"))
private List<Phone> phones = new ArrayList<Phone>();;
public Employee() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<Phone> getPhones() {
return phones;
}
public void setPhones(List<Phone> phones) {
this.phones = phones;
}
}
Repository:
#Repository
public interface EmployeeRepository extends CrudRepository<Employee, Long>{
public Employee findById(long id);
}
Then I use it in main method:
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
EmployeeRepository repository = context.getBean(EmployeeRepository.class);
Phone phone = new Phone("work", "613", "494-1234");
Employee emp = new Employee();
emp.getPhones().add(phone);
repository.save(emp);
emp = repository.findById(1);
for (Phone p : emp.getPhones()) {
System.out.println(p.getNumber());
}
context.close();
}
It throws exception (when emp.getPhones() is called): Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: elcol.repository.Employee.phones, could not initialize proxy - no Session
If I add (fetch=FetchType.EAGER) to #ElementCollection annotation(commented in the code above in Employee class) - everything is ok.
How can I fix this without FetchType.EAGER?
In findById(long id) implementation, add this Hibernate.initialize(emp.getPhones()).
Your repository service should return all the data you will need already initialized so the client that calls the service stays independent of it. In short, If you don't need employees phones on the client side, don't initialize it. If you do need it - initialize it.
EDIT
With spring data you obviously don't have the implementation, so you can specify the query which will be used, and fetch the data in the query (the question is tagged with jpa so I guess you can use JpaRepository)
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>{
#Query("SELECT e FROM Employee e JOIN FETCH e.phones WHERE e.id = (:id)")
public Employee findById(long id);
}

Spring + JPA "Lock wait timeout exceeded; try restarting transaction"

I'm new to Spring and JPA and I encountered the problem specified in the title. To simplify the problem, I have two classes: User and FeedItem. User can have more FeedItems but the relationship is bi-directional (FeedItem knows with which User it's associated). They're both persisted in the database using JPA+Hibernate:
#Entity
#Table
public class User
{
#Id
#GeneratedValue
#Column(name = "id", nullable = false, length = 8)
private int id;
#Column(nullable = false, length = 32, unique = true)
private String alias;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<FeedItem> feedItems = new ArrayList<FeedItem>();
public User()
{
}
public User(String alias)
{
this.alias = alias;
}
... getters/setters...
}
#Entity
#Table
public class FeedItem
{
#Id
#GeneratedValue
#Column(name = "id", nullable = false, length = 16)
private int id;
#Column(nullable = false, length = 64)
private String title;
#ManyToOne
#JoinColumn(name = "userId", nullable = false)
private User user;
public FeedItem()
{
}
public FeedItem(String title, User user)
{
this.title = title;
this.user = user;
}
... getters/setters...
}
The DAOs:
#Repository
public class UserJpaDao implements UserDao
{
private EntityManager em;
#Transactional
public User save(User user)
{
return this.em.merge(user);
}
#Transactional
public void delete(User user)
{
this.em.remove(user);
}
#Transactional(readOnly = true)
public User findById(int id)
{
return this.em.find(User.class, id);
}
#PersistenceContext
void setEntityManager(EntityManager entityManager)
{
this.em = entityManager;
}
}
#Repository
public class FeedItemJpaDao implements FeedItemDao
{
private EntityManager em;
#Transactional
public FeedItem save(FeedItem feedItem)
{
return this.em.merge(feedItem);
}
#Transactional
public void delete(FeedItem feedItem)
{
this.em.remove(feedItem);
}
#Transactional
public FeedItem findById(int id)
{
return this.em.find(FeedItem.class, id);
}
#PersistenceContext
void setEntityManager(EntityManager entityManager)
{
this.em = entityManager;
}
}
This is the test giving the error:
#RunWith(SpringJUnit4ClassRunner.class)
public class FeedItemJpaDaoTest
{
#Autowired
private DriverManagerDataSource dataSource;
#Autowired
private FeedItemJpaDao feedItemDao;
#Autowired
private UserJpaDao userDao;
#Before
#Transactional
public void setUp() throws Exception
{
DatabaseOperation.CLEAN_INSERT.execute(getConnection(), getDataSet());
}
#After
#Transactional
public void tearDown() throws Exception
{
DatabaseOperation.DELETE_ALL.execute(getConnection(), getDataSet());
}
#Test
#Transactional
public void testSave() throws Exception
{
User user = userDao.findById(3);
FeedItem feedItem = new FeedItem("Achievement unlocked!", user);
feedItem = feedItemDao.save(feedItem);
assertEquals(feedItem, feedItemDao.findById(feedItem.getId()));
}
private IDatabaseConnection getConnection() throws Exception
{
return new DatabaseConnection(dataSource.getConnection());
}
private IDataSet getDataSet() throws Exception
{
return new FlatXmlDataSetBuilder().build(new File("src/test/resources/dataset.xml"));
}
}
I don't understand why the error is happening -- any suggestion is appreciated!
Thank you.
EDIT: Seems like the problem is due to DbUnit: if I comment out the tearDown() method, the error doesn't occour
Solved the problem following this: http://tadaya.wordpress.com/2008/04/27/transaction-aware-datasource-use-dbunit-hibernate-in-spring/

Resources