我有一个包含以下内容的挂毯5项目:


实体包中的一个抽象实体,由所有其他具体实体继承

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public class AbstractEntity implements Serializable, Comparable<AbstractEntity> {

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "ID")
protected Integer id;

@Override
public int compareTo(AbstractEntity o) {
     return this.toString().compareTo(o.toString());
}

}

继承AbstractEntity的几个具体实体(我会省略它们的大部分内容,因为我认为与这个问题完全无关,它们是简单的实体数据类)。一种此类实体类的示例:

//Imports go here

@Entity
@Table(name = "room")
@NamedQueries({
    @NamedQuery(name = "Room.findAll", query = "SELECT r FROM Room r")})
public class Room extends AbstractEntity {
    private static final long serialVersionUID = 1L;
    @Basic(optional = false)
    @Column(name = "ROOM_TYPE")
    @Validate("required")
    @Enumerated(EnumType.STRING)
    private RoomType roomType;
//rest of the attributes and their annotations go here, as well as setter/getter methods

通用DAO接口

import com.mycompany.myproject.entities.AbstractEntity;
import java.util.List;

public interface GenericDAO <T extends AbstractEntity>{

public abstract List<T> getListOfObjects(Class myclass);
public abstract T getObjectById(Integer id, Class myclass);
public abstract T addOrUpdate(T obj);
public abstract T delete(Integer id, Class myclass);

}

通用DAO接口的实现,使用Binder.bind在服务包的AppModule中将其绑定到该接口

import com.mycompany.myproject.entities.AbstractEntity;
import java.util.Collections;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

public class GenericDAOImpl<T extends AbstractEntity> implements GenericDAO<T> {

private Session session;

@Override
public List getListOfObjects(Class myclass) {
    List<T> list = session.createCriteria(myclass).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
    Collections.sort(list);
    return list;
}

@Override
public T getObjectById(Integer id, Class myclass) {
    AbstractEntity ae = (AbstractEntity) session.createCriteria(myclass)
        .add(Restrictions.eq("id", id)).list().get(0);
    return (T) ae;
}

@Override
public AbstractEntity addOrUpdate(AbstractEntity obj) {
    return (T) session.merge(obj);
}

@Override
public T delete(Integer id, Class myclass) {
    AbstractEntity ae = (AbstractEntity) session.createCriteria(myclass)
        .add(Restrictions.eq("id", id)).list().get(0);
    session.delete((T) ae);
    session.flush();
    return (T) ae;
}

}

组件包中的通用编辑器Java类

import com.mycompany.myproject.entities.AbstractEntity;
import com.mycompany.myproject.services.GenericDAO;
import java.util.List;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.beaneditor.BeanModel;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.BeanModelSource;
import org.apache.tapestry5.services.PropertyConduitSource;

public class GenericEditor<T extends AbstractEntity> {

@Inject
private PropertyConduitSource conduit;
@Inject
private GenericDAO genericDAO;
@Property
@Persist
private T bean;
@Property
private T row;
@Inject
private BeanModelSource bms;
@Inject
private ComponentResources cr;

private Class myclass;

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

public List<T> getGrid(){
    List<T> temp = genericDAO.getListOfObjects(myclass);
    return temp;
}

public BeanModel<T> getFormModel(){
    return bms.createEditModel(myclass, cr.getMessages()).exclude("id");
}

public BeanModel<T> getGridModel(){
    return bms.createDisplayModel(myclass, cr.getMessages()).exclude("id");
}

@CommitAfter
Object onActionFromDelete(int id){
    genericDAO.delete(id, myclass);
    return this;
}

@CommitAfter
Object onActionFromEdit(int row){
    bean = (T)genericDAO.getObjectById(row, myclass);
    return this;
}

@CommitAfter
Object onSuccess(){
    genericDAO.addOrUpdate(bean);
    try {
        bean = (T) myclass.newInstance();
    } catch(Exception ex){
    }
    return this;
}

GenericEditor Java类的关联的.tml文件

<!--GenericEditor.tml-->
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
    <t:beaneditform object="bean" t:model="formModel" >
    </t:beaneditform>
    <t:grid t:source="grid" t:model="gridModel" add="edit,delete" row="row">
        <p:editCell>
            <t:actionlink t:id="edit" context="row">Edit</t:actionlink>
        </p:editCell>
        <p:deleteCell>
            <t:actionlink t:id="delete" context="row">Delete</t:actionlink>
        </p:deleteCell>
    </t:grid>
</html>

此外,页面包中还有几个Java类及其关联的.tml文件,这些类最初是在不使用genericDAO的情况下制作的,但是使用了具体的DAO,因此它们看起来像这样(其中一个示例):

import com.mycompany.myproject.entities.Room;
import com.mycompany.myproject.services.RoomDAO;
import java.util.ArrayList;
import java.util.List;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;

public class RoomPage {

    @Property
    private Room room;
    @Property
    private Room roomrow;
    @Inject
    private RoomDAO roomDAO;

    @Property
    private List<Room> rooms;


    void onActivate(){
        if(rooms==null){
            rooms = new ArrayList<Room>();
        }
        rooms = roomDAO.getListOfRooms();
    }

    @CommitAfter
    Object onSuccess(){
        roomDAO.addOrUpdateRoom(room);
        room = new Room();
        return this;
    }

    @CommitAfter
    Object onActionFromEdit(Room room2){
        room = room2;
        return this;
    }

    @CommitAfter
    Object onActionFromDelete(int id){
        roomDAO.deleteRoom(id);
        return this;
    }

}

以及相关的.tml文件:

<!--RoomPage.tml-->
<html t:type="layout" title="RoomPage"
      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
      xmlns:p="tapestry:parameter">
    <div class="row">

        <div class="col-sm-4 col-md-4 col-lg-3">
            <t:beaneditform object="room" exclude="id" reorder="roomtype, floor,
                    tv, internet"
                    submitlabel="message:submit-label"/>
        </div>
        <div class="col-sm-8 col-md-8 col-lg-9">
            <t:grid t:source="rooms" exclude="id"
            add="edit,delete" row="roomrow"
            include="roomtype, floor, tv, internet">
                <p:editCell>
                    <t:actionlink t:id="edit" context="roomrow">Edit</t:actionlink>
                </p:editCell>
                <p:deleteCell>
                    <t:actionlink t:id="delete" context="roomrow.id">Delete</t:actionlink>
                </p:deleteCell>
            </t:grid>
        </div>
    </div>
</html>



上面使用具体DAO的代码可以正常工作,在数据库中按预期显示用于在数据库中输入新行的表单,以及带有数据库表中行的网格。

因此,基本思想是将GenericEditor与genericDAO一起使用,以减少所需的代码量并处理任何数据库表,使用BeanEditForm在表中输入新行,并使用Grid来显示表中的所有行,删除或编辑它们。从理论上讲,这应该对继承AbstractEntity类的任何实体都适用,因此不需要为每个实体创建单独的DAO接口/实现对。

问题是,我似乎无法按预期工作,因为我不确定如何实际使用上面显示的G​​enericEditor。我尝试了以下操作:


修改后的RoomPage.java:

import com.mycompany.myproject.components.GenericEditor;
import com.mycompany.myproject.entities.Room;

public class RoomPage{

    @Component
    private GenericEditor<Room> ge;

}

修改后的RoomPage.tml:

<!--RoomPage.tml-->
<html t:type="layout" title="RoomPage"
      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
      xmlns:p="tapestry:parameter">
<t:GenericEditor t:id="ge" />
</html>



但这显然不起作用,因为它产生的只是一个空指针异常以及此错误:


Blockquote [ERROR]页面。RoomPageSetupRender [RoomPage:ge.grid]中的呈现队列错误:无法读取组件RoomPage:ge.grid的参数“源”:org.apache.tapestry5.ioc.internal.util.TapestryException
org.apache.tapestry5.ioc.internal.util.TapestryException:读取组件RoomPage:ge.grid的参数“源”失败:org.apache.tapestry5.ioc.internal.util.TapestryException [at classpath:com / mycompany / myproject /components/GenericEditor.tml,第5行]


然后,我尝试完全删除grid元素,并仅使用BeanEditForm运行GenericEditor。这实际上导致了页面的加载,但是并未在页面上显示预期的表单,而是在页面末尾显示了Room实体和“创建/更新”按钮的字段,而出现的只是“创建/更新”按钮,没有任何字段,就好像BeanEditForm是在没有任何属性的对象上创建的。按下创建/更新按钮会创建另一个空指针异常。

出于调试目的,我将GenericEditor.java更改为以非通用方式工作,方法是在其中创建通用类型T的另一个属性,然后将其初始化为Room类型的新对象,强制转换为(T),并然后声明属性类与room属性的类型相同,如下所示

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


通过这些更改运行应用程序(仍禁用网格并仅启用beaneditform),页面现在可以正确呈现所有输入字段。这使我得出结论,问题在于GenericEditor无法通过泛型接收正确的类型,但是我不知道我的逻辑是否正确,即使是正确的,也不知道如何解决此问题。问题的另一个可能原因可能是PropertyConduit,我不确定它的工作方式是否正确,以及是否正确使用了它,因此我不排除问题是否也源于此。
无论哪种方式,我的主要猜测是我以某种方式滥用了GenericEditor,因此如该问题的标题所述,我应该如何使用GenericEditor来正确访问数据库?

我已经在stackoverflow上搜索了与自己类似的问题,但是无论在这里还是在其他地方,我都找不到类似的问题。我希望这里的某人能够帮助我确定问题所在并帮助我解决问题,因为我真的不知道如何独自解决。提前致谢。

更新:
通过尝试检查将哪种类型的类转发给GenericEditor的myclass,我进行了一些进一步的调试。我修改了GenericEditor.java的以下位:

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


以下:

    {
        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());
    }


这导致了以下输出:


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

pipe1.getPropertyType()。toString():类com.mycompany.myproject.entities.AbstractEntity

pipe1.getPropertyType()。getName():com.mycompany.myproject.entities.AbstractEntity

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


我认为这几乎意味着转发给GenericEditor的T类型是AbstractEntity,而不是预期的Room。如果我的假设是正确的,那么我会滥用GenericEditor,因为我没有通过泛型将适当的类转发给它,那么我应该如何将适当的类转发给它呢?还是我的假设是错误的,这里还有其他问题吗?

最佳答案

我已经设法找到了这个问题的答案,所以我把它张贴在这里,以防万一有人需要它:

应用程序无法按预期运行的原因有两个:
1)在GenericDAOImpl类中,我忘了在“私有会话会话”行上方添加@Inject批注,该批注首先产生了错误,因此该段代码应如下所示:

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


2)首先我不确定的是如何使用GenericEditor组件,而我试图通过将组件添加到类文件和关联的tml文件中来以错误的方式使用它。相反,应该做的只是简单地扩展GenericEditor,并删除关联的tml文件,因此使用GenericEditor tml,如下所示:

public class RoomPage extends GenericEditor<Room>{
}


进行这两项更改后,该应用程序将按预期工作

10-05 18:56