关于hibernate:无法确定类型:java.util.List

Could not determine type for: java.util.List

我对冬眠比较陌生,结果发现这不是一项简单的学习技术…在这个项目中,我使用了Hibernate版本4.2.0.cr1。我正在尝试为所有数据库实体创建一个基类,因为它们都应该包含一些标识符和创建日期。奇怪的是,一开始我把没有任何基类的类用户和用户图片装进板条箱,它工作得非常好,现在我又添加了它,尽管它应该像以前一样工作,但它不工作,它不断地对我的图片列表抛出一些奇怪的例外,这在以前没有被抛出……所以我继续跟踪stacktrace:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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)

抽象实体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@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;
}
}

用户:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
@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;
}  
}

用户图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@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;
}  
}

我做错了什么?为什么我要继续得到例外?


abstractEntity不能用@Entity@Inheritance注释。必须用@MappedSuperclass注释。实际上,这种继承只用于继承公共属性,这就是MappedSuperclass的作用。

您得到的异常是由于映射注释位置缺乏一致性造成的。基超类对getter进行了注释,子类对字段进行了注释。Hibernate使用ID注释的位置来确定实体的访问类型。因为@id在getter上,所以它只考虑放在getter上的注释,而忽略放在字段上的注释。将所有注释放在字段(我推荐)或getter上。

而且,你的getter名字很差。应该是getProfilePictures()而不是getProfilePicture()


从Hibernate 5.2文档:

By default, the placement of the @Id annotation gives the default
access strategy.

对于您的情况,Hibernate将对UserPictureUser实体同时使用AccessType.PROPERTY,因此例外情况是,要使用字段映射策略,您应该明确定义@access策略:

1
2
3
4
5
6
7
8
9
10
11
12
@Entity
@Table(name="User")
@Access( AccessType.FIELD )
public class User extends AbstractEntity {
    ...
}

@Entity
@Access( AccessType.FIELD )
public class UserPicture extends AbstractEntity {
    ....
}


我也遇到了同样的问题,我发现Hibernate试图使用属性访问器来使用父级,所以我使用@access注释强制使用字段来解决了这个问题。

1
2
3
4
5
6
@Entity
@Table(name ="MyTable")
@Access(AccessType.FIELD)
public class MyEntity{
     ......
}