OpenJpa - Incomprehensible exception creating a named-native-query

Go To StackoverFlow.com

2

OpenJPA 1.2.2, WebSphere 7 (Java EE 5)

I'm trying to map a table to a POJO (Not entity !) using a named-native-query defined in orm.xml:

<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>

The PojoBean is a final class with String getter/setters and empty-argument constructor:

public final class PojoBean implements java.io.Serializable {

    public PojoBean() {
    }

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

When I create the query:

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

I got an exception (Formatted for readability):

<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.

What does it means ?

More info:

  • The implementation of PojoBean cannot be changed and as final class cannot also be extended.
  • Running the query from java using EntityManager.createNativeQuery(...) works, but it's not an option.

Thank you,

2012-04-04 08:15
by Giambo
Do you have an abigious setter? Something like setValue(String val) setVatue(Integer val). If your query returns null it may be abigiuos, which setter should be called - Christian Kuetbach 2012-04-04 09:29
There are no ambiguous setters. If I code the query on Java (EntityManager.createNativeQuery(...)) instead of using orm.xml it works - Giambo 2012-04-04 10:36
For giggles, can you try making your POJO non-final? Also, your orm snippet shows that your query is a native query, why aren't you calling createNativeQuery(...) - Rick 2012-04-04 11:34
I also tried setting the POPJO non-final, no luck. I don't want to use createNativeQuery(...): The queries are stored in orm.xml and are called based on some parameters ("Convention over configuration" - Giambo 2012-04-04 13:08


0

You may want to make sure that the class PojoBean in the deployed JAR actually has the public setters & getters.

2012-04-04 09:26
by Samarth Bhargava
Getter/Setters are public. If I manualy add a generic "put(Object,Object)" method as suggested in the exception, it seems to work, but this solution is not acceptable - Giambo 2012-04-04 10:58
Can you check that you have not used primitives(int,long etc) in the Bean. JPA might be facing problems setting null -'for the projection or aggregate result element "null" - Samarth Bhargava 2012-04-04 11:22
No primitives, the bean uses only String. Also the columns in the database (Oracle) are defined as VARCHAR2 - Giambo 2012-04-04 11:32
Something is definitely being returned as null from the query. Maybe you can run the same query on the SQL prompt and see what is 'null'. OpenJPA is having a problem setting the 'null - Samarth Bhargava 2012-04-04 12:05
Even using values known to be not-null (Primary keys) didn't solve the problem. The only way is to implement a dummy (Empty) "put(Object, Object)" method that won't even be called. But that's not a solution, I cannot modify the POJOs : - Giambo 2012-04-04 13:14


0

I got the same exception. The problem in my case was, that in the persistence.xml the persistence-unit name was wrong. In this case, the excpetion does not exactly point in the correct direction...

2015-01-30 11:44
by Rudolf Pailer


0

The problem is that openJPA does not auto-map underscore_names to cameCaseName, so you have to provide to translate in order to fill your POJO.

In your case col_one => colOne, but openJPA does not know that.

What I did was to implement the generic setter that assigns the value to corresponding field via reflection, with a little help from Google Guava for string transformation:

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

}

I must say that I don't like this solution very much, but it work's really good. Is there a way to implement some interface or use an @Annotation to wire this up?

Another way is with an abstract class that every pojo extends. In that case you should go for the setter method because the field could be private.

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

    }   
}
2015-02-20 07:30
by Jmakuc
Ads