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

本文通过一个具体的例子详细介绍了使用 Ebean ORM 框架时遇到的 findPagedList() 抛出 IllegalStateException 的问题及解决步骤。从实体类定义到实现 EntityBean 接口,再到正确设置_ebean_props字段和_ebean_getIntercept()方法,最终实现了数据的正常获取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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方法不能是空实现

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值