FoxEM
FoxEM

Reputation: 11

How to use a generic editor for database access in tapestry 5?

I have a tapestry 5 project that contains the following:

The code above using concrete DAO works properly, a form for inputting new rows in the database appears on the page as expected, as well as the grid with rows from the database table.

So, the basic idea was to use the GenericEditor together with genericDAO in order to reduce the amount of code necessary and manipulate any of the database tables, using the BeanEditForm to input new rows in the table and Grid to show all rows from the table and delete or edit them. In theory, this should work for any entity that inherits the AbstractEntity class, so there wouldn't be a need to make a separate DAO interface/implementation pairing for each entity.

The problem is, I can't seem to get this to work as intended, as I'm not sure how to actually use the GenericEditor shown above. I have attempted the following:

But that apparently does not work, as all it yielded was a null pointer exception as well as this error:

Blockquote [ERROR] pages.RoomPage Render queue error in SetupRender[RoomPage:ge.grid]: Failure reading parameter 'source' of component RoomPage:ge.grid: org.apache.tapestry5.ioc.internal.util.TapestryException org.apache.tapestry5.ioc.internal.util.TapestryException: Failure reading parameter 'source' of component RoomPage:ge.grid: org.apache.tapestry5.ioc.internal.util.TapestryException [at classpath:com/mycompany/myproject/components/GenericEditor.tml, line 5]

I have then tried to remove the grid element entirely, and run the GenericEditor with BeanEditForm only. This has resulted in the page actually loading, but instead of showing an expected Form on the page, with the fields of the Room entity and the Create/Update button at the end of the form, all that appeared was the Create/Update button, without any field, as if the BeanEditForm was created on an object without any attributes. Pressing the Create/Update button creates another null pointer exception.

For debugging purposes, I have changed GenericEditor.java to work in a non-generic way, by creating another attribute of the generic type T in it, and then initializing it as a new object of type Room, casted as (T), and then declaring attribute class to be of the same type as the room attribute, as seen bellow

private T room; 
{
    //PropertyConduit conduit1 = conduit.create(getClass(), "bean");
    //class = conduit1.getPropertyType();
    room = (T) new Room();
    class = room.getClass();
}

Running the application with these changes (with grid still disabled and only beaneditform enabled), the page now renders all the input fields correctly. This has led me to conclusion that the problem lies within the fact that the GenericEditor does not receive the proper type through the generic, but I do not know if my logic is correct, and even if it is, how to get around this issue. Another possible source of the problem might be the PropertyConduit, I am not sure how it works exactly, and if I'm using it correctly or not, so I'm not ruling out that the issue originates there as well. Either way, my main guess is that I'm misusing the GenericEditor somehow, so as the title of this question says, how am I supposed to use the GenericEditor in order to access database properly with it?

I have searched stackoverflow for similar problems to my own but I have been unable to find anything similar, neither here nor elsewhere. I am hoping that someone here will be able to help me to identify what the issue is and help me get around it, as I really have no idea how to do so on my own. Thanks in advance.

Update: I have done some further debugging, by trying to check what type of class gets forwarded to GenericEditor's myclass. I have modified the following bit of GenericEditor.java:

    {
        PropertyConduit conduit1 = conduit.create(getClass(), "bean");
        myclass = conduit1.getPropertyType();
    }

to following:

    {
        PropertyConduit conduit1 = conduit.create(getClass(), "bean");
        System.out.println("conduit1.toString(): "+conduit1.toString());
        System.out.println("conduit1.getPropertyType().toString(): "+conduit1.getPropertyType().toString());
        System.out.println("conduit1.getPropertyType().getName(): "+conduit1.getPropertyType().getName());
        myclass = conduit1.getPropertyType();
        System.out.println("myclass.getName(): "+myclass.getName());
    }

and this has resulted in the following output:

conduit1.toString(): PropertyConduit[com.mycompany.myproject.components.GenericEditor bean]

conduit1.getPropertyType().toString(): class com.mycompany.myproject.entities.AbstractEntity

conduit1.getPropertyType().getName(): com.mycompany.myproject.entities.AbstractEntity

myclass.getName(): com.mycompany.myproject.entities.AbstractEntity

Which I believe pretty much means that type T forwarded to the GenericEditor is AbstractEntity, not Room as intended. If my assumption is correct, I'm misusing the GenericEditor as I'm not getting the proper class forwarded to it via generics, so how am I supposed to forward the proper class to it? Or is my assumption wrong and something else is amiss here?

Upvotes: -1

Views: 610

Answers (2)

FoxEM
FoxEM

Reputation: 11

I've managed to find an answer to this question, so I'm posting it here in case anyone ever needs it:

There were 2 reasons why the application did not work as intended: 1) In the GenericDAOImpl class, I've forgot to add the @Inject annotation above the "private Session session" line, which yielded the error in the first place so that piece of code should have looked like this:

//imports
public class GenericDAOImpl<T extends AbstractEntity> implements GenericDAO<T> {
@Inject
private Session session;
//rest of code unchanged

2) the very thing I was unsure about in the first place was how to use the GenericEditor component, and I was trying to do so in the wrong way, by trying to add the component into the class file and the associated tml file. What was supposed to be done instead was to simply extend GenericEditor, and delete the associated tml file, so the GenericEditor tml is used instead, like this:

public class RoomPage extends GenericEditor<Room>{
}

Upon making these 2 changes, the application works as intended

Upvotes: 1

lance-java
lance-java

Reputation: 28099

I've never used it myself but you might be interested in tynamo's tapestry-model which i understand helps with generic CRUD.

Upvotes: 0

Related Questions