Reputation: 11
I am new with using spring boot + jersey api + JPA.
I hava three entity that uses one to many bidirectional mapping. When i used spring boot + jersey api+ JPA I get error :
failed to lazily initialize a collection of role: com.kavinaam.GSTbilling.entity.Country.states, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.kavinaam.GSTbilling.entity.City["states"]->com.kavinaam.GSTbilling.entity.States["countyId"]->com.kavinaam.GSTbilling.entity.Country["states"])
I have added my entity, dao , services and end point.
@Entity
@Table(name="country")
public class Country implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private int id;
@Column(name="countryName")
private String countryName;
@OneToMany(mappedBy = "countyId",cascade = CascadeType.ALL)
private Set<States> states;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
public Set<States> getStates() {
return states;
}
public void setStates(Set<States> states) {
this.states = states;
}
}
My state class:
@Entity
@Table(name="states")
public class States implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private int id;
@ManyToOne
@JoinColumn(name="countyId")
private Country countyId;
@Column(name="stateName")
private String stateName;
@OneToMany(mappedBy = "states", cascade = CascadeType.ALL)
private Set<City> city;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Country getCountyId() {
return countyId;
}
public void setCountyId(Country countyId) {
this.countyId = countyId;
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
public Set<City> getCity() {
return city;
}
public void setCity(Set<City> city) {
this.city = city;
}
}
My city class:
@Entity
@Table(name="cities")
public class City implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private int id;
@ManyToOne
@JoinColumn(name="stateId")
private States states;
@Column(name="cityName")
private String cityName;
@Column(name="zip")
private String zip;
public void setId(int id) {
this.id = id;
}
public void setZip(String zip) {
this.zip = zip;
}
public States getStates() {
return states;
}
public void setStates(States states) {
this.states = states;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public String getZip() {
return zip;
}
public int getId() {
return id;
}
}
My DAO:
@Transactional
@Repository
public class GSTCityDAO implements IGSTCityDAO {
@PersistenceContext
private EntityManager entityManager;
//@SuppressWarnings("unchecked")
@Override
public List<City> getAllCities() {
//Session session = sessionFactory.getCurrentSession();
String hql = "FROM City as ct ORDER BY ct.id";
List<City> l = entityManager.createQuery(hql,City.class).getResultList();
return l;
}
@Override
public City getCityById(int cityId) {
return entityManager.find(City.class, cityId);
}
@SuppressWarnings("unchecked")
@Override
public List<City> getCityByStateId(States stateId) {
String getcitybystate = " FROM City as c WHERE c.states = ?";
return (List<City>) entityManager.createQuery(getcitybystate).setParameter(1, stateId).getResultList();
}
@Override
public void addCity(City city) {
entityManager.persist(city);
}
@Override
public void updateCity(City city) {
City cityctl = getCityById(city.getId());
cityctl.setCityName(city.getCityName());
cityctl.setZip(city.getZip());
cityctl.setStates(city.getStates());
entityManager.flush();
}
@Override
public void deleteCity(int cityId) {
entityManager.remove(getCityById(cityId));
}
@Override
public boolean cityExists(String name, String zip) {
String hql = "FROM City WHERE cityName = ? and zip = ?";
int count = entityManager.createQuery(hql).setParameter(1,name).setParameter(2, zip).getResultList().size();
return count > 0 ? true : false;
}
}
Services:
@Service
public class GSTCityService implements IGSTCityService {
@Autowired
private IGSTCityDAO cityDAO;
@Override
public List<City> getAllCities() {
List<City> l = cityDAO.getAllCities();
Hibernate.initialize(l);
return l;
}
public List<City> getCityByStateId(States stateId) {
return cityDAO.getCityByStateId(stateId);
}
@Override
public City getCityById(int cityId) {
City city = cityDAO.getCityById(cityId);
return city;
}
@Override
public synchronized boolean addCity(City city) {
if(cityDAO.cityExists(city.getCityName(), city.getZip())){
return false;
}else{
cityDAO.addCity(city);
return true;
}
}
@Override
public void updateCity(City city) {
cityDAO.updateCity(city);
}
@Override
public void deleteCity(int cityId) {
cityDAO.deleteCity(cityId);
}
}
End Point:
@Component
@Path("/")
public class Test {
private static final Logger logger = LoggerFactory.getLogger(Test.class);
@Autowired
private IGSTCityService cityService;
@GET
@Path("/hi")
@Produces(MediaType.APPLICATION_JSON)
public Response hello(){
return Response.ok("Hello GST").build();
}
@GET
@Path("/test")
@Produces(MediaType.APPLICATION_JSON)
public Response getAllDate(){
List<City> list = cityService.getAllCities();
for(City city: list){
System.out.println(city);
}
return Response.ok(list).build();
}
@GET
@Path("/test/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getAllDateBySome(@PathParam("id") Integer id){
States state = new States();
state.setId(id);
List<City> list = cityService.getCityByStateId(state);
return Response.ok(list).build();
}
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getDataById(@PathParam("id")Integer id){
City citl = cityService.getCityById(id);
return Response.ok(citl).build();
}
@POST
@Path("/add")
@Consumes(MediaType.APPLICATION_JSON)
public Response addData(City city){
boolean isAdded = cityService.addCity(city);
if(!isAdded){
return Response.status(Status.CONFLICT).build();
}
return Response.created(URI.create("/gst/"+ city.getId())).build();
}
@PUT
@Path("/update")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response updateCountry(City city){
cityService.updateCity(city);
return Response.ok(city).build();
}
@DELETE
@Path("/{id}")
@Consumes(MediaType.APPLICATION_JSON)
public Response deleteCountry(@PathParam("id")Integer id){
cityService.deleteCity(id);
return Response.noContent().build();
}
}
I am using import org.springframework.transaction.annotation.Transactional; for transnational in DAO. Also I can not use @PersistenceContext(type=PersistenceContextType.EXTENDED) and fetch type Eager because I get error of Maximum stack size exceeded
Upvotes: 0
Views: 697
Reputation: 11
I solved it by using the @JsonBackReference on OneToMany relationship. The problem is with the Serialization and Deserialization. " the property annotated with @JsonManagedReference annotation is handled normally (serialized normally, no special handling for deserialization) and the property annotated with @JsonBackReference annotation is not serialized; and during deserialization, its value is set to instance that has the "managed" (forward) link."
Upvotes: 1
Reputation: 26552
You should do one or both of the following:
1) Move the @Transactional
from DAO to Service. Thats a good idea in general as usually are still processing the result entities in some way on that layer.
2) Fetch the dependencies in the queries explicitly:
select ct FROM City as ct inner join fetch ct.states s ORDER BY ct.id
Upvotes: 0