I'm trying to add a City
to a Country
using a @ManyToOne
relationship. The problem is that I am getting a org.hibernate.PropertyAccessException
as I try to save my entities.
private void addAddressData() {
Session session = sessionFactory.openSession();
session.beginTransaction();
List<Country> countryList = new ArrayList<>();
Country austria = new Country("at");
countryList.add(new Country("de"));
countryList.add(austria);
for(Country country : countryList) {
try {
session.save(country);
} catch (ConstraintViolationException e) {
e.printStackTrace();
}
}
List<City> cityList = new ArrayList<>();
cityList.add(new City(austria, "Graz"));
cityList.add(new City(austria, "Wien"));
for(City city : cityList) {
try {
session.save(city);
} catch (ConstraintViolationException e) {
e.printStackTrace();
}
}
session.getTransaction().commit();
}
It seems like I need to specify the relation different or at least tell Hibernate where it can find the Country
id. It surely is just an annotation thing ..
Please Note: I auto-generated all setters and getters but removed them for the sake of code length here on SO.
Country.java
@Entity
public class Country implements Serializable {
/**
*
*/
private static final long serialVersionUID = -2060021861139912774L;
@Id
@GeneratedValue
@Column(name="id")
private Long id; // = null; (was not the problem)
@Column(unique=true)
private String countryCode;
public Country(String country_code) {
this.countryCode = country_code;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "Country [id=" + id.toString() + ", country_code=" + countryCode.toString() +"]";
}
}
City.java
@Entity
public class City implements Serializable {
/**
*
*/
private static final long serialVersionUID = -4374113410767348574L;
@Id
@GeneratedValue
@Column(name="id")
private Long id;
@Id
@ManyToOne
private Country country;
private String cityName;
public City(Country country, String cityName) {
this.setCountry(country);
this.cityName = cityName;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCityName() {
return cityName;
}
public void setCityName(String countryName) {
this.cityName = countryName;
}
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
@Override
public String toString() {
return "City [id=" + id.toString() + ", country_id="
+ getCountry().toString() + ", cityName=" + cityName + "]";
}
}
Stacktrace
Exception in thread "main" org.hibernate.PropertyAccessException: could not set a field value by reflection setter of com.mahlzeit.datamodel.address.City.id
at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:150)
at org.hibernate.mapping.Component$ValueGenerationPlan.execute(Component.java:436)
at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:121)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:120)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:204)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:189)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:642)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:635)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:631)
at com.mahlzeit.datamodel.HibernateTest.addAddressData(HibernateTest.java:57)
at com.mahlzeit.datamodel.HibernateTest.main(HibernateTest.java:31)
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.Long field com.mahlzeit.datamodel.address.City.id to org.hibernate.id.IdentifierGeneratorHelper$2
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(Unknown Source)
at java.lang.reflect.Field.set(Unknown Source)
at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:138)
... 13 more
The definition of the oneToMany
mapping between the two classes is incorrect.
@Id //wrong annotation here
@ManyToOne
private Country country;
Should be:
@ManyToOne
@JoinColumn(name="id") //the country id, better rename it country_id
private Country country;
The @Id
is misplaced here and Hibernate get confused because there are two columns annotated @Id
, and in your Country
class you should declare a set of cities to complete the mapping, like this:
@OneToMany(mappedBy="country")
private Set<City> cities;
//the right getters and setters for cities
For further information about One To Many mapping take a look at this Hibernate One To Many Annotation Tutorial.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With