Ebean findPagedList() throw Exception的分析处理过程

来源:互联网 发布:变频器仿真软件 编辑:程序博客网 时间:2024/05/18 20:08

Ebean findPagedList() throw Exception的分析处理过程


一、定义User

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name = "t_user")public class User {    @Id    private String id;    @Column    private String username;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }}

二、执行测试

    @Test    public void testFindPageList() {        Query<User> find = Ebean.find(User.class);        find.setMaxRows(1);        find.setFirstRow(1);        System.out.println(find.findPagedList().getList());    }

抛出Exception:Caused by: java.lang.IllegalStateException: Bean class User is not enhanced?


三、分析过程

step1

进入BeanDescriptorManager.java:1442查看错误处,看到抛出Exception这里有个hasEntityBeanInterface的校验:


进入到hasEntityBeanInterface方法,源码如下:

private boolean hasEntityBeanInterface(Class<?> beanClass) {    Class<?>[] interfaces = beanClass.getInterfaces();    Class[] var3 = interfaces;    int var4 = interfaces.length;    for(int var5 = 0; var5 < var4; ++var5) {        Class<?> anInterface = var3[var5];        if (anInterface.equals(EntityBean.class)) {            return true;        }    }    return false;}
由此可知,Entity Bean必须实现一个EntityBean的接口(在网上看到的都没有实现这个接口和集成Model的,不知道是版本问题还是用的方式不对

step2

User实现EntityBean接口:

import io.ebean.bean.EntityBean;import io.ebean.bean.EntityBeanIntercept;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;import java.beans.PropertyChangeListener;@Entity@Table(name = "t_user")public class User implements EntityBean {    @Id    private String id;    @Column    private String username;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String[] _ebean_getPropertyNames() {        return new String[0];    }    public String _ebean_getPropertyName(int i) {        return null;    }    public String _ebean_getMarker() {        return null;    }    public Object _ebean_newInstance() {        return null;    }    public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {    }    public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener) {    }    public void _ebean_setEmbeddedLoaded() {    }    public boolean _ebean_isEmbeddedNewOrDirty() {        return false;    }    public EntityBeanIntercept _ebean_getIntercept() {        return null;    }    public EntityBeanIntercept _ebean_intercept() {        return null;    }    public void _ebean_setField(int i, Object o) {    }    public void _ebean_setFieldIntercept(int i, Object o) {    }    public Object _ebean_getField(int i) {        return null;    }    public Object _ebean_getFieldIntercept(int i) {        return null;    }}
执行测试,抛出Exception:


进入BeanPropertiesReader.java:43查看错误处,看到getProperties源码如下:

private String[] getProperties(Class<?> clazz) {    try {        Field field = clazz.getField("_ebean_props");        return (String[])((String[])field.get((Object)null));    } catch (Exception var3) {        throw new IllegalStateException("Error getting _ebean_props field on type " + clazz, var3);    }}
这里获取一个public static_ebean_props字段,因为这个字段存储的是当前实体类(User)对应数据库的字段,所以用field.get((Object)null)来限制该字段必须是public static字段。


step3

增加_ebean_props字段后,再次执行测试,抛出Exception:

进入到BeanDescriptor.java:523查看错误处,看到如下代码(这里的_ebean_getIntercept()就是User实现的EntityBean_ebean_getIntercept()):

            EntityBeanIntercept ebi = this.prototypeEntityBean._ebean_getIntercept();            this.idPropertyIndex = this.idProperty == null ? -1 : ebi.findProperty(this.idProperty.getName());


step4

重写User中的_ebean_getIntercept()

    public EntityBeanIntercept _ebean_getIntercept() {        return new EntityBeanIntercept(this);    }
执行测试,发现结果字段值均为null:



step5

Debugger跟踪源码运行,发现设置属性值的方法在EnhanceBeanPropertyAccess.Setter.set(...)方法中会调用实体类的_ebean_setField(...)方法对属性进行赋值操作(即赋值操作由EntityBean._ebean_setField(...)方法完成)。

重写User_ebean_setField方法:

public void _ebean_setField(int i, Object o) {    try {        Field field = this.getClass().getDeclaredField(get_ebean_props()[i]);        field.setAccessible(true);        field.set(this, o);    } catch (Exception e) {        e.printStackTrace();    }}
执行测试,运行结果如下:


四、整理后的代码

定义AbstractEntityBean,实现EntityBean接口:

import io.ebean.bean.EntityBean;import io.ebean.bean.EntityBeanIntercept;import java.beans.PropertyChangeListener;import java.lang.reflect.Field;public abstract class AbstractEntityBean implements EntityBean {    // 因为每个实体类都需要一个静态的_ebean_props属性,所以这里定义一个方法获取这个静态属性方便下面的代码调用    public abstract String[] get_ebean_props();    public String[] _ebean_getPropertyNames() {        return get_ebean_props();    }    public String _ebean_getPropertyName(int i) {        return null;    }    public String _ebean_getMarker() {        return null;    }    public abstract Object _ebean_newInstance();    public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {    }    public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener) {    }    public void _ebean_setEmbeddedLoaded() {    }    public boolean _ebean_isEmbeddedNewOrDirty() {        return false;    }    public EntityBeanIntercept _ebean_getIntercept() {        return new EntityBeanIntercept(this);    }    public EntityBeanIntercept _ebean_intercept() {        return null;    }    public void _ebean_setField(int i, Object o) {        try {            Field field = this.getClass().getDeclaredField(get_ebean_props()[i]);            field.setAccessible(true);            field.set(this, o);        } catch (Exception e) {            e.printStackTrace();        }    }    public void _ebean_setFieldIntercept(int i, Object o) {    }    public Object _ebean_getField(int i) {        return null;    }    public Object _ebean_getFieldIntercept(int i) {        return null;    }}

修改User,继承AbstractEntityBean,实现EntityBean接口(因为Class.getInterfaces()只能获取到当前类实现的接口,所以这里再实现一次):

import io.ebean.bean.EntityBean;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name = "t_user")public class User extends AbstractEntityBean implements EntityBean {    public static String[] _ebean_props = new String[] {"id", "username"};    @Id    @Column(name = "id")    private String id;    @Column    private String username;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    @Override    public String[] get_ebean_props() {        return _ebean_props;    }    @Override    public Object _ebean_newInstance() {        return new User();    }    @Override    public String toString() {        return "User{" +                "id='" + id + '\'' +                ", username='" + username + '\'' +                '}';    }}

测试代码TestDBConnection

import io.ebean.Ebean;import io.ebean.Query;import org.junit.Test;public class TestDBConnection {    @Test    public void test() {        System.out.println("cnt : " + Ebean                .createSqlQuery("select count(0) as cnt from t_user").findOne()                .getInteger("cnt"));    }    @Test    public void testFindPageList() {        Query<User> find = Ebean.find(User.class);        find.setMaxRows(1);        find.setFirstRow(1);        System.out.println(find.findPagedList().getList());    }}

五、总结

这种不与其他框架集成的方式:

  • 实体类需要实现EntityBean接口
  • 实体类需要有一个public static_ebean_props字段存储查询的字段名
  • 实体类中的_ebean_getIntercept()返回值不能为null(即不能是空实现)
  • 查询数据后Ebean会调用_ebean_setField方法为属性赋值,实体类中的_ebean_setField方法不能是空实现

原创粉丝点击