Reputation: 2025
I'm rather new to Hibernate and it turns out it's not a simple technology to learn... In the project I use hibernate version 4.2.0.CR1. I'm trying to create a base class for all database entities, as they all are supposed to contain some identifier and date of creation. What is weird is that at first, I crated class User and UserPicture without any base class and it worked perfectly fine and now that I added it, even though it's supposed to work just like before, it doesn't o_O and it keeps on throwing some weird exception about my list of pictures, that was not thrown before... So I keep on getting following stacktrace:
org.hibernate.MappingException: Could not determine type for: java.util.List, at table: User, for columns: [org.hibernate.mapping.Column(profilePicture)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:314)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:292)
at org.hibernate.mapping.Property.isValid(Property.java:239)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:469)
at org.hibernate.mapping.UnionSubclass.validate(UnionSubclass.java:61)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1283)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1734)
at love.commons.database.DBManager.<init>(DBManager.java:28)
at love.commons.database.DBManagerTest.<clinit>(DBManagerTest.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
AbstractEntity:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractEntity implements Serializable{
private static final long serialVersionUID = 1L;
protected Long id;
protected Date creationDate = new Date();
@Id
@Column(name="id")
@GeneratedValue(strategy=GenerationType.TABLE)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column
@NotNull
@Temporal(TemporalType.DATE)
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
}
User:
@Entity
@Table(name="User")
public class User extends AbstractEntity {
private static final long serialVersionUID = 1L;
@Column (unique=true, length=30)
@NotNull
private String login;
@Column (length=32)
@NotNull
private String password;
@NotNull
@Email
@Column (unique=true, length=80)
private String email;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="owner")
private List<UserPicture> profilePictures = new LinkedList<UserPicture>();
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Transient
public void encryptPassword() {
this.password = md5(password);
}
public List<UserPicture> getProfilePicture() {
return Collections.unmodifiableList(profilePictures);
}
public void addProfilePicture(UserPicture profilePicture) {
profilePicture.setOwner(this);
profilePictures.add(profilePicture);
}
@Transient
private String md5(String input) {
String md5 = null;
if(null == input) return null;
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(input.getBytes(), 0, input.length());
md5 = new BigInteger(1, digest.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5;
}
}
UserPicture:
@Entity
public class UserPicture extends AbstractEntity {
private static final long serialVersionUID = 1L;
@Column(length=734004)
private byte [] picture = null;
@ManyToOne(fetch=FetchType.LAZY)
@Column(name="owner")
@JoinColumn(nullable=false,name="id")
private User owner;
public UserPicture() {
picture = null;
}
public UserPicture(InputStream stream) {
try {
this.picture = new byte[stream.available()];
stream.read(picture);
} catch (IOException e) {
e.printStackTrace();
}
}
public UserPicture(byte [] picture) {
this.picture = picture;
}
public byte[] getPicture() {
return picture;
}
public void setPicture(byte[] picture) {
this.picture = picture;
}
public User getOwner() {
return owner;
}
public void setOwner(User owner) {
this.owner = owner;
}
}
So what am I doing wrong? Why do I keep on getting the exception?
Upvotes: 1
Views: 24391
Reputation: 470
you can try to add @ElementCollection mapping above the List declaration.
Upvotes: 0
Reputation: 176
I had the same problem, i figured out that hibernate tried to use Parent using properties accessorso i solved the problem by using @Access annotation to force use fields
@Entity
@Table(name = "MyTable")
@Access(AccessType.FIELD)
public class MyEntity{
......
}
Upvotes: 0
Reputation: 3121
From Hibernate 5.2 documentation:
By default, the placement of the @Id annotation gives the default access strategy.
For your case, hibernate will use AccessType.PROPERTY
both for UserPicture
and User
entities hence the exception, to use field mapping strategy, you should define @Access strategy explicitly :
@Entity
@Table(name="User")
@Access( AccessType.FIELD )
public class User extends AbstractEntity {
...
}
@Entity
@Access( AccessType.FIELD )
public class UserPicture extends AbstractEntity {
....
}
Upvotes: 1
Reputation: 691625
AbstractEntity must not be annotated with @Entity
and @Inheritance
. It must be annotated with @MappedSuperclass
. Indeed, this inheritance is only used to inherit common attributes, and that's what MappedSuperclass
is for.
The exception you get is caused by the lack of coherence in the position of your mapping annotations. The base superclass annotated the getters, and the subclasses annotate the fields. Hibernate uses the position of the Id annotation to determine the access type of the entity. Since @Id is on a getter, it only considers the annotations placed on getters, and ignores those placed on fields. Put all your annotations either on fields (which I would recommend) or on getters.
Moreover, your getter is badly named. It should be getProfilePictures()
and not getProfilePicture()
.
Upvotes: 6