Parth Darji
Parth Darji

Reputation: 11

Spring boot+jersey api+ JPA : failed to lazily initialize a collection of role

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

Answers (2)

Parth Darji
Parth Darji

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

Maciej Kowalski
Maciej Kowalski

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

Related Questions