Repository returns empty list in Spring boot - spring

I am trying to write a simple REST to pull records from a table that was shared with me. Since the table doesn't have a default ID column, I embedded a pk column to the entity object. Please find the code below for your review.
The issue I'm facing is that the repository.findByMediaType, where mediaType is one of the entity properties, returns empty list. I made sure the query param is not null and there are records in the table for the param passed. I tried findAll as well but didn't work. I can't seem to find what's wrong with the code. I am new to spring boot and would like to know the different ways I can debug this.
Service implementation class
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.hyb.enterprisedashboard.api.entity.Tenders;
import com.hyb.enterprisedashboard.api.repository.DashboardRepository;
#Service
public class DashboardServiceImpl implements DashboardService{
Logger logger = LoggerFactory.getLogger(DashboardServiceImpl.class);
#Autowired
DashboardRepository dashboardRepository;
#Override
public List<Tenders> getTenderByMediaType(String mediaType) {
List<Tenders> tenderList = dashboardRepository.findAll();
//findByMediaType(mediaType);
tenderList.stream().forEach(tender -> {
logger.info("Order {} paid via {}",tender.getId().getOrderNumber(), tender.getMediaType());
});
return tenderList;
}
}
Entity class
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
#Entity
#Table(name = "TENDERS")
public class Tenders {
/** The id. */
#EmbeddedId
private TendersPK id;
/** The dateTime. */
#Column(name="DATE_TIME")
private Date dateTime;
/** The tenderMedia. */
#Column(name="TENDERED_MEDIA")
private String tenderMedia;
/** The mediaType. */
#Column(name="MEDIA_TYPE")
private String mediaType;
/** The tenderAmount. */
#Column(name="TENDERED_AMOUNT")
private BigDecimal tenderAmount;
/**
* #return the id
*/
public TendersPK getId() {
return id;
}
/**
* #param id the id to set
*/
public void setId(TendersPK id) {
this.id = id;
}
/**
* #return the dateTime
*/
public Date getDateTime() {
return dateTime;
}
/**
* #param dateTime the dateTime to set
*/
public void setDateTime(Date dateTime) {
this.dateTime = dateTime;
}
/**
* #return the tenderMedia
*/
public String getTenderMedia() {
return tenderMedia;
}
/**
* #param tenderMedia the tenderMedia to set
*/
public void setTenderMedia(String tenderMedia) {
this.tenderMedia = tenderMedia;
}
/**
* #return the mediaType
*/
public String getMediaType() {
return mediaType;
}
/**
* #param mediaType the mediaType to set
*/
public void setMediaType(String mediaType) {
this.mediaType = mediaType;
}
/**
* #return the tenderAmount
*/
public BigDecimal getTenderAmount() {
return tenderAmount;
}
/**
* #param tenderAmount the tenderAmount to set
*/
public void setTenderAmount(BigDecimal tenderAmount) {
this.tenderAmount = tenderAmount;
}
#Override
public String toString() {
return "Tenders [id=" + id + ", dateTime=" + dateTime + ", tenderMedia=" + tenderMedia + ", mediaType="
+ mediaType + ", tenderAmount=" + tenderAmount + "]";
}
}
PK Embedded class
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
#Embeddable
public class TendersPK implements Serializable{
/** The Constant serialVersionUID.*/
private static final long serialVersionUID = 1L;
/**
*
*/
public TendersPK() {
}
/**
* #param storeNumber
* #param orderNumber
*/
public TendersPK(long storeNumber, long orderNumber) {
super();
this.storeNumber = storeNumber;
this.orderNumber = orderNumber;
}
#Column(name = "STORE_NUMBER")
private long storeNumber;
#Column(name = "ORDER_NUMBER")
private long orderNumber;
/**
* #return the storeNumber
*/
public long getStoreNumber() {
return storeNumber;
}
/**
* #param storeNumber the storeNumber to set
*/
public void setStoreNumber(long storeNumber) {
this.storeNumber = storeNumber;
}
/**
* #return the orderNumber
*/
public long getOrderNumber() {
return orderNumber;
}
/**
* #param orderNumber the orderNumber to set
*/
public void setOrderNumber(long orderNumber) {
this.orderNumber = orderNumber;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (orderNumber ^ (orderNumber >>> 32));
result = prime * result + (int) (storeNumber ^ (storeNumber >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof TendersPK))
return false;
TendersPK other = (TendersPK) obj;
if (orderNumber != other.orderNumber)
return false;
if (storeNumber != other.storeNumber)
return false;
return true;
}
#Override
public String toString() {
return "TendersPK [storeNumber=" + storeNumber + ", orderNumber=" + orderNumber + "]";
}
}
Repository class
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.hyb.enterprisedashboard.api.entity.Tenders;
import com.hyb.enterprisedashboard.api.entity.TendersPK;
#Repository
public interface DashboardRepository extends JpaRepository<Tenders, TendersPK>{
#Query("select t from Tenders t where t.mediaType = ?1")
List<Tenders> findByMediaType(String mediaType);
}
And I see the below query passed in the console
Hibernate: select tenders0_.order_number as order_number1_0_, tenders0_.store_number as store_number2_0_, tenders0_.date_time as date_time3_0_, tenders0_.media_type as media_type4_0_, tenders0_.tendered_amount as tendered_amount5_0_, tenders0_.tendered_media as tendered_media6_0_ from tenders tenders0_
Could anyone please help to find the cause?

This was happening to me and it turns out my spring.datasource.* properties were not being set. I had them in the wrong file and the were not being read.
I would think that my repository query would error out if I had not provided datasource url, username, and password - instead I would simply just get an empty list returned.
I ended up figuring out that I was not pulling my datasource credentials by adding this in my RestController:
#Value("${spring.datasource.username}")
String username;
Then I just printed username to the system.out.println. When starting the application I would get an error that spring.datasource.username was undefined. Hence I knew I was not loading datasource information that I thought I was.

Related

Spring Boot multiple data source with SpringPhysicalNamingStrategy

Require Spring boot application with multiple data source configured.
Multiple data source configuration is working with separate datasource, entityManager and transactionManager.
Also hibernate naming configuration is working with single data source with below configuration.
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
The above configuration can be provided with JPA properties to entityManager. But not able to add dynamic table name (from application.properties) in SpringPhysicalNamingStrategy.
I have created a custom physical naming strategy. It can change names with environment variables. Also, it can change column names too. Name identifier will be decided by the database catalog name. You can change selection criteria with using jdbcEnvironment. If you put any criteria option text will be the property value.
Application Properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.naming.physical-strategy=com.example.demo.DynamicPhysicalNamingStrategy
# dynamic
user.table.name=TESTDB:TestUser,TESTDB2:TestUser2
user.column.name=username
User Entity
#Table(name = "${user.table.name}")
#Entity
#Data
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "${user.column.name}")
private String name;
private String email;
}
DynamicPhysicalNamingStrategy
package com.example.demo;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* It is copied from {#link org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl}
*/
#Component
public class DynamicPhysicalNamingStrategy implements PhysicalNamingStrategy, ApplicationContextAware {
private final Pattern VALUE_PATTERN = Pattern.compile("^\\$\\{([\\w.]+)}$");
private Environment environment;
#Override
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
#Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
#Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
#Override
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
#Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
private Identifier apply(Identifier name, JdbcEnvironment jdbcEnvironment) {
if (name == null) {
return null;
}
// Custom Implementation Start
String text = name.getText();
Matcher matcher = VALUE_PATTERN.matcher(text);
if (matcher.matches()) {
String propertyKey = matcher.group(1);
text = environment.getProperty(propertyKey);
Assert.notNull(text, "Property is not found '" + propertyKey + "'");
// extract catalog selection part
// Example:
// Current Catalog: TESTDB
// Property: TESTDB:TestUser, TESTDB2:TestUser
// Text will be TestUser
Pattern catalogPattern = Pattern.compile(jdbcEnvironment.getCurrentCatalog().getText() + ":([^,]+)");
Matcher catalogMatcher = catalogPattern.matcher(text);
if (catalogMatcher.find()) {
text = catalogMatcher.group(1);
}
// Caution: You can remove below return function, if so text will be transformed with spring advice
return getIdentifier(text, name.isQuoted(), jdbcEnvironment);
}
// Custom Implementation End
StringBuilder builder = new StringBuilder(text.replace('.', '_'));
for (int i = 1; i < builder.length() - 1; i++) {
if (isUnderscoreRequired(builder.charAt(i - 1), builder.charAt(i), builder.charAt(i + 1))) {
builder.insert(i++, '_');
}
}
return getIdentifier(builder.toString(), name.isQuoted(), jdbcEnvironment);
}
/**
* Get an identifier for the specified details. By default this method will return an
* identifier with the name adapted based on the result of
* {#link #isCaseInsensitive(JdbcEnvironment)}
*
* #param name the name of the identifier
* #param quoted if the identifier is quoted
* #param jdbcEnvironment the JDBC environment
* #return an identifier instance
*/
protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
if (isCaseInsensitive(jdbcEnvironment)) {
name = name.toLowerCase(Locale.ROOT);
}
return new Identifier(name, quoted);
}
/**
* Specify whether the database is case sensitive.
*
* #param jdbcEnvironment the JDBC environment which can be used to determine case
* #return true if the database is case insensitive sensitivity
*/
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return true;
}
private boolean isUnderscoreRequired(char before, char current, char after) {
return Character.isLowerCase(before) && Character.isUpperCase(current) && Character.isLowerCase(after);
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
environment = applicationContext.getBean(Environment.class);
}
}
Test
package com.example.demo;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
#SpringBootTest
class DemoApplicationTests {
#Autowired
private UserRepository userRepository;
#Test
void contextLoads() {
User user = new User();
user.setName("test");
user.setEmail("test#test.com");
userRepository.save(user);
userRepository.findAll();
}
}
Hibernate: call next value for hibernate_sequence
Hibernate: insert into testuser (email, username, id) values (?, ?, ?)
Hibernate: select user0_.id as id1_0_, user0_.email as email2_0_, user0_.username as username3_0_ from testuser user0_

gson.toJson() throws StackOverflowError and I dont have a circular dependency

I am trying to generate a JSON
Gson gson = new Gson();
String json = gson.toJson(item);
But every time i try to I keep getting a stackoverflow error:
java.lang.StackOverflowError: null
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:968)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:968)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
It is caused when i try to convert DataTableResults class which contains a list of Transactions.class as its property field to a string.
The DataTableResult class looks like this :
public class DataTableResults<T> {
/** The draw. */
private String draw;
/** The records filtered. */
private String recordsFiltered;
/** The records total. */
private String recordsTotal;
/** The list of data objects. */
#SerializedName("data")
List<T> listOfDataObjects;
/**
* Gets the draw.
*
* #return the draw
*/
public String getDraw() {
return draw;
}
/**
* Sets the draw.
*
* #param draw the draw to set
*/
public void setDraw(String draw) {
this.draw = draw;
}
/**
* Gets the records filtered.
*
* #return the recordsFiltered
*/
public String getRecordsFiltered() {
return recordsFiltered;
}
/**
* Sets the records filtered.
*
* #param recordsFiltered the recordsFiltered to set
*/
public void setRecordsFiltered(String recordsFiltered) {
this.recordsFiltered = recordsFiltered;
}
/**
* Gets the records total.
*
* #return the recordsTotal
*/
public String getRecordsTotal() {
return recordsTotal;
}
/**
* Sets the records total.
*
* #param recordsTotal the recordsTotal to set
*/
public void setRecordsTotal(String recordsTotal) {
this.recordsTotal = recordsTotal;
}
/**
* Gets the list of data objects.
*
* #return the listOfDataObjects
*/
public List<T> getListOfDataObjects() {
return listOfDataObjects;
}
/**
* Sets the list of data objects.
*
* #param listOfDataObjects the listOfDataObjects to set
*/
public void setListOfDataObjects(List<T> listOfDataObjects) {
this.listOfDataObjects = listOfDataObjects;
}
}
while the Transactions.class looks like this
#Entity
#Table(name = "TRANS")
public class Transactions extends DefaultEntity {
public enum TRANSACTIONTYPE{WITHDRAW, DEPOSIT, WIN, LOSS}
#ManyToOne(targetEntity = User.class)
#JoinColumn(name="player")
private User player;
private double amount;
#Enumerated(EnumType.STRING)
private TRANSACTIONTYPE transactiontype;
private String referenceID;
private String detail;
private String token;
public TRANSACTIONTYPE getTransactiontype() {
return transactiontype;
}
public Transactions setTransactiontype(TRANSACTIONTYPE transactiontype) {
this.transactiontype = transactiontype;
return this;
}
public double getAmount() {
return amount;
}
public Transactions setAmount(double amount) {
this.amount = amount;
return this;
}
public String getReferenceID() {
return referenceID;
}
public Transactions setReferenceID(String referenceID) {
this.referenceID = referenceID;
return this;
}
public String getDetail() {
return detail;
}
public Transactions setDetail(String detail) {
this.detail = detail;
return this;
}
public String getToken() {
return token;
}
public Transactions setToken(String token) {
this.token = token;
return this;
}
public User getPlayer() {
return player;
}
public Transactions setPlayer(User player) {
this.player = player;
return this;
}
}
according to this post, it is supposed to be caused by a circular dependency, but in my case it is not cause i dont have one. What else could cause such error ?
You should remove extends DefaultEntity, you don't need it and may bring circular dependency.
Also you have a #ManyToOne relationship with User, that may cause circular dependency if User also have a reference to Transactions.
If you have it in both parts, you should exclude it from serialization with transient on one part at least.

methods in an ejb session bean for an entity dont work in a spring MVC project

I created a maven entreprise application project, in the ejb module i put my entities in a package and i generated my session beans in an other package and i deployed my ejb module in glassfish,in the web module i added dependencies of spring and I created a controller that search the session bean and call the methode find all() but it doesnt get my objects stored in database, what should i do?
Category entity
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.entities;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
/**
*
* #author DELL
*/
#Entity
#Table(name = "categorie")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Categorie.findAll", query = "SELECT c FROM Categorie c"),
#NamedQuery(name = "Categorie.findByIdCategorie", query = "SELECT c FROM Categorie c WHERE c.idCategorie = :idCategorie"),
#NamedQuery(name = "Categorie.findByDescription", query = "SELECT c FROM Categorie c WHERE c.description = :description"),
#NamedQuery(name = "Categorie.findByName", query = "SELECT c FROM Categorie c WHERE c.name = :name"),
#NamedQuery(name = "Categorie.findByNomPhoto", query = "SELECT c FROM Categorie c WHERE c.nomPhoto = :nomPhoto")})
public class Categorie implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idCategorie")
private Integer idCategorie;
#Size(max = 255)
#Column(name = "description")
private String description;
#Size(max = 20)
#Column(name = "name")
private String name;
#Size(max = 255)
#Column(name = "nomPhoto")
private String nomPhoto;
#Lob
#Column(name = "photo")
private byte[] photo;
#OneToMany(mappedBy = "idCategorie")
private List<Produit> produitList;
public Categorie() {
}
public Categorie(Integer idCategorie) {
this.idCategorie = idCategorie;
}
public Integer getIdCategorie() {
return idCategorie;
}
public void setIdCategorie(Integer idCategorie) {
this.idCategorie = idCategorie;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNomPhoto() {
return nomPhoto;
}
public void setNomPhoto(String nomPhoto) {
this.nomPhoto = nomPhoto;
}
public byte[] getPhoto() {
return photo;
}
public void setPhoto(byte[] photo) {
this.photo = photo;
}
#XmlTransient
public List<Produit> getProduitList() {
return produitList;
}
public void setProduitList(List<Produit> produitList) {
this.produitList = produitList;
}
#Override
public int hashCode() {
int hash = 0;
hash += (idCategorie != null ? idCategorie.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Categorie)) {
return false;
}
Categorie other = (Categorie) object;
if ((this.idCategorie == null && other.idCategorie != null) || (this.idCategorie != null && !this.idCategorie.equals(other.idCategorie))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.mycompany.entities.Categorie[ idCategorie=" + idCategorie + " ]";
}
}
AbstractFacade
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.dao;
import java.util.List;
import javax.persistence.EntityManager;
/**
*
* #author DELL
*/
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
public List<T> findRange(int[] range) {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
javax.persistence.Query q = getEntityManager().createQuery(cq);
q.setMaxResults(range[1] - range[0] + 1);
q.setFirstResult(range[0]);
return q.getResultList();
}
public int count() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
javax.persistence.Query q = getEntityManager().createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}
CategorieFacade
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.dao;
import com.mycompany.entities.Categorie;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
/**
*
* #author DELL
*/
#Stateless
public class CategorieFacade extends AbstractFacade<Categorie> implements CategorieFacadeLocal {
#PersistenceContext(unitName = "com.mycompany_ProjetCommerce-ejb_ejb_1.0-SNAPSHOTPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public CategorieFacade() {
super(Categorie.class);
}
}
CategorieFacadeLocal
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.dao;
import com.mycompany.entities.Categorie;
import java.util.List;
import javax.ejb.Local;
/**
*
* #author DELL
*/
#Local
public interface CategorieFacadeLocal {
void create(Categorie categorie);
void edit(Categorie categorie);
void remove(Categorie categorie);
Categorie find(Object id);
List<Categorie> findAll();
List<Categorie> findRange(int[] range);
int count();
}
CategorieController
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.controlleur;
import com.mycompany.dao.CategorieFacadeLocal;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.springframework.stereotype.*;
import org.springframework.ui.*;
import org.springframework.web.bind.annotation.*;
#Controller
#RequestMapping("categorie")
public class CategorieController {
CategorieFacadeLocal categorieFacade = lookupCategorieFacadeLocal();
#RequestMapping(method = RequestMethod.GET)
public String index(ModelMap modelmap){
modelmap.put("listeCategorie", categorieFacade.findAll());
return "index";
}
private CategorieFacadeLocal lookupCategorieFacadeLocal() {
try {
Context c = new InitialContext();
return (CategorieFacadeLocal) c.lookup("java:global/com.mycompany_ProjetCommerce-ear_ear_1.0-SNAPSHOT/com.mycompany_ProjetCommerce-ejb_ejb_1.0-SNAPSHOT/CategorieFacade!com.mycompany.dao.CategorieFacadeLocal");
} catch (NamingException ne) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
throw new RuntimeException(ne);
}
}
}

#ManyToMany spring-mvc, spring-data-jpa, update error - failed to lazily initialize a collection of role

Very well-known exception "failed to lazily initialize a collection of role". I read many blogs, many suggestions but they did not work for my case.
Can anybody help me to understand how to resolve my issue ?
All these work in WAR spring-webmvc (JSP view).
I have entities Person and Address. 1 Person can have many Addresses, at 1 Address can live many persons (family). Look :
package abc.def.data.model;
import java.io.Serializable;
import java.util.Collections;
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.Table;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
/**
*/
#Entity
#Table( name = "PERSON" )
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
/*
* ID of person.
*/
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private long id;
/*
* email and used as login of person.
*/
#Column( name = "email", length = 128, nullable = false, unique = true )
private String email;
/*
* Fullname of person.
*/
#Column( name = "fullname", length = 128, nullable = true )
private String fullName;
/*
* Person`s password. It is stored as encrypted value. Nobody know this value except person. There used
* Spring encryption mechanism. Look at the
*/
#Column( name = "password", length = 128, nullable = false )
private String password;
/*
*
*/
#Column( name = "role", length = 16, nullable = false )
private String role;
#Column( name = "timezone", nullable = false )
private int timezone;
#Column( name = "created", nullable = false )
#Type( type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime" )
private DateTime created;
#Column( name = "updated", nullable = false )
#Type( type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime" )
private DateTime updated;
#Column( name = "isenabled", nullable = false )
#Type( type = "true_false" )
private boolean enabled;
/*
* Addresses of person. One person can has many addresses. In that time many persons can live in one
* address (family).
*/
#ManyToMany( fetch = FetchType.LAZY, cascade = {CascadeType.ALL} )
#JoinTable( name = "PERSON_ADDRESS", joinColumns = {#JoinColumn( name = "personid",
referencedColumnName = "id" )}, inverseJoinColumns = {#JoinColumn( name = "addressid",
referencedColumnName = "id" )} )
private Set<Address> addresses = new HashSet<Address>(0);
/**
* closed Contructor. Need for JPA.
*/
protected Person() {
}
/**
* Public Contructor.
*
* #param fullName
* #param email
* #param role
* #param timezone
* #param created
* #param udated
*/
public Person( String fullName, String email, String password, String role, int timezone,
DateTime created, DateTime udated, boolean enabled ) {
this.fullName = fullName;
this.email = email;
this.password = password;
this.role = role;
this.timezone = timezone;
this.created = created;
updated = udated;
this.enabled = enabled;
}
/**
* Public Contructor without enabled status field. By default user is DISABLED here.
*
* #param fullName
* #param email
* #param role
* #param timezone
* #param created
* #param udated
*/
public Person( String fullName, String email, String password, String role, int timezone,
DateTime created, DateTime udated ) {
this.fullName = fullName;
this.email = email;
this.password = password;
this.role = role;
this.timezone = timezone;
this.created = created;
updated = udated;
this.enabled = false;
}
/*
* (non-Javadoc)
* #see java.lang.Object#toString()
*/
#Override
public String toString() {
return String.format(
"Person [id=%s, fullName=%s, email=%s, password=%s, role=%s, timezone=%s, created=%s,"
+ " updated=%s, enabled=%s, {address}]", id, fullName, email, password, role,
timezone, created, updated, enabled );
}
/**
* Getter.
*
* #return the id
*/
public long getId() {
return id;
}
/**
* Getter.
*
* #return the fullName
*/
public String getFullName() {
return fullName;
}
/**
* Getter.
*
* #return the email
*/
public String getEmail() {
return email;
}
/**
* Getter.
*
* #return the password
*/
public String getPassword() {
return password;
}
/**
* Getter.
*
* #return the role
*/
public String getRole() {
return role;
}
/**
* Getter.
*
* #return the timezone
*/
public int getTimezone() {
return timezone;
}
/**
* Getter.
*
* #return the created
*/
public DateTime getCreated() {
return new DateTime( created, DateTimeZone.forOffsetMillis( this.timezone ) );
}
/**
* Getter.
*
* #return the updated
*/
public DateTime getUpdated() {
return new DateTime( updated, DateTimeZone.forOffsetMillis( this.timezone ) );
}
/**
* Getter.
*
* #return the enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* Getter.
*
* #return the addressCollection
*/
public Set<Address> getAddresses() {
//force clients through our add and remove methods
return Collections.unmodifiableSet( addresses );
}
public void addAddress( Address address ) {
//avoid circular calls : assumes equals and hashcode implemented
if ( !addresses.contains( address ) ) {
addresses.add( address );
//add method to Product : sets 'other side' of association
address.addPerson( this );
}
}
public void removeAddress( Address address ) {
//avoid circular calls : assumes equals and hashcode implemented
if ( !addresses.contains( address ) ) {
addresses.remove( address );
//add method to Product : sets 'other side' of association
address.removePerson( this );
}
}
/**
* Setter.
*
* #param id
* the id to set
*/
public void setId( long id ) {
this.id = id;
}
/**
* Setter.
*
* #param fullName
* the fullName to set
*/
public void setFullName( String fullName ) {
this.fullName = fullName;
}
/**
* Setter.
*
* #param email
* the email to set
*/
public void setEmail( String email ) {
this.email = email;
}
/**
* Setter.
*
* #param password
* the password to set
*/
public void setPassword( String password ) {
this.password = password;
}
/**
* Setter.
*
* #param role
* the role to set
*/
public void setRole( String role ) {
this.role = role;
}
/**
* Setter.
*
* #param timezone
* the timezone to set
*/
public void setTimezone( int timezone ) {
this.timezone = timezone;
}
/**
* Setter.
*
* #param created
* the created to set
*/
public void setCreated( DateTime created ) {
this.created = created;
}
/**
* Setter.
*
* #param updated
* the updated to set
*/
public void setUpdated( DateTime updated ) {
this.updated = updated;
}
/**
* Setter.
*
* #param enabled
* the enabled to set
*/
public void setEnabled( boolean enabled ) {
this.enabled = enabled;
}
/**
* Setter.
*
* #param addressCollection
* the addressCollection to set
*/
public void setAddresses( Set<Address> addressCollection ) {
this.addresses = addressCollection;
}
/*
* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) ( id ^ ( id >>> 32 ) );
return result;
}
/*
* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals( Object obj ) {
if ( this == obj ) return true;
if ( obj == null ) return false;
if ( getClass() != obj.getClass() ) return false;
Person other = (Person) obj;
if ( id != other.id ) return false;
return true;
}
}
Address :
package abc.def.data.model;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
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.ManyToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
/**
* Addresses of person. <br />
* One person can has many addresses. In that time many persons can live in one address (family).
*
*/
#Entity
#Table( name = "ADDRESS", uniqueConstraints = {#UniqueConstraint( columnNames = {"country", "city", "street",
"housenum"} )}, indexes = {} )
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
/*
* Address ID.
*/
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private long id;
/*
* Name of country.
*/
#Column( length = 128 )
private String country;
/*
* Name of city.
*/
#Column( length = 64 )
private String city;
/*
* Name of street.
*/
#Column( length = 64 )
private String street;
/*
* Number of house.
*/
#Column( name = "housenum" )
private Integer houseNumber;
/*
* Users who live at this Address.
*/
#ManyToMany( fetch = FetchType.LAZY, mappedBy = "addresses" )
public Set<Person> persons = new HashSet<Person>( 0 );
/**
* Getter.
*
* #return the id
*/
public long getId() {
return id;
}
/**
* Getter.
*
* #return the country
*/
public String getCountry() {
return country;
}
/**
* Getter.
*
* #return the city
*/
public String getCity() {
return city;
}
/**
* Getter.
*
* #return the street
*/
public String getStreet() {
return street;
}
/**
* Getter.
*
* #return the houseNumber
*/
public Integer getHouseNumber() {
return houseNumber;
}
/**
* Getter.
*
* #return the personCollection
*/
public Set<Person> getPersons() {
return Collections.unmodifiableSet( persons );
}
/**
* Setter.
*
* #param id
* the id to set
*/
public void setId( long id ) {
this.id = id;
}
/**
* Setter.
*
* #param country
* the country to set
*/
public void setCountry( String country ) {
this.country = country;
}
/**
* Setter.
*
* #param city
* the city to set
*/
public void setCity( String city ) {
this.city = city;
}
/**
* Setter.
*
* #param street
* the street to set
*/
public void setStreet( String street ) {
this.street = street;
}
/**
* Setter.
*
* #param houseNumber
* the houseNumber to set
*/
public void setHouseNumber( Integer houseNumber ) {
this.houseNumber = houseNumber;
}
/**
* Setter.
*
* #param personCollection
* the personCollection to set
*/
public void setPersons( Set<Person> personCollection ) {
this.persons = personCollection;
}
/*
* (non-Javadoc)
* #see java.lang.Object#toString()
*/
#Override
public String toString() {
return String.format( "Address [id=%s, country=%s, city=%s, street=%s, houseNumber=%s, {person}]",
id, country, city, street, houseNumber );
}
/**
*
*/
public void addPerson( Person person ) {
//assumes equals and hashcode implemented: avoid circular calls
if ( !persons.contains( person ) ) {
persons.add( person );
//add method to Product : sets 'other side' of association
person.addAddress( this );
}
}
/**
*
*/
public void removePerson( Person person ) {
//assumes equals and hashcode implemented: avoid circular calls
if ( !persons.contains( person ) ) {
persons.remove( person );
}
//add method to Product : sets 'other side' of association
person.removeAddress( this );
}
/*
* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) ( id ^ ( id >>> 32 ) );
return result;
}
/*
* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals( Object obj ) {
if ( this == obj ) return true;
if ( obj == null ) return false;
if ( getClass() != obj.getClass() ) return false;
Address other = (Address) obj;
if ( id != other.id ) return false;
return true;
}
}
In case New registration and new person and new address - no problem. It passed find.
In PersonService #Service I have :
// create new Person
Person newPerson = new Person( fullName, email, password, role, timezone, created, udated, true );
// add addresses - it is possible have more 1 address in registration
newPerson.setAddresses( (Set<Address>) addrList );
try {
newPerson = personRepository.save( newPerson );
} catch (Exception e) {
actionResult.setError( true );
actionResult.addErrorItem( "error", e.getMessage() );
}
LOG.debug( "Created new person : {}", newPerson.toString() );
actionResult.setObject( newPerson );
return actionResult;
/*
* Check given addresses for existing.
*/
private Collection<Address> checkAddresses( Set<Address> addrList, Person newPerson ) {
Set<Address> newAddresses = new HashSet<Address>();
Address addr = null;
for (Address address : addrList) {
addr =
addressRepository.findByCountryAndCityAndStreetAndHouseNumber( address.getCountry(), address.getCity(), address.getStreet(), address.getHouseNumber() );
if ( addr != null ) {
addr.getPersons().size();
}
addr = addr == null ? address : addr;
newAddresses.add( addr );
LOG.debug( "checked address {}", addr.toString() );
}
return newAddresses;
}
personRepository :
public interface PersonRepository extends JpaRepository<Person, Long> {
}
In case new user enter existing address - it checks (found) in DB. When it found it have to be added to newPerson() . In this case exception arise.
I tried use address.getPerson().size - also exception .
Also I do not want use EAGER. is It possible ?
If you don't have an active transaction or open thread-bound EntityManager, Spring Data JPA will create a new EntityManager for each call on a repository. Then it closes the EntityManager before returning, leading to the exception you're getting when Hibernate tries to lazy-load.
There are two ways to deal with this. One is to use transactions, possibly by applying #Transactional as appropriate. The other is to use OpenEntityManagerInViewFilter, which will create a thread-bound EntityManager at the beginning of each request and hold it open for the entire request. In this case I think a transaction is called for because you're doing an INSERT that depends on previous SELECTs. OpenEntityManagerInViewFilter is very handy for using lazy-loaded collections in views, but it doesn't provide any transaction management.

JSF 2 managed bean is being shared across mulitple users logged in different window

I am using JSF2, Spring 3 and Mybatis. On user login, I am doing authentication from ConfigAutomationLoginBean.java which has other beans as its Managed properties. The problem is that my beans are being shared across multiple users in different browser window. All my beans are SessionScoped and if I don't keep it that way, I may not get navigation screen after login. I guess JSF creates all managed bean with SessionScoped attribute by default singleton. Would it be good idean if I make the initial bean authentication bean ie. ConfigAutomationLoginBean and other beans autorwired to it using Spring 3 and remove the JSF for intial bean loading? Below is my login code:
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.telus.routerconfigurationtool.dto.UserProfileDTO;
import com.telus.routerconfigurationtool.service.UserManagementService;
import com.telus.routerconfigurationtool.util.CommonUtil;
#Component
#ManagedBean(name = "configAutomationLoginBean")
#SessionScoped
public class ConfigAutomationLoginBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(ConfigAutomationLoginBean.class);
private String id;
private String password;
private String role;
#ManagedProperty(value = "#{userManagementService}")
private UserManagementService userManagementService;
#ManagedProperty(value = "#{treeNavigationBean}")
private TreeNavigationBean treeNavigationBean;
#ManagedProperty(value = "#{breadCrumbBean}")
private BreadCrumbBean breadCrumbBean;
public String authenticateUser() {
/** Reset and Update BreadCrumb - Add Nodes for Create User **/
breadCrumbBean.resetBreadCrumbModel();
Boolean authenticUser = false;
//TODO logic to authenticate user. authenticUser set true if authentication
//TODO Temporary setting to true
authenticUser = true;
if (authenticUser) {
return authorizeUser();
} else {
CommonUtil.displayFacesMessage(this.getClass(), FacesContext.getCurrentInstance(),
FacesMessage.SEVERITY_ERROR, "ERR1", id);
return "index";
}
}
private String authorizeUser() {
UserProfileDTO userProfileDTO = new UserProfileDTO();
CommonUtil.copyProperties(userProfileDTO, this);
Boolean authorizedUser = false;
// logic to authorize user. authorizedUser set true if authorization is
// successful
authorizedUser = userManagementService.authorizeUser(userProfileDTO);
if (authorizedUser) {
// Set User Role fetched from Database
this.role = userProfileDTO.getRole();
treeNavigationBean.setLoggedInUserId(id);
treeNavigationBean.setLoggedInUserRole(role);
treeNavigationBean.createTreeByUserRole();
treeNavigationBean.setViewCenterContent(null);
return "treeNavigation";
} else {
// Display Error Message that user is not authorized.
CommonUtil.displayFacesMessage(this.getClass(), FacesContext.getCurrentInstance(),
FacesMessage.SEVERITY_ERROR, "ERR2", id);
return "index";
}
}
/**
* #return the id
*/
public String getId() {
return id;
}
/**
* #param id the id to set
*/
public void setId(String id) {
if (StringUtils.isBlank(id)) {
this.id = id;
} else {
this.id = id.toUpperCase();
}
}
/**
* #return the password
*/
public String getPassword() {
return password;
}
/**
* #param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* #return the role
*/
public String getRole() {
return role;
}
/**
* #param role the role to set
*/
public void setRole(String role) {
this.role = role;
}
/**
* #return the userManagementService
*/
public UserManagementService getUserManagementService() {
return userManagementService;
}
/**
* #param userManagementService the userManagementService to set
*/
public void setUserManagementService(UserManagementService userManagementService) {
this.userManagementService = userManagementService;
}
/**
* #return the treeNavigationBean
*/
public TreeNavigationBean getTreeNavigationBean() {
return treeNavigationBean;
}
/**
* #param treeNavigationBean the treeNavigationBean to set
*/
public void setTreeNavigationBean(TreeNavigationBean treeNavigationBean) {
this.treeNavigationBean = treeNavigationBean;
}
/**
* #return the breadCrumbBean
*/
public BreadCrumbBean getBreadCrumbBean() {
return breadCrumbBean;
}
/**
* #param breadCrumbBean the breadCrumbBean to set
*/
public void setBreadCrumbBean(BreadCrumbBean breadCrumbBean) {
this.breadCrumbBean = breadCrumbBean;
}
}
Note: Since TreeNavigation bean is sessionscoped and single instance is shared, loggedInUserName is changed everytime different user is logging in. If user1 and user 2 logged in, then user1 who logged in first will see the screen of user2.
#ManagedBean(name = "treeNavigationBean")
#SessionScoped
public class TreeNavigationBean implements Serializable {
private static final long serialVersionUID = 1892577430001834938L;
private static final Logger LOGGER = Logger.getLogger(TreeNavigationBean.class);
private TreeNode root;
private TreeNode selectedNode;
private String loggedInUserId;
private String loggedInUserRole;
private String loggedInUserName;
private String viewCenterContent;
private String userAction;
#ManagedProperty(value = "#{userProfileBean}")
private UserProfileBean userProfileBean;
#ManagedProperty(value = "#{createConfigurationBean}")
private CreateConfigurationBean createConfigurationBean;
#ManagedProperty(value = "#{placeholderBean}")
private CreateConfigPlaceholderBean placeholderBean;
#ManagedProperty(value = "#{ncParamMappingBean}")
private NCParamMappingBean ncParamMappingBean;
#ManagedProperty(value = "#{breadCrumbBean}")
private BreadCrumbBean breadCrumbBean;
#ManagedProperty(value = "#{createTemplateBean}")
private CreateTemplateBean createTemplateBean;
#ManagedProperty(value = "#{configurationManagementBean}")
private ConfigurationManagementBean configurationManagementBean;
public void createTreeByUserRole() {
root = new DefaultTreeNode("Root", null);
if (TreeNodesEnum.SUPER_USER.equals(loggedInUserRole)) {
addCreateConfigurationNodes();
addTemplateAdministrationNodes();
addUserAdministrationNodes();
} else if (TreeNodesEnum.ADMIN_USER.equals(loggedInUserRole)) {
addCreateConfigurationNodes();
addTemplateAdministrationNodes();
} else if (TreeNodesEnum.NORMAL_USER.equals(loggedInUserRole)) {
addCreateConfigurationNodes();
}
}
.....................
With #Component you are using spring mvc beans instead of JSF beans. You can either switch to JSF beans or use Spring scopes, for example #Scope("session").

Resources