What is the proper way for fetching or ignoring lazy loaded objects using hibernate and spring - spring

I am using spring MVC + hibernate + jackson.
Spring version : 4.3.x
Hibernate version : 4.3.x
I want to create two API- one fetching BeanB objects as well while one not fetching BeanB object. I am using fetchtype.lazy for the same.
I have following beans:
#Entity
class BeanA
{
#Id
int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "BeanB_id")
private BeanB beanB;
//getters and setters
}
#Entity
class BeanB
{
#Id
int i;
//getters and setters
}
In my controller I have two methods: (Removing service layer to make question small. In my service layer class, I have #Transactional)
#RequestMapping(value = "/beanA/{id}" , method=RequestMethod.GET)
public ResponseEntity<BeanA> findDetailedBeanAById(#PathVariable("id") int id )
{
// to return beanA object with beanB
BeanA beanA = beanADao.findDetailedBeanAById(id);
return new ResponseEntity<BeanA>(beanA, HttpStatus.OK);
}
#RequestMapping(value = "/beanA/{id}" , method=RequestMethod.GET)
public ResponseEntity<BeanA> findNonDetailedBeanAById(#PathVariable("id") int id )
{
// to return beanA object without beanB
BeanA beanA = beanADao.findNonDetailedBeanAById(id);
return new ResponseEntity<BeanA>(beanA, HttpStatus.OK);
}
In My Dao
public BeanA findDetailedBeanAById(long id) {
BeanA beanA = (BeanA) getSession().get(BeanA.class, id);
Hibernate.initialize(beanA.getBeanB())
return beanA;
}
public BeanA findNonDetailedBeanAById(long id) {
BeanA beanA = (BeanA) getSession().get(BeanA.class, id);
return beanA;
}
When I am hitting findNonDetailedBeanAById controller method, I am getting error as :
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: could not initialize proxy - no Session
When I am hitting findNonDetailedBeanAById controller method, I am getting error as :
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)`
What changes are needed to be done?

For the detailed findBy method you can build a custom query and fetching the beanB inside of the query, like getSession().createQuery("SELECT a FROM beanA a LEFT JOIN FETCH a.beanB WHERE a.id == :id")
For the lazy findBy method I think you need to add the #Transactional(readonly=true) at the controller level, because you are trying to use the beanA after getting it with the service which was annotated as transactional. I think it tries to fetch the beanB from the database but the hibernate session might already be closed.
I was not able to tryout any of my suggestions because I'm only at phone.

Related

Spring constructor injection using java config

I have a Class that accepts the following constructor
public Student(int id, String name, Map<String, List<String>> mapInject) {
super();
this.id = id;
this.name = name;
this.mapInject = mapInject;
}
And from spring Java Config, I am injecting the constructor args like below..
#Configuration
public class JavaConfig {
#Bean
public Employee getEmployeeBean() {
Map<String,List<String>> mapInject = new HashMap<String,List<String>>();
//Add map element
return new Employee(3123,"John",mapInject);
}
}
Am i doing constructor injection here? Is this the right way to do so?
I wouldn't use Spring to handle this bean creation, unless you want ALL employees to have the same id and name which I doubt.
The power behind Spring is its Dependency Injection (DI) where you define beans for providers such as database managers, services, etc. and inject those into your components. Defining a #Bean like you have there serves no purpose as now you can only inject employees with an id of 3123 and name John.
It's important to understand that just because you are using Spring it doesn't mean EVERYTHING needs to be handled as a bean - you will always need standard POJOs for housing and passing around state (such as your Employee class) which doesn't need to have anything to do with Spring.
Down the line you might have an EmployeeService for example which houses business logic to fetch employees from a database or something, this could then be configured as a bean so it can be injected across the application.
EDIT
#Configuration
public class JavaConfig {
#Bean
#Autowired //assuming a sessionfactory been is configured elsewhere
public EmployeeService employeeService(final SessionFactory sessionfactory) {
return new EmployeeService(sessionFactory);
}
}
You could then inject this anywhere (maybe in a controller for example):
#RestController
public class EmployeeController {
private final EmployeeService employeeService;
#Autowired
public EmployeeController(final EmployeeService employeeService) {
this.employeeService = employeeService;
}
}
Where the EmployeeController doesn't need to know or care that the userService has a DB connection and doesn't need to worry about configuring it as Spring will handle all of that.

Spring: autowired service in a component is null

I have created a service:
package tn.ett.medial.service;
#Service
public class ExchangeService {
private Currency EURCurrency;
public Currency getEURCurrency() {
....
return EURCurrency;
}
and a component
package tn.ett.medial.utils.dto;
#Component
public class ProductDTO implements Serializable {
#Autowired
ExchangeService exchangeService;
public ProductDTO() {
}
public ProductDTO(Product product){
System.out.println("service****" + exchangeService);
Currency EURCurrency = exchangeService.getEURCurrency();
}
}
I added the component-scan tag in my application context
<context:component-scan base-package="tn.ett.medial" />
Why the exchangeService is null? (although it works when I inject it into a #Controller).
Since this is a DTO, I guess you do something like ProductDTO productDTO = new ProductDTO();.
So annotated #Autowired ExchangeService is null because Spring doesn't know about the copy of ProductDTO that you created with new and didn't know to autowire it.
Some more info
You run this code:
System.out.println("service****" + exchangeService);
Currency EURCurrency = exchangeService.getEURCurrency();
in a constructor, that is not autowired. No wonder it can not autowire bean, since it is not a bean itself.
The idea of IoC is that Spring Container is creating beans itself.
If you want Spring to use a specific constructor, you have to Autowire it like this:
package tn.ett.medial.utils.dto;
#Component
public class ProductDTO implements Serializable {
private final ExchangeService exchangeService;
public ProductDTO() {
}
#Autowired
public ProductDTO(Product product, ExchangeService exchangeService){
this.exchangeService = exchangeService;
System.out.println("service****" + exchangeService);
Currency EURCurrency = exchangeService.getEURCurrency();
}
}

Spring Boot JPA #Transactional #Service does not update, but #Transactional in controller does

I have a very basic Spring Boot/JPA stack app, with a controller, service layer, and repository that does not persist updates as I understand it should.
A trivial Entity:
#Entity
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
protected Customer() {}
public Customer(String name) { this.name = name; }
// standard getters,setters //
}
A trivial Repository:
#Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {}
A simple Service layer:
// If the service is #Transactional and the controller is not, the update does NOT occur
#Transactional
#Service
public class CustomerService {
private static final Logger LOG = getLogger(CustomerService.class);
#Autowired
private CustomerRepository customerRepository;
boolean updateCustomerName(Long id, String name) {
Customer customer = customerRepository.findOne(id);
if (customer == null) { return false; }
// Modifies the entity
customer.setName(name);
// No explicit save()
return true;
}
}
And a REST controller that uses it all:
// If the controller is #Transactional and the service is not, the update occurs
#RestController
#RequestMapping("/mvc")
public class CustomerController {
#Autowired
private CustomerService customerService;
#RequestMapping(path = "{id}", method = RequestMethod.PUT)
public ResponseEntity updateCustomerName(#PathVariable Long id, #RequestParam("name") String name) {
customerService.updateCustomerName(id,name);
return ResponseEntity.noContent().build();
}
}
These are wired together with a simple one-liner SpringBootApplication
I have SQL debug logs enabled and see the selects, update, etc.
With the code above: When the service method is invoked by the controller, the modified entity is not persisted. SQL logs show the select of the entity but no update.
There is also no update if nothing is marked #Transactional
However, simply by moving the #Transactional annotation from the service class to the controller class, the SQL update does occur.
If I add an explicit customerRepository.save(customer) to the service method, the update also occurs. But my understanding is that the ORM should automatically save modified persistent entities.
I'm sure the issue has something to do with the EntityManager lifecycle in the web request, but I'm puzzled. Do I need to do additional configuration?
Complete example at https://github.com/monztech/SO-41515160
EDIT: This was solved, see below. Per the Spring spec #Transactional does not work in package-private methods and mistakenly did not make the update service method public.
The update will occur if the method is public and the service class has the #Transactional annotation.
I do have another question, however. Why is the #Transactional annotation necessary? (the update does not occur without it) Shouldn't the entity manager still persist the object because of the open session in view mechanism that Spring uses, independent of any transaction?
Make your updateCustomerName method public.

spring4 beans injection in bean constructor using #Autowired

I have Class object constructor where one of parameters is Long parent_id cause object is self related as follow:
public class Folder {
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Folder parent;
}
When I try to deserialize with Gson I have to create object using Gson. Using parent_id I would like to creat new object of Folder to apply it to parent element.
When I try to do:
#Transient #Autowired public Folder folderDao;
someMethod() {
folderDao.get(9L);
}
My dao class:
#Override
public T get(Long id) {
System.out.println("_Trying to get by id...");
return (T) getCurrentSession().get(entityClass, id);
}
I got a NullPointerException
and this line is not excecuted: System.out.println("_Trying to get by id...");
I dont know why. Can anyone help me? What Am I doing wrong with Spring Injection.
By the way: My controllers have #Transactional annotation
Seems that skeletonElementDao is null.
Should you autowire the dao, not the folder?
#Autowired
private SkeletonElementDao skeletonElementDao;
instead of
#Transient #Autowired public Folder folder;

The #Transactional annotation - class level and method level in Spring

Please consider the following case in Spring (I'm working with Spring 4.0.0 GA and Hibernate 4.3.5 final).
#Service
#Transactional(readOnly = true, propagation=Propagation.REQUIRED)
public final class ChangePasswordDAO implements ChangePasswordService
{
#PersistenceContext
private EntityManager entityManager;
public void setEntityManager(EntityManager entityManager)
{
this.entityManager = entityManager;
}
#Override
#SuppressWarnings("unchecked")
public String getOldPassword(UserTable userTable)
{
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<String>criteriaQuery=criteriaBuilder.createQuery(String.class);
Root<UserTable> root = criteriaQuery.from(entityManager.getMetamodel().entity(UserTable.class));
criteriaQuery.multiselect(root.get(UserTable_.password));
criteriaQuery.where(criteriaBuilder.equal(root, userTable));
List<String> list = entityManager.createQuery(criteriaQuery).getResultList();
return list!=null&&!list.isEmpty()?list.get(0):null;
}
#Override
#SuppressWarnings("unchecked")
public boolean changePassword(String password, UserTable userTable)
{
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaUpdate<UserTable> criteriaUpdate=criteriaBuilder.createCriteriaUpdate(UserTable.class);
Root<UserTable> root = criteriaUpdate.from(entityManager.getMetamodel().entity(UserTable.class));
criteriaUpdate.set(root.get(UserTable_.password), password);
criteriaUpdate.set(root.get(UserTable_.lastModified), DateTime.now(DateTimeZone.UTC));
criteriaUpdate.where(criteriaBuilder.equal(root, userTable));
return entityManager.createQuery(criteriaUpdate).executeUpdate()>0;
}
}
In this case, I expect the following line
#Transactional(readOnly = false, propagation=Propagation.REQUIRED)
before the changePassword() method so that the class level #Transactional annotation can be overridden. Otherwise, the class level annotation uses readOnly = true is applied to this method too. Accordingly the update operation should not happen as the transaction is readonly.
How does Spring perform the update operation in this case then?
Transactional annotation has to be in the services layer, not in the DAO layer.
Each DAO method should perform an operation so it does not make sense to use it in this layer.
If several operations are needed, the various DAO methods will be invoked from a service layer method.

Resources