I'm developing an application using java with hibernate 4.2.6 and spring 4.0.1. My application is a REST FULL application. for this I use jackson. My entities are as follow:
Calk.java:
#Entity
public class Calk {
#Id
#GeneratedValue
private Long id;
#OneToMany(mappedBy="calk", fetch=FetchType.LAZY)
List<BaseLayer> baseLayer = new ArrayList<BaseLayer>();
public void addBaseLayer(BaseLayer baseLayer){
this.baseLayer.add(baseLayer);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JsonIgnore
public List<BaseLayer> getBaseLayer() {
return baseLayer;
}
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}
}
BaseLayer.java:
#Entity
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="layer")
#JsonSubTypes(
{
#JsonSubTypes.Type(value=PointLayer.class, name="point")
})
#DiscriminatorValue("BaseLayerDiscriminator")
public class BaseLayer {
#Id
#GeneratedValue
protected Long gid;
#ManyToOne(fetch = FetchType.LAZY)
protected Calk calk;
public Long getGid(){
return gid;
}
public void setGid(Long gid){
this.gid = gid;
}
#JsonIgnore
public Calk getCalk(){
return calk;
}
public void setCalk(Calk calk){
this.calk = calk;
}
}
Now I have a class that extends from BaseLayer.java as follow:
PointLayer.java:
#Entity
#DiscriminatorValue("PointDiscriminator")
public class PointLayer extends BaseLayer{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now I create a json as follow and then send it to a controller:
{"layer": "point", "calk":{"id":1}, "name": "itsme"}
Now the controller defines as follow:
#RequestMapping("\test")
public String test(#RequestBody BaseLayer baseLayer){
System.out.println(baseLayer.getName());// this print "itsme"
Calk calk = baseLayer.getCalk();//it return null
if(calk == null)
return "its null";
else
return "its not null";
}
when we call the controller it return its not null. The calk should not be null.
Where is the problem?
Update:
When I remove #JsonIgnore at getCalk, It work fine. But Why? I want to ignore getCalk but NOT ignore setCalk.
#JsonIgnore in follow:
#JsonIgnore
public List<BaseLayer> getBaseLayer() {
return baseLayer;
}
set Ignore to following by default:
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}
You must add #JsonProperty("baseLayer") On top of set function as follow:
#JsonProperty("baseLayer")
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}
Related
I have 3 controllers on my spring app. Each one of them have different name then I set up for example I have
#RestController
#RequestMapping("/operator")
public class OperativesController {
and when run it on localhost and check available routes this is my output
{
"_links" : {
"operativeses" : {
"href" : "http://localhost:8080/operativeses"
}
}
}
I would appreciate if someone would tell me that where this name is coming from?
PS. yesterday everything was all right.
Not sure if that is helpful for you but below you can find my properties
logging.level.org.hibernate=INFO
spring.jpa.show-sql=true
hibernate.dialect = org.hibernate.dialect.SQLServer2016Dialect
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.ddl-auto=none
EDIT
I just debug this spring app and find out that, my path are created from "Entities". So I have entity names Operatives and spring picking up it as URL, so it automatically creating path like operativeses (why? I do not know) because I change name of this entity to 'Operativesasd' and in the result I have path 'Operativesasds' (notice s on the end)
So my question now is, Why my spring app creating path base on entities even if I have controllers?
my entity looks like
#Entity
#Table(name="operatives", schema = "lm")
public class Operatives implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name", length=150)
private String name;
#Column(name = "level", length=7)
private String level;
#Column(name="is_qa", length=50)
private String isQa;
#Column(name="is_active", length=5)
private String isActive;
#Column(name="is_admin", length=50)
private String isAdmin;
public Operatives() {
super();
}
public int getId() {
return id;
}
public void setId(int aId) {
id = aId;
}
public String getName() {
return name;
}
public void setName(String aName) {
name = aName;
}
public String getLevel() {
return level;
}
public void setLevel(String aLevel) {
level = aLevel;
}
public String getIsQa() {
return isQa;
}
public void setIsQa(String aIsQa) {
isQa = aIsQa;
}
public String getIsActive() {
return isActive;
}
public void setIsActive(String aIsActive) {
isActive = aIsActive;
}
public String getIsAdmin() {
return isAdmin;
}
public void setIsAdmin(String aIsAdmin) {
isAdmin = aIsAdmin;
}
}
In my project I try yo use Spring data Jpa. My find methods(findById, findAll) works correctly, but delete and save method works with problems. Delete method delete only from duck table. Save doesn't work:
Exception in thread "main" org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find springdata.entities.FrogJpa with id 2; nested exception is javax.persistence.EntityNotFoundException: Unable to find springdata.entities.FrogJpa with id 2
I have 2 entities: Frog and Duck. Every ducks have 1 Frog(OneToOne). There are problems with entities relationship?
There are my entities class:
#Entity
#Table(name = "DUCKS")
public class DuckJpa implements Serializable {
#Id
private int id;
#Column(name = "NAME")
private String name;
#Column(name = "FLY")
private String flyBehavior;
#Column(name = "QUACK")
private String quackBehavior;
#OneToOne(optional = false)
#JoinColumn(name = "FROG_ID", unique = true, nullable = false, updatable = false)
private FrogJpa frogJpa;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setFlyBehavior(String flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(String quackBehavior) {
this.quackBehavior = quackBehavior;
}
public void setFrogJpa(FrogJpa frogJpa) {
this.frogJpa = frogJpa;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getFlyBehavior() {
return flyBehavior;
}
public String getQuackBehavior() {
return quackBehavior;
}
public FrogJpa getFrogJpa() {
return frogJpa;
}
And Frog:
#Entity
#Table(name = "FROGS")
public class FrogJpa {
#OneToOne(optional = false, mappedBy = "frogJpa")
private DuckJpa duckJpa;
#Id
private int id;
#Column(name = "name")
private String name;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setDuckJpa(DuckJpa duckJpa) {
this.duckJpa = duckJpa;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public DuckJpa getDuckJpa() {
return duckJpa;
}
}
My service class:
public interface DuckService {
List<DuckJpa> findAll();
Optional<DuckJpa> findById(Integer i);
DuckJpa save(DuckJpa duckJpa);
void delete(DuckJpa duckJpa);
}
And it's implementation:
#Service("springJpaDuckService")
#Transactional
public class DuckServiceImpl implements DuckService {
#Autowired
private DuckJpaRepository duckJpaRepository;
#Transactional(readOnly = true)
public List<DuckJpa> findAll() {
return new ArrayList<>(duckJpaRepository.findAll());
}
#Override
public Optional<DuckJpa> findById(Integer i) {
return duckJpaRepository.findById(i);
}
#Override
public DuckJpa save(DuckJpa duckJpa) {
duckJpaRepository.save(duckJpa);
return duckJpa;
}
#Override
public void delete(DuckJpa duckJpa) {
duckJpaRepository.delete(duckJpa);
}
Use #OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY).
For more information please refer What is cascading in Hibernate?
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
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."
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
I have such situation:
There are a few groups of POJO classes, each with one parent. Each group serves to be working with some recording of data - to the XML with the help of JAXB and to the database with the help of Hibernate. A simplified version of my working code is:
public static abstract class Habit{
String habitName;
/* constructors */
/* getter & setter */
}
#Entity
#Access(AccessType.PROPERTY)
#Table(name = "habit")
public static class DBHabit extends Habit{
#Id
#GeneratedValue
private int id;
#Column(name = "habit_name")
public String getHabitName() {
return habitName;
}
public void setHabitName(String habitName) {
this.habitName = habitName;
}
}
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name = "habit")
public static class XmlHabit extends Habit{
#XmlElement
public String getHabitName() {
return habitName;
}
public void setHabitName(String habitName) {
this.habitName = habitName;
}
}
public static abstract class Person{
int age;
String name;
List<Habit> habits;
/* Constructor */
/* Getters & Setters */
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Habit> getHabits() {
return habits;
}
public void setHabits(List<Habit> habits) {
this.habits = habits;
}
}
#Entity
#Access(AccessType.PROPERTY)
#Table(name = "person")
public static class DBPerson extends Person{
#Id
#GeneratedValue
private int id;
#Column(name = "age")
#Override
public int getAge() {
return age;
}
#Override
public void setAge(int age) {
this.age = age;
}
#Column(name = "name")
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, targetEntity = DBHabit.class)
#Override
public List<Habit> getHabits() {
return habits;
}
#Override
public void setHabits(List<Habit> friends) {
this.habits = habits;
}
}
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlType(name = "", propOrder = {
"age",
"name",
"habits"
})
#XmlRootElement(name = "state")
public static class XmlPerson extends Person{
#Override
#XmlElement(required = true)
public int getAge() {
return super.getAge();
}
#Override
public void setAge(int age) {
super.setAge(age);
}
#Override
#XmlElement(required = true)
public String getName() {
return super.getName();
}
#Override
public void setName(String name) {
super.setName(name);
}
#Override
#XmlElement(required = true)
#XmlElementWrapper(name = "friends")
public List<Habit> getHabits() {
return super.getHabits();
}
#Override
public void setHabits(List<Habit> habits) {
super.setHabits(habits);
}
}
I have problems with working with Hibernate. Thought I wrote that I expect the recording of DBHabit.class in targetEntity, hibernate does not record any information about habits, this table is always empty.
Please give me a hint, what can I make in such situation or advice, how I can make a similar abstract system like this for the writing in different ways.
Thank you for attention!
A couple of strange thing i noticed in your mapping:
a #OneToOne mapping, backed by a List<Habit>. Why not directly Habit ?
You annotate class with #Access(AccessType.PROPERTY) but then you put the mapping annotation on accessor methods (you're issue might come from there).
Instead you could try to annotate the parent abstract class as #MappedSuperclass. This way, you do not have to redefine the accessor. Or if you do not wish to put hibernate annotations in the parent class, remove the #Access(AccessType.PROPERTY) annotation.
I have the next maven projects:
project-model : I have JPA entities
project-rest : Spring data, spring rest based on spring boot
project-client : Jersey clients to consume the rest services
project-web : Only jsf web application
project-desktop : Java Fx desktop application
project-android : Mobile application which consumes my Rest web services.
I'm planing to remove the JPA entities from the project-model and place there only DTO's pojos and interfaces and place my JPA entities in the rest project in order to remove the jpa dependencies from the project-model. This is because I don't want to have JPA dependencies in the project-android, project-web and project-desktop.
I was thinking to follow the next schema:
#JsonSerialize(as=CountryDto.class)
#JsonDeserialize(as=CountryDto.class)
public interface ICountry extends Serializable
{}
#Entity
#Table(name = "COUNTRY")
#JsonSerialize(as=Country.class)
#JsonDeserialize(as=Country.class)
public class Country implements ICountry
{}
public class CountryDto implements ICountry
{}
And if I need to convert from Entities to DTO's use mapstruct or Selma.
But I'm not sure if this is the best practice because I have problems in my code like the next:
#JsonSerialize(as=CityDto.class)
#JsonDeserialize(as=CityDto.class)
public interface ICity extends Serializable
{
public Integer getIdCity();
public void setIdCity(Integer idCity);
public String getName();
public void setName(String name);
public ICountry getCountryId();
public void setCountryId(ICountry countryId);
}
public class CityDto implements ICity
{
private static final long serialVersionUID = -6960160473351421716L;
private Integer idCity;
private String name;
private CountryDto countryId;
public CityDto()
{
// TODO Auto-generated constructor stub
}
public CityDto(Integer idCity, String name, CountryDto countryId)
{
super();
this.idCity = idCity;
this.name = name;
this.countryId = countryId;
}
public CityDto(Integer idCity, String name)
{
super();
this.idCity = idCity;
this.name = name;
}
#Override
public Integer getIdCity()
{
return idCity;
}
#Override
public void setIdCity(Integer idCity)
{
this.idCity = idCity;
}
#Override
public String getName()
{
return name;
}
#Override
public void setName(String name)
{
this.name = name;
}
#Override
public ICountry getCountryId()
{
return countryId;
}
#Override
public void setCountryId(ICountry countryId)
{
this.countryId = (CountryDto) countryId;
}
}
#Entity
#Table(name = "CITY")
#JsonSerialize(as=City.class)
#JsonDeserialize(as=City.class)
public class City implements ICity
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_CITY")
private Integer idCity;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "NAME")
private String name;
#JoinColumn(name = "COUNTRY_ID", referencedColumnName = "ID_COUNTRY")
#ManyToOne(optional = false)
private Country countryId;
private static final long serialVersionUID = 1L;
public City()
{
}
public City(Integer idCity)
{
this.idCity = idCity;
}
public City(Integer idCity, String name)
{
this.idCity = idCity;
this.name = name;
}
#Override
public Integer getIdCity()
{
return idCity;
}
#Override
public void setIdCity(Integer idCity)
{
this.idCity = idCity;
}
#Override
public String getName()
{
return name;
}
#Override
public void setName(String name)
{
this.name = name;
}
#Override
public ICountry getCountryId()
{
return countryId;
}
#Override
public void setCountryId(ICountry countryId)
{
this.countryId = (Country) countryId;
}
#Override
public int hashCode()
{
int hash = 0;
hash += (idCity != null ? idCity.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 City))
{
return false;
}
City other = (City) object;
if ((this.idCity == null && other.idCity != null) || (this.idCity != null && !this.idCity.equals(other.idCity)))
{
return false;
}
return true;
}
#Override
public String toString()
{
return "com.neology.ebreeder.model.entities.City[ idCity=" + idCity + " ]";
}
}
And as You can see in the entity I have getters and setters using the shared interface, and I think that It could provoke problems, I thought to override the getters using the entity but I can't override the setters.
I cant do this:
#Override
public Country getCountryId()
{
return countryId;
}
But I can't do this :
#Override
public void setCountryId(Country countryId)
{
this.countryId = (Country) countryId;
}
Do you see a better solution or could you give me your point of view :)
thanks
Based on past experience, I do not think it is a good idea to use an interface that is shared between the DTO model and the JPA model.
You are in essence tightly coupling your DTO model to your JPA model with this approach.
I would rather have them loosely coupled and use a separate framework to copy between these two models. This will need to be powered by a meta model (could be derived from JPA) to walk and copy the data from one model to another based on the getters and setters.