无法将java.lang.String字段设置为java.lang.String

5

我目前正在开发一个带有socket服务器的小型MMO应用程序。我在使用PostgreSQL数据库,使用Hibernate ORM。当我请求单个用户拥有的所有头像时,遇到了一个异常。

涉及到三个类:

  • GameServerClient
  • Database
  • Database.Queries

当用户(客户端应用程序)通过sockets向服务器发送请求时,将调用一个方法,该方法应返回所有头像的JsonString。

但是,使用HQL查询from UserOwnsAvatar where user = :username并将结果放入UserOwnsAvatar对象的ArrayList中时,会返回一个Can not set java.lang.String field nl.marcusink.mmo.server.database.table.User.username to java.lang.String错误。

完整的堆栈跟踪为:

org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private java.lang.String nl.marcusink.mmo.server.database.table.User.username] by reflection for persistent property [nl.marcusink.mmo.server.database.table.User#username] : Mjollnir94
    at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:43)
    at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:223)
    at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4594)
    at org.hibernate.type.EntityType.toLoggableString(EntityType.java:505)
    at org.hibernate.internal.util.EntityPrinter.toString(EntityPrinter.java:87)
    at org.hibernate.engine.spi.QueryParameters.traceParameters(QueryParameters.java:281)
    at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:194)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1268)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
    at nl.marcusink.mmo.server.database.Database$Queries.avatarsRequest(Database.java:134)
    at nl.marcusink.mmo.server.connection.GameServerClient.run(GameServerClient.java:91)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.String field nl.marcusink.mmo.server.database.table.User.username to java.lang.String
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
    at java.lang.reflect.Field.get(Field.java:393)
    at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:39)
    ... 11 more

查询代码是:

Query query = session.createQuery("from UserOwnsAvatar where user = :username");
query.setParameter("username", username);
ArrayList<UserOwnsAvatar> ownedAvatars = (ArrayList<UserOwnsAvatar>) query.list();

最后一行是导致错误的原因,有什么想法吗?
编辑
@Id
@ManyToOne(targetEntity = User.class)
@JoinColumn(name = "username", nullable = false)
private User user;

@Id
@OneToOne(targetEntity = Avatar.class)
@JoinColumn(name = "avatar", nullable = false, unique = true)
private Avatar avatar;

这里的用户名等同于用户对象的用户名,即:

@Id
@Column(name = "username", unique = true, nullable = false)
private String username;

1
你能展示与“用户名”相关的代码吗? - Jos
2
也许你需要在User类中添加public void setUsername(String username) {this.username = username;} - Blake Yarbrough
我为每个表类生成了所有的getter和setter。其中之一是public void setUsername(String username) { this.username = username; }。我认为这不可能是问题所在。 - Marcel
谢谢您的帮助!我对这种错误视而不见... - Marcel
2
哦,那个错误信息真是一团糟。从堆栈跟踪中可以看出,它试图进行“获取”操作,但却产生了“无法设置”的错误消息。在查看UnsafeFieldAccessorImpl.ensureObj的源代码后,我得出结论,尽管错误消息关注的是值,但实际上是实例不属于User类型,导致了这次尝试失败… - Holger
显示剩余4条评论
2个回答

3

您需要设置完整的对象(或只包含相关字段的对象),而不是该对象的某个特定值。

我的理解是,您尝试在设置参数时设置了一个String,但是该列的类型为User。Hibernate正在尝试在String上调用getUsername方法,这就是错误的原因。

因此,请将您的代码更改为以下内容:

User user = getSomeUser();
Query query = session.createQuery("from UserOwnsAvatar where user.username =  :username");
query.setParameter("username", user);

你的想法是正确的,但你的示例代码需要修改。它解决了我之前遇到的类似问题。 - Tom Tresansky

1

user = :username 不正确。 user不是实体的字符串字段。可以使用连接或使用Hibernate标准来为User创建别名并添加限制,例如 .add(Restriction.eq("user.username",username)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接