OpenJpa - 创建命名本机查询的难以理解的异常

时间:2012-04-04 08:15:58

标签: java openjpa

OpenJPA 1.2.2,WebSphere 7(Java EE 5)

我正在尝试使用orm.xml中定义的named-native-query将表映射到POJO(非实体!):

<named-native-query name="myNativeQuery" result-class="foo.bar.PojoBean">
    <query>
        SELECT col_one AS colOne, col_two AS colTwo, col_three AS colThree 
        FROM myTable WHERE id = 42
    </query>
</named-native-query>

PojoBean是一个带有String getter / setters和empty-argument构造函数的final类:

public final class PojoBean implements java.io.Serializable {

    public PojoBean() {
    }

    public String getColOne() { ... }
    public void setColOne(String colOne) { ... }
    ...
}

创建查询时:

EntityManager myEntityManager = ...
myEntityManager.createNamedQuery("myNativeQuery");

我有一个例外(格式化的可读性):

<openjpa-1.2.2-r422266:898935 nonfatal user error>  
org.apache.openjpa.persistence.ArgumentException: 
Result type "class foo.bar.PojoBean" does not have any public fields or setter methods for the projection or aggregate result element "null", 
nor does it have a generic put(Object,Object) method that can be used, 
nor does it have a public constructor that takes the types null.

这意味着什么?

更多信息:

  • 无法更改PojoBean的实现,也无法扩展最终类。
  • 使用EntityManager.createNativeQuery(...)从java运行查询有效,但它不是一个选项。

谢谢,

3 个答案:

答案 0 :(得分:0)

您可能希望确保已部署的JAR中的类PojoBean实际上具有公共setter&amp;吸气剂。

答案 1 :(得分:0)

我得到了同样的例外。我的问题是,在persistence.xml中,持久性单元名称是错误的。在这种情况下,激发并没有完全指向正确的方向......

答案 2 :(得分:0)

问题是openJPA不会将underscore_names自动映射到cameCaseName,因此必须提供翻译以填充您的POJO。

在你的情况下col_one =&gt; colOne,但openJPA不知道。

我所做的是实现通用反射器将值分配给相应字段的通用setter,并在Google Guava的帮助下进行字符串转换:

public void put(Object field, Object value) {

    try {

        String fieldName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, field.toString());
        Field f = this.getClass().getDeclaredField(fieldName);
        f.set(this, value);

    }
    catch(Exception e) {
        logger.error("ERROR: " + e.getMessage());
    }

}

我必须说我不太喜欢这个解决方案,但它的工作非常好。有没有办法实现某个接口或使用@Annotation连接它?

另一种方法是使用每个pojo扩展的抽象类。在这种情况下,您应该使用setter方法,因为该字段可能是私有的。

public abstract class JpaPutter  {


    public void put(Object field, Object value) {

        try {

            String methodName = "set" + CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, field.toString());
            this.getClass().getMethod(methodName, value.getClass()).invoke(this,  value);

        }
        catch(Exception e) {
            throw new RuntimeException(e);
        }

    }   
}