No session to write JSON lazy load - spring

I'm just starting with spring and hibernate. I'm trying to create some basic service using DAO.
Here is one of it:
#SuppressWarnings("unchecked")
#Override
public Users findByUserId(int id) {
List<Users> users = new ArrayList<Users>();
if(getSessionFactory() != null) {
try {
session = getSessionFactory().getCurrentSession();
users = session
.createQuery("from Users where id=?")
.setParameter(0, id)
.list();
} catch (HibernateException e) {
LOGGER.error("HibernateException: " + e);
}
}
if (!users.isEmpty()) {
return users.get(0);
} else {
return null;
}
}
And I called this service from a controller:
#RestController
public class JSONController {
#Autowired
private UserDao userDao;
#RequestMapping(value = "/rest/userbyid/{id}",
method = RequestMethod.GET,
headers = "Accept=application/json")
public Users getUserById(#PathVariable("id") int id) {
return userDao.findByUserId(id);
}
}
I understand that the session had been closed when the process come to controller. I can solve this by using openSession() method.
I just want to know is there any better way to handle this? Better still using getCurrentSession() (or any).

It's not good to return Entity to be serialized in controller. Imagine serializer which invokes all methods and even lazy collections.
For User instance it calls let's say getProjects() lazy method, then for each Project returned it agains call getUser() and so on.
Good practice is to define Service layer and return DTO (Data Transfer Object) which contains only necessary fields.
There is alternative approach to unproxy entities before return defining depth.
#SuppressWarnings("unchecked")
protected T unproxy(T entity){
if (entity == null) {
return null;
}
if (entity instanceof HibernateProxy) {
try {
Hibernate.initialize(entity);
} catch (ObjectNotFoundException e) {
return null;
}
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
return entity;
}
From
https://gist.github.com/maikelsperandio/6889130

Related

Multiple Mockito.when not working on same class

Only the first Mokcito.when is working here, resulting it to return a null, instead of the object.
Ive return two when as, there are two JPA functions being caled inside the service method.
#Test
public void testEditComplaintStatusDetail() {
long id = 1;
String status = "Investigation Complete";
EmergencyComplaint editedComplaint = new EmergencyComplaint(id, "No dogs to feed", "Investigation Complete");
when(emergencyComplaintRepository.findById(id)).thenReturn(Optional.of(emergencyComplaint));
when(emergencyComplaintRepository.save(editedComplaint)).thenReturn(editedComplaint);
assertEquals(emergencyComplaintService.editComplaintStatusDetails(status, id), editedComplaint);
}
Service
#Override
public EmergencyComplaint findComplaintDetailsById(long id) {
return emergencyComplaintDAO.findById(id);
}
#Override
public EmergencyComplaint editComplaintStatusDetails(String status, long id) {
EmergencyComplaint complaint = findComplaintDetailsById(id);
complaint.setStatus(status);
return emergencyComplaintDAO.save(complaint);
}
DAO
#Override
public EmergencyComplaint findById(long id) {
return emergencyComplaintRepository.findById(id).orElse(null);
}
#Override
public EmergencyComplaint save(EmergencyComplaint emergencyComplaint) {
return emergencyComplaintRepository.save(emergencyComplaint);
}
Update after edit:
Your mock for save() won't work if your EmergencyComplaint object does not equals to your editedComplaint object. So you have to change (or at least show) your equals function or widen your expected mocking parameters like this:
when(emergencyComplaintRepository.save(Mockito.any())).thenReturn(editedComplaint);

WebClient is not successfully invoking "POST" operation

I am playing with Spring's WebClient. The primary implementation of the REST endpoints (in DemoPOJORouter and DemoPOJOHandler) seem to work. Also, the http.Get endpoint in DemoClientRouter and DemoClientHandler seems to work.
But, the http.Post for the DemoClient implementation "does nothing". It returns success (200), but nothing gets added to the dummy repo. I have a feeling that I need to do something in DemoClient to cause the http.Post endpoint in DemoPOJOHandler to actually execute (i.e., I believe neither the statements in DemoPOJOService.add() nor DemoPOJORepo.add() are being executed).
Based on prior pratfalls in WebFlux/reactive/functional efforts, I have a feeling that I'm not successfully subscribing, and so the statements never are invoked. But, I'm having difficulty identifying the "why".
Test code follows...
DemoClient router...
#Configuration
public class DemoClientRouter {
#Bean
public RouterFunction<ServerResponse> clientRoutes(DemoClientHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/DemoClient/{id}"), requestHandler::getById)
.andRoute(RequestPredicates.POST("/DemoClient"), requestHandler::add)));
}
}
DemoClient handler...
#Component
public class DemoClientHandler {
public static final String PATH_VAR_ID = "id";
#Autowired
DemoClient demoClient;
public Mono<ServerResponse> getById(ServerRequest request) {
Mono<DemoPOJO> monoDemoPOJO;
int id;
// short-circuit if bad request or invalid value for id
id = getIdFromServerRequest(request);
if (id < 1) {
return ServerResponse.badRequest().build();
}
// non-blocking mechanism for either returning the Mono<DemoPOJO>
// or an empty response if Mono<Void> was returned by repo.getById()
return demoClient.getById(id).flatMap(demoPOJO -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Mono.just(demoPOJO), DemoPOJO.class))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> add(ServerRequest request) {
return request.bodyToMono(DemoPOJO.class).doOnSuccess( demoPOJO -> demoClient.add(demoPOJO))
.then(ServerResponse.ok().build())
.onErrorResume(e -> simpleErrorReporter(e))
.switchIfEmpty(ServerResponse.badRequest().build());
}
private int getIdFromServerRequest(ServerRequest request) {
Map<String, String> pathVariables = request.pathVariables();
int id = -1;
// short-circuit if bad request
// should never happen, but if this method is ever called directly (vice via DemoPOJORouter)
if ((pathVariables == null)
|| (!pathVariables.containsKey(PATH_VAR_ID))) {
return id;
}
try {
id = Integer.parseInt(pathVariables.get(PATH_VAR_ID));
} catch (NumberFormatException e) {
// swallow the error, return value <0 to signal error
id = -1;
}
return id;
}
private Mono<ServerResponse> simpleErrorReporter(Throwable e) {
return ServerResponse.badRequest()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(e.getMessage());
}
}
DemoClient impl...
#Component
public class DemoClient {
private final WebClient client;
public DemoClient() {
client = WebClient.create();
}
public Mono<DemoPOJO> getById(int id) {
return client.get().uri("http://localhost:8080/v2/DemoPOJO/" + id)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMap(response -> response.bodyToMono(DemoPOJO.class));
}
public Mono<Boolean> add(DemoPOJO demoPOJO) {
return client.post().uri("http://localhost:8080/v2/DemoPOJO")
.syncBody(demoPOJO)
.exchange()
.flatMap(response -> response.bodyToMono(Boolean.class));
}
}
And, the DemoPOJO stuff, starting with DemoPOJORouter...
#Configuration
public class DemoPOJORouter {
#Bean
public RouterFunction<ServerResponse> demoPOJORoute(DemoPOJOHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/DemoPOJO/{id}"), requestHandler::getById)
.andRoute(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
}
}
DemoPOJOHandler...
#Component
public class DemoPOJOHandler {
public static final String PATH_VAR_ID = "id";
#Autowired
private DemoPOJOService service;
public Mono<ServerResponse> getById(ServerRequest request) {
Mono<DemoPOJO> monoDemoPOJO;
int id;
// short-circuit if bad request or invalid value for id
id = getIdFromServerRequest(request);
if (id < 1) {
return ServerResponse.badRequest().build();
}
// non-blocking mechanism for either returning the Mono<DemoPOJO>
// or an empty response if Mono<Void> was returned by repo.getById()
return service.getById(id).flatMap(demoPOJO -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Mono.just(demoPOJO), DemoPOJO.class))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> add(ServerRequest request) {
return request.bodyToMono(DemoPOJO.class).doOnSuccess( demoPOJO -> service.add(demoPOJO))
.then(ServerResponse.ok().build())
.onErrorResume(e -> simpleErrorReporter(e))
.switchIfEmpty(ServerResponse.badRequest().build());
}
private int getIdFromServerRequest(ServerRequest request) {
Map<String, String> pathVariables = request.pathVariables();
int id = -1;
// short-circuit if bad request
// should never happen, but if this method is ever called directly (vice via DemoPOJORouter)
if ((pathVariables == null)
|| (!pathVariables.containsKey(PATH_VAR_ID))) {
return id;
}
try {
id = Integer.parseInt(pathVariables.get(PATH_VAR_ID));
} catch (NumberFormatException e) {
// swallow the exception, return illegal value to signal error
id = -1;
}
return id;
}
private Mono<ServerResponse> simpleErrorReporter(Throwable e) {
return ServerResponse.badRequest()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(e.getMessage());
}
}
DemoPOJOService...
#Component
public class DemoPOJOService {
#Autowired
private DemoPOJORepo demoPOJORepo;
public Mono<DemoPOJO> getById(int id) {
DemoPOJO demoPOJO = demoPOJORepo.getById(id);
return (demoPOJO == null) ? Mono.empty()
: Mono.just(demoPOJO);
}
public Mono<Boolean> add(DemoPOJO demoPOJO) {
return Mono.just(demoPOJORepo.add(demoPOJO));
}
}
DemoPOJORepo...
#Component
public class DemoPOJORepo {
private static final int NUM_OBJS = 5;
private static DemoPOJORepo demoRepo = null;
private Map<Integer, DemoPOJO> demoPOJOMap;
private DemoPOJORepo() {
initMap();
}
public static DemoPOJORepo getInstance() {
if (demoRepo == null) {
demoRepo = new DemoPOJORepo();
}
return demoRepo;
}
public DemoPOJO getById(int id) {
return demoPOJOMap.get(id);
}
public boolean add(DemoPOJO demoPOJO) throws InvalidParameterException {
// short-circuit on null pointer or duplicate id
if (demoPOJO == null) {
throw new InvalidParameterException("Add failed, null object detected...");
} else if (demoPOJOMap.containsKey(demoPOJO.getId())) {
throw new InvalidParameterException("Add failed, duplicate id detected...");
}
demoPOJOMap.put(demoPOJO.getId(), demoPOJO);
// if the return statement is reached, then the new demoPOJO was added
return true;
}
}
Finally, DemoPOJO...
public class DemoPOJO {
public static final String DEF_NAME = "DEFAULT NAME";
public static final int DEF_VALUE = 99;
private int id;
private String name;
private int value;
public DemoPOJO(int id) {
this(id, DEF_NAME, DEF_VALUE);
}
public DemoPOJO(#JsonProperty("id") int id, #JsonProperty("name") String name, #JsonProperty("value") int value) {
this.id = id;
this.name = name;
this.value = value;
}
/*
* setters and getters go here
*/
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(id);
builder.append(" :: ");
builder.append(name);
builder.append(" :: ");
builder.append(value);
return builder.toString();
}
}
Here is probably your problem.
DemoPOJOHandler.class
request.bodyToMono(DemoPOJO.class).doOnSuccess(demoPOJO -> service.add(demoPOJO))
DemoPOJOService.class
public Mono<Boolean> add(DemoPOJO demoPOJO) {
return Mono.just(demoPOJORepo.add(demoPOJO));
}
doOnSuccess returns Void, but you are calling a method that wraps the "action" in a returning Mono. So the demoPOJORepo#add function will never be triggered because you have broken the event chain here. The easiest fix is to just remove the wrapping Mono and return void.
public void add(DemoPOJO demoPOJO) {
demoPOJORepo.add(demoPOJO);
}
This took me way to long to find so here are some pointers when asking a question.
The names of your classes are too like each other, it was hard to follow the codeflow.
DemoPOJOService service your names are so alike so when i saw service was it the DemoPOJOService or the DemoClientService? clear names please.
There is nothing called http.POST when you wrote that i had no idea what you where talking about.
you had problems with the POST part but you posted everything, even the working GET parts, please only post code you suspect is relevant and are part of the problem.
Explain the question more clearly, what you have done, how you do it, what your application structure is and so fourth
Your endpoint urls say nothing "/DemoClient"?
How this question could have been asked to be more clear:
I have two endpoints in two routers in the same spring reactive
application.
When I do a POST request to the "/add" endpoint, this endpoint in turn
makes an a POST call using a WebClient to the same application just on
another endpoint called "/addToMap".
When this first call returns, it returns me a 200 OK status but when i
check the map (that the second endpoint is supposed to add the posted
data to) nothing gets added.
So please, next time asking a question, be clear, very clear, a lot clearer than you think. make sure your code is clear too with good variable and class names and clear url names. If you have messy names on your own computer its fine but when posting here be polite and clean up the code .It takes 5 minutes to add good names to classes and parameters so that we understand your code quicker.
take the time to read the "how to ask a good question" please.
How to ask a good question

Spring #SessionAttributes not working

My Controller class
#Controller
#SessionAttributes("basschoolsform")
public class SchoolStudentsConfirmationContrl
{
Below method accepts ac_year and gets data accordingly and redirects to page showreport
#RequestMapping(value="/SchoolStudentConfirmation.getData",method=RequestMethod.GET)
public ModelAndView BASyearWiseReport(#ModelAttribute BASSchoolsForm basschoolsform,HttpServletRequest request)
{
ModelAndView mav=new ModelAndView();
try
{
List<Object[]> result=schoolstdconfirmservice.BASyearWiseReport(request,basschoolsform);
PageHeading = "BAS Students Confirmation for the Academic Year:"+ basschoolsform.getAc_year()
if(!result.isEmpty())
{
mav.addObject("result",result);
}
else
{
mav.addObject("msg","NO Data Found");
}
mav.setViewName("showreportwithmenu");
}
catch(Exception e)
{
e.printStackTrace();
}
mav.addObject("basschoolsform",basschoolsform);
return mav;
}
This Method also uses ac_year and gets data and redirects to studentstatusedit
#RequestMapping(value="/SchoolStudentConfirmation.ConfirmStudentByDO",method=RequestMethod.GET)
public ModelAndView ConfirmStudentByDO(#ModelAttribute BASSchoolsForm basschoolsform,HttpServletRequest request)
{
ModelAndView mav=new ModelAndView();
System.out.println(basschoolsform.getAc_year()+" later value");
List<BASSchoolsForm> studentdata=schoolstdconfirmservice.ConfirmStudentByDO(basschoolsform,request);
if(studentdata != null && studentdata.size() > 0)
{
mav.addObject("PageHeading","Academic Year:"+request.getParameter("ac_year")+" School: "+request.getParameter("school"));
mav.addObject("studentdata",studentdata);
mav.addObject("schooltype",request.getParameter("school").split("-")[2]);
request.setAttribute("school",request.getParameter("school"));
}
else
{
mav.addObject("msg","All Applications are Confirmed");
mav.addObject("showyear","showyear");
}
mav.setViewName("studentstatusedit");
return mav;
}
Though I have added sessionAttribute i get ac_year as null in next method.
Please Tell me where im being wrong
First you need to initialize ModelAttribute and use the ModelAttribute name in the method parameter
#Controller
#SessionAttributes("basschoolsform")
public class SchoolStudentsConfirmationContrl
{
#ModelAttribute("basschoolsform")
public BASSchoolsForm populate(){
return new BASSchoolsForm();
}
................
public ModelAndView ConfirmStudentByDO(#ModelAttribute("basschoolsform") BASSchoolsForm basschoolsform,HttpServletRequest request)
{

Spring , Transactions , Hibernate Filters

I am using declarative transactions in Spring. I have a service layer which is annotated with "Transactional". This service layer calls the DAO. I need to enable a hibernate filter in all the dao methods. I don't want to have to explicitly call teh session.enablefilter each time. So is there a way using spring transaction aop etc such that a intercepter can be called when the hibernate session is created?
My Service layer:
#Service("customerViewService")
#Transactional
public class CustomerViewServiceImpl extends UFActiveSession implements CustomerViewService {
private static final Logger log = LoggerFactory.getLogger(CustomerViewServiceImpl.class);
private CustomerDAO daoInstance = null;
private CustomerDAO getCustomerDAO() {
if (daoInstance == null)
daoInstance = DAOFactory.getDao(CustomerDAO.class);
return daoInstance;
}
#Transactional(propagation=Propagation.REQUIRED, rollbackFor=DAOException.class)
public CustomerModel getCustomerModel() throws UFClientException {
CustomerModel model = null;
try {
Customer customerTbl = getCustomerDAO().getCustomerDetail(getUserName());
if (customerTbl == null) {
log.error("DAO-02: No entry found for Customer id- " + getUserName());
throw new UFClientException("DAO-02");
}
model = DozerConverter.hibernateToDto(customerTbl, CustomerModel.class);
}
catch (DAOException e) {
log.error("DAO-01: Not able to fetch entry from database for customer.");
throw new UFClientException();
}
return model;
}
}
My Dao Layer
public class CustomerDAOImpl extends HibernateDaoSupport implements CustomerDAO {
#SuppressWarnings("unchecked")
public Customer getCustomerDetail(String email) throws DAOException {
try {
List<Customer> customers = getHibernateTemplate().find(sb.toString(), email);
if (customers.size() == 0)
return null;
return customers.get(0);
}
catch (Exception e) {
throw new DAOException(e);
}
}
Appreciate your help!!
You can create your own interceptor, and apply it to methods that havbe transactional:
#AroundInvoke("#annotation(transactional)")
public ... handle(Transactional transactional) {
...
}

Problem using Stateful EJB in ManagedBean with RequestScope

I'm using JSF 2.0 and EJB 3.1 in the Glassfish v3 app server. And I'm facing actually the follwing problem:
In a MenagedBean with RequestScope I want to access a session object (an EJB with #Stateful) which should store some session relevant information as the seleced category, the seleced page (with a datatable paginator for each category), etc. - nothing special I think.
The first time a category is selected, the datatable is created and displayed. Allright so far.
Now, if an item (row) is clicked (to show the item's details) or if the next page should be displayed, the session (the stateful EJB) is recreated and again the default values are used to display and render the page.
The code looks like:
#ManagedBean
#RequestScoped
public class TableViewBean {
#EJB
SessionBean session;
public DataModel getTable() {
return session.getDataModel();
}
public SessionBean getSession(){
return session;
}
public void next() {
session.getPaginator().nextPage();
session.resetList();
}
public void previous() {
session.getPaginator().previousPage();
session.resetList();
}
// some other code
}
and the session EJB:
#Stateful
public class SessionBean {
private String selectedType = "Entity";
private DataModel dataModel;
private int rowsPerPage = 5;
private Paginator paginator;
public void setSelectedType(String type){
if(!type.equalsIgnoreCase(selectedType)){
selectedType = type;
updateService();
}
resetList();
}
public void resetList() {
dataModel = null;
}
public void resetPagination() {
paginator = null;
}
public int getRowsPerPage() {
return rowsPerPage;
}
public void setRowsPerPage(int rowsPerPage) {
this.rowsPerPage = rowsPerPage;
resetList();
resetPagination();
}
public Paginator getPaginator() {
if (paginator == null) {
paginator = new Paginator(rowsPerPage) {
#Override
public int getItemsCount() {
return selectedService.getCount();
}
#Override
public DataModel createPageDataModel() {
DataModel model = null;
if(selectedService != null){
model = new ListDataModel(....);
}
return model;
}
};
}
return paginator;
}
public DataModel getDataModel() {
if(dataModel == null){
dataModel = getPaginator().createPageDataModel();
}
return dataModel;
}
}
If I change the Scope of the ManagedBean to SessionScope everything works fine, but I don't like this, because of use of memory concerns.
What's wrong with my code...please help me.
Greetz, Gerry
Your RequestScoped ManagedBean is re-instantiated for each request (that's what RequestScoped means after all). Therefore, with each instantiation it gets injected with a new SFSB instance.

Resources