hakandilek / play2-crud

Simple CRUD & DAO implementation for play2
Other
142 stars 52 forks source link

Wrong Parameter type for the editForm method #43

Closed gbersac closed 10 years ago

gbersac commented 10 years ago

Issue description

When I call to the address : http://localhost:9000/app/User/3/edit I get an error about wrong parameter type for method execution. The exeception has been send from the line 97 of TemplateController.java (in the call method) :

result = ReflectionUtils.invokeMethod(method, null, paramValues);

Hypothesis

This is probably a problem of cast of the string in the url to the generic type K of the CRUDController. RouterController.editForm(String name, String key) is call in the route and its argument key is cast implicitly to the type K while relay to ControllerProxyCRUD.editForm(key). This is not throwing any exception at this moment, but it seems like a lack of correct cast come to fame while used in the TemplateController.call function.

The strange thing is that, if I type the url http://localhost:9000/app/User/3/delete, the deletion work fine while the same cast procedure (ie: no procedure) is processed.

Workaround

!!!Warning: ugly code!!!

I have a class User which inherit a class MyCrudController<Long, User> which extend CRUDController<Long, User>. The idea is to render the form independently of the crudPlay plugin, so that I can have my own cast engine (which is very ugly):

new Long(key.toString())

This few words solve the entire problem !

User.java

public class UserCtr extends MyCrudController<Long, User>
{
    @Inject
    public UserCtr(models.User.Dao dao)
    {
        super(dao, Long.class, User.class);
    }

    private static CrudForm<User> form = null;

    public static FormOptions<User> getFormOptions(Long _id, Form<User> _form)
    {
        if (form == null)
        {
            form = new CrudForm<User>(User.class, "UserCtr.createTitle", "UserCtr.createTitle");
        }
        User logUser = Login.getLogUser();
        return form.getOptions(_id, logUser, _form);
    }
        [...]
}

MyCrudController.java

/**
 * The K generic type must be of type Long.
 * Stating it statically in the definition of the class (ie: extends CRUDController<Long, M>)
 * is throwing exception.
 */
@With(misc.LoginAction.class)
public abstract class MyCrudController<K, M extends BasicModel<K>> extends CRUDController<K, M>
{
        //This fields are private in the CRUDController, so I redefine them
    protected String        className;
    protected Class<M>      myModelClass;
    protected Class<K>      myKeyClass;
    private final DAO<K, M> myDao;

    @Inject
    public MyCrudController(DAO<K, M> dao, Class<K> keyClass, Class<M> modelClass)
    {
        super(dao, Form.form(modelClass), keyClass,
                modelClass, 10, "id" + modelClass.getSimpleName());
        className = modelClass.getSimpleName();
        myModelClass = modelClass;
        myKeyClass = keyClass;
        myDao = dao;
    }

    @Override
    protected Call                  toIndex()
    {
        return controllers.routes.Application.index();
    }

    @Override
    public Result                   editForm(K key)
    {
        Form<M> sendForm = Form.form(myModelClass);
        M toUpdate = myDao.get(key);
        if (toUpdate == null){
            String msg = "Can't found with id : " + key;
            play.Logger.error(msg);
            ListInfo.addMessage(msg, ListInfo.InfoType.ERROR);
            return ok(msg);
        }
        sendForm = sendForm.fill(toUpdate);
        //      return super.editForm(key);
        return formRenderMethod(key, sendForm);
    }

    /**
     * Function which render and return the form independently of the crudPlay
     * plugin.
     * @return
     */
    private Result                  formRenderMethod(K key, Form<M> form)
    {
        Method      method;

        try{
            Class<?> template = Class.forName("views.html." + templateForForm());
            method = template.getMethod("render", myKeyClass, Form.class);
            Logger.debug("key: " + key.toString());
                        //here is the magic cast !
            return ok((Content) method.invoke(template, new Long(key.toString()), form));
        }catch(Throwable e){
            Logger.error(e.getMessage());
        }
        return null;
    }

    protected String                templateForForm()
    {
        return className.toLowerCase() + "Form";
    }
        [...]
}

And this is de dao. I don't know what is the utility of that class, but I know it is involved in the process of getting a Model instance out of a key. In case it is helpful.

public class User extends Model implements BasicModel<Long>
{
        [...]

    public static class Dao extends BasicDAO<Long, User> {
        @Inject
        public Dao() {
            super(Long.class, User.class);
        }
    }
}
dgmagno commented 10 years ago

I reported a bug ( #33 ) related to your problem. Are you using the latest version of this plugin?

gbersac commented 10 years ago

Hi,

I am using the last commit :

commit b629c853814a451817a93d72ebef536b5861bf5a
Merge: 9383e36 890b963
Author: Hakan Dilek <hakandilek@users.noreply.github.com>
Date:   Tue Jul 22 20:34:10 2014 +0200

    Merge pull request #40 from pablo/master
gbersac commented 10 years ago

I am not able to reproduce the problem anymore. Maybe I was still using the old version.

Thanks for your help.