could not set a field value by reflection setter of models.User.avatar

5,549 views
Skip to first unread message

McGivrer

unread,
Mar 16, 2011, 6:55:03 PM3/16/11
to play-framework
Hello Players !

I am in front of a strange behaviour, due to, IMHO, hibernate
persistence engine.

I've just tried to design a new Attachment field, inspired by the Blob
field from 1.1 release.

Mine is Attachment with an interface IAttachment to produce some agile
attribute on file management purpose. As I am not a specialist on Java
1.6, I am not sur to go through the right way.

See bellow my classes :



----- Attachment.java
--------------------------------------------------------------------------

package shared;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.PostPersist;
import javax.persistence.PostUpdate;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;

import play.Play;
import play.db.Model.BinaryField;
import play.exceptions.UnexpectedException;
import play.libs.Codec;
import play.libs.IO;

/**
* Picture management for Play! Models attributes.
* @author frederic
*
*/
public class Attachment<T> implements BinaryField, UserType {
/**
* Unic Id
*/
private String UUID;
/**
* Type of data
*/
private String type;
/**
* File attachement
*/
private Map<String,File> files;

/**
* Default constructor.
*/
public Attachment() {
}

public String[] setThumbnailsSize(){
return new String[]{""};
}
public String setAttachmentPath(){
return "Attachments";
}

/**
* Parameterized Constructor.
* @param UUID
* @param type
*/
private Attachment(String UUID, String type) {
this.UUID = UUID;
this.type = type;
}

/**
* @see play.db.Model.BinaryField.get()
*/
public InputStream get() {
return get("");
}

/**
* Specific implementation for Thumbnailing picture.
* @param size
* @return
*/
public InputStream get(String size) {
if(exists(size)) {
try {
return new FileInputStream(getFile(size));
} catch(Exception e) {
throw new UnexpectedException(e);
}
}
return null;
}

/**
* Set InputStream to the file system.
*/
public void set(InputStream is, String type) {
this.UUID = Codec.UUID();
this.type = type;
IO.write(is, getFile(""));
try {
generateThumbnails();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* generate Thumbnails on size defined.
* @throws Exception
*/
public void generateThumbnails() throws Exception{
String size;
// Generate Thumbnails
for (int i=0; i<setThumbnailsSize().length;i++) {
size = setThumbnailsSize()[i];
String sizeName = size.split("-")[0];
Thumbnail.create(getFile(sizeName),getFile(""),size);
}

}

public long length() {
return getFile("").length();
}

public String type() {
return type;
}

public boolean exists() {
return UUID != null && getFile("").exists();
}

/**
* Specific implementation to manage Thumbnail size.
* @param size
* @return
*/
public boolean exists(String size) {
return UUID != null && getFile(size).exists();
}


/**
* Return file for size qualified attachment.
* @return
*/
public File getFile(String size) {
if(files == null) {
files = new HashMap<String,File>();
}
if(files.get(size)==null){
files.put(size,new File(getStore(this.setAttachmentPath()
+File.separator), UUID+(size!=null && size!="" ? "."+size : "")
+".jpg"));
}
return files.get(size);
}


public int[] sqlTypes() {
return new int[] {Types.VARCHAR};
}

public Class returnedClass() {
return Attachment.class;
}

public boolean equals(Object o, Object o1) throws
HibernateException {
return o == null ? false : o.equals(o1);
}

public int hashCode(Object o) throws HibernateException {
return o.hashCode();
}

// TODO: After we switch to Hibernate 3.6, Hibernate.STRING must
be changed to
// Hibernate.StringType.INSTANCE (how stupid is that to deprecate
stuff before offering
// an alternative?
@SuppressWarnings("deprecation")
public Object nullSafeGet(ResultSet rs, String[] names, Object o)
throws HibernateException, SQLException {
String val = (String) Hibernate.STRING.nullSafeGet(rs,
names[0]);
if(val == null || val.length() == 0 || !val.contains("|")) {
return new Attachment<T>();
}
return new Attachment<T>(val.split("[|]")[0], val.split("[|]")
[1]);
}

public void nullSafeSet(PreparedStatement ps, Object o, int i)
throws HibernateException, SQLException {
if(o != null) {
ps.setString(i, ((Attachment)o).UUID + "|" +
((Attachment)o).type);
} else {
ps.setNull(i, Types.VARCHAR);
}
}

public Object deepCopy(Object o) throws HibernateException {
if(o == null) {
return null;
}
return new Attachment<T>(this.UUID, this.type);
}

public boolean isMutable() {
return true;
}

public Serializable disassemble(Object o) throws
HibernateException {
throw new UnsupportedOperationException("Not supported yet.");
}

public Object assemble(Serializable srlzbl, Object o) throws
HibernateException {
throw new UnsupportedOperationException("Not supported yet.");
}

public Object replace(Object o, Object o1, Object o2) throws
HibernateException {
throw new UnsupportedOperationException("Not supported yet.");
}

//

public static String getUUID(String dbValue) {
return dbValue.split("[|]")[0];
}

public static File getStore(String path) {
String name =
Play.configuration.getProperty("attachments.path", "attachments");
File store = null;
if(new File(name).isAbsolute()) {
store = new File(name+File.separator+path);
} else {
store = Play.getFile(name+File.separator+path);
}
if(!store.exists()) {
store.mkdirs();
}
return store;
}

}

----- IAttachment.java
--------------------------------------------------------------------------

/**
*
*/
package shared;

/**
* @author frederic
*
*/
public interface IAttachment {
public String[] setThumbnailsSize();
public String setAttachmentPath();

}


Avatar is one implementation of the Attachment field:

----- Avatar.java
--------------------------------------------------------------------------

/**
*
*/
package shared;


/**
* @author frederic
*
*/
public class Avatar extends Attachment<Avatar> implements IAttachment
{
public String[] setThumbnailsSize(){
return new String[]
{"micro-60x80","mini-90x120","medium-120x190","paysage-320x80"};
}
public String setAttachmentPath(){
return "Games";
}
}


and finaly, the User model, trying to implement this Avatar "field":

----- User.java
--------------------------------------------------------------------------

/**
* Project myplayapp
* Classe modélisant un utilisateur de l'application
*/
package models;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.OneToMany;
import javax.persistence.PostLoad;
import javax.persistence.Transient;

import play.data.validation.Email;
import play.data.validation.MaxSize;
import play.data.validation.MinSize;
import play.data.validation.Required;
import play.data.validation.URL;
import play.db.jpa.Model;
import shared.Avatar;

/**
* User modélise un utilisateur pouvant se connecter.
* @author McGivrer
*/
@Entity
public class User extends Model{

public enum UserRole {
ADMINISTRATOR,
MODERATOR,
USER
}

@Required
@MaxSize(30)
public String username;

@Required
@MinSize(4)
@MaxSize(25)
public String password;

//@Transient
//@Required
//@Equals("password")
//public String passwordConfirm;

@MaxSize(50)
public String firstname;

@MaxSize(50)
public String lastname;

@Required
@Email
@MaxSize(100)
public String email;

@MaxSize(100)
@URL
public String webblog;

@MaxSize(255)
public String image="test";

@Required
@MaxSize(2)
public String status="a";

@Required
@Enumerated(EnumType.STRING)
public UserRole role;

@Required
public String language;

@Transient
public String gravatarHash;

public Avatar avatar;

@OneToMany
public List<Game> games;

/**
* Constructeur paramétré par défaut.
* @param username
* @param password
* @param firstname
* @param lastname
* @param email
* @param webblog
* @param image
* @param status
* @param role
* @param language
*/
public User(
String username,
String password,
//String passwordConfirm,
String firstname,
String lastname,
String email,
String webblog,
String image,
String status,
UserRole role,
String language){
this.username=username;
this.password=password;
//this.passwordConfirm=passwordConfirm;
this.firstname=firstname;
this.lastname=lastname;
this.email=email;
this.webblog=webblog;
this.image=image;
this.status=status;
this.role=role;
this.language = language;
}


/**
* Initialisation des données calculées non persistantes.
*/
@PostLoad
public void initializeTransientAttribute(){
if(null!=this.email){
this.gravatarHash = play.libs.Crypto.passwordHash(this.email);
}
}

/**
* simplified displayed string for List.
*/
public String toString(){
return this.username + " (" + this.firstname + " " + this.lastname +
")";
}

/**
* Find Method to implement user connection.
* @param email
* @param password
* @return
*/
public static User connect(String username, String password){
return User.find("byUsernameAndPassword",username,password).first();
}

/**
* check if user have Administrator profile.
* @return
*/
public boolean isRole(String role){
return role.equals(this.role.toString());
}


/**
* Encode Gravatar hash.
* @return
*/
public String getGravatarHash(){
return play.libs.Crypto.passwordHash(this.email.trim());
}
}


so, the Log produce by "Play run" :

Listening for transport dt_socket at address: 8000
23:45:06,980 INFO ~ Starting /home/frederic/Projects/Java/play/
myplayapp
23:45:06,984 INFO ~ Module secure is available (/home/frederic/Tools/
java/tools/play-1.1.1/modules/secure)
23:45:06,984 INFO ~ Module excel is available (/home/frederic/Tools/
java/tools/play-1.1.1/modules/excel-1.1)
23:45:06,985 INFO ~ Module crud is available (/home/frederic/Tools/
java/tools/play-1.1.1/modules/crud)
23:45:07,709 WARN ~ You're running Play! in DEV mode
23:45:07,793 INFO ~ Listening for HTTP on port 9000 (Waiting a first
request to start) ...
23:47:08,746 INFO ~ Connected to jdbc:hsqldb:file:/home/frederic/
Projects/Java/play/myplayapp/db/db
23:47:09,754 INFO ~ Application 'myplayapp' is now started !
23:47:10,734 ERROR ~

@65n7d122n
Internal Server Error (500) for request GET /

Execution exception (In /app/controllers/Application.java around line
33)
JPAQueryException occured : Error while executing query from
models.User where username = ?: org.hibernate.PropertyAccessException:
could not set a field value by reflection setter of models.User.avatar

play.exceptions.JavaExecutionException: Error while executing query
<strong>from models.User where username = ?</strong>:
org.hibernate.PropertyAccessException: could not set a field value by
reflection setter of models.User.avatar
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:290)
at Invocation.HTTP Request(Play!)
Caused by: play.db.jpa.JPABase$JPAQueryException: Error while
executing query <strong>from models.User where username = ?</strong>:
org.hibernate.PropertyAccessException: could not set a field value by
reflection setter of models.User.avatar
at play.db.jpa.GenericModel$JPAQuery.first(GenericModel.java:327)
at controllers.Application.setConnectedUser(Application.java:33)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:
413)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:
408)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:161)
... 1 more
Caused by: javax.persistence.PersistenceException:
org.hibernate.PropertyAccessException: could not set a field value by
reflection setter of models.User.avatar
at
org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:
1235)
at
org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:
1168)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:250)
at play.db.jpa.GenericModel$JPAQuery.first(GenericModel.java:321)
... 5 more
Caused by: org.hibernate.PropertyAccessException: could not set a
field value by reflection setter of models.User.avatar
at org.hibernate.property.DirectPropertyAccessor
$DirectSetter.set(DirectPropertyAccessor.java:151)
at
org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:
586)
at
org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:
231)
at
org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:
3824)
at
org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:
153)
at
org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:
898)
at org.hibernate.loader.Loader.doQuery(Loader.java:773)
at
org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:
270)
at org.hibernate.loader.Loader.doList(Loader.java:2449)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2192)
at org.hibernate.loader.Loader.list(Loader.java:2187)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:452)
at
org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:
363)
at
org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:
196)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1258)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:241)
... 6 more
Caused by: java.lang.IllegalArgumentException: Can not set
shared.Avatar field models.User.avatar to shared.Attachment
at org.hibernate.property.DirectPropertyAccessor
$DirectSetter.set(DirectPropertyAccessor.java:139)
... 22 more


Anybody have some idea about my error/mistake/misunderstood ?

Thanks in advance.

Fred.

Manuel Bernhardt

unread,
Mar 17, 2011, 5:50:09 AM3/17/11
to play-fr...@googlegroups.com, McGivrer
Just a guess: maybe Play did not generate the accessors for your
Avatar? Have you tried adding the getter and setter yourself in the
User class?

> --
> You received this message because you are subscribed to the Google Groups "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
>
>

McGivrer

unread,
Mar 19, 2011, 8:51:11 AM3/19/11
to play-framework
Hi, Manuel,

I've tried your proposed solution, but didn't work.

I had add setter and getter on the Avatar avatar attribute. but
without success :(

Execution exception (In /app/models/User.java around line 153)
JPAQueryException occured : Error while executing query from
models.User where username = ? AND password = ?:
org.hibernate.PropertyAccessException: could not set a field value by
reflection setter of models.User.avatar

play.exceptions.JavaExecutionException: Error while executing query
<strong>from models.User where username = ? AND password = ?</strong>:
org.hibernate.PropertyAccessException: could not set a field value by
reflection setter of models.User.avatar
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:290)
at Invocation.HTTP Request(Play!)
Caused by: play.db.jpa.JPABase$JPAQueryException: Error while
executing query <strong>from models.User where username = ? AND
password = ?</strong>: org.hibernate.PropertyAccessException: could
not set a field value by reflection setter of models.User.avatar
at play.db.jpa.GenericModel$JPAQuery.first(GenericModel.java:327)
at models.User.connect(User.java:153)
at controllers.Security.authenticate(Security.java:23)
at play.utils.Java.invokeStaticOrParent(Java.java:136)
at controllers.Secure$Security.invoke(Secure.java:185)
at controllers.Secure$Security.access$0(Secure.java:176)
at controllers.Secure.authenticate(Secure.java:64)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:
413)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:
408)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:182)
... 1 more
Caused by: javax.persistence.PersistenceException:
org.hibernate.PropertyAccessException: could not set a field value by
reflection setter of models.User.avatar
at
org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:
1235)
at
org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:
1168)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:250)
at play.db.jpa.GenericModel$JPAQuery.first(GenericModel.java:321)
... 10 more
... 11 more
Caused by: java.lang.IllegalArgumentException: Can not set
models.shared.Avatar field models.User.avatar to
models.shared.Attachment
at org.hibernate.property.DirectPropertyAccessor
$DirectSetter.set(DirectPropertyAccessor.java:139)
... 27 more


No success.

any idea ?

On Mar 17, 10:50 am, Manuel Bernhardt <bernhardt.man...@gmail.com>
wrote:
> >      ...
>
> read more »

Manuel Bernhardt

unread,
Mar 19, 2011, 10:19:27 AM3/19/11
to play-fr...@googlegroups.com, McGivrer
hi,

some more ideas:

- add a public default constructor to "Avatar" (it does not have one
at the moment it seems)

- it seems that the setter gets an Attachment instead of an Avatar:

> Caused by: java.lang.IllegalArgumentException: Can not set

> shared.Avatar field models.User.avatar to shared.Attachment
> at org.hibernate.property.DirectPropertyAccessor

not sure why that happens but it looks like a possible source of the issue.

Reply all
Reply to author
Forward
0 new messages