3

I have a problem with generated static metamodel classes in EclipseLink. In my project I firstly generated static metamodel classed for my entities using:

1) org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor and IntelliJ IDEA and this classes have been generated to: target/generated-sources

Then I try to use such Hibernate generated metamodel classes (ex. below) with EclipseLink (GlassFish embedded), but lines of code that contains references to metamodel attributes throws NullPointerException exception:

 SingularAttribute<Employee, String> descriptionAttr = Employee_.description;
 predicates.add(criteriaBuilder.like(employee.get(descriptionAttr), "%" + description + "%"));

Here emploee.get( >> null << ) throws exception.

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Employee.class)
public abstract class Employee_ extends pl.salonea.entities.NaturalPerson_ {

    public static volatile SetAttribute<Employee, Skill> skills;
    public static volatile SetAttribute<Employee, ProviderService> suppliedServices;
    public static volatile SetAttribute<Employee, EmployeeRating> receivedRatings;
    public static volatile SingularAttribute<Employee, String> description;
    public static volatile SetAttribute<Employee, Education> educations;
    public static volatile SingularAttribute<Employee, String> jobPosition;
    public static volatile SetAttribute<Employee, TermEmployeeWorkOn> termsOnWorkStation;

}

2) Next I thought that this metamodel classes maybe are implementation specific. So I generated them analogically with EclipseLink using org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor and target/generated-sources-eclipselink (as on picture)

IntelliJ IDEA EclipseLink static metamodel generation

At the end I have something like this directory stracture with metamodel:

enter image description here

3) I am also using in build.gradle such configuration to as I think include this generated sources in project:

if(hasProperty('jboss')) {
    sourceSets {
        main {
            java {
                srcDir 'target/generated-sources/'
            }
        }
    }
} else {
    sourceSets {
        main {
            java {
                srcDir 'target/generated-sources-eclipselink/'
            }
        }
    }
}

This way I want to use Hibernate generated classes with Jboss and EclipseLink generated classes with EclipseLink.

4) Such configuration works only if running on WilfFly/Hibernate but not on GlassFish/EclipseLink here is this NullPointerException

5) In persistence.xml I have more over EclipseLink generation using such property for one Persistence Unit

<property name="eclipselink.canonicalmodel.subpackage" value="metamodel" />

and such property for second Persistence Unit (to avoid duplicate conflict)

<property name="eclipselink.canonicalmodel.subpackage" value="metamodel_local" />

But I'm trying not to use this generation. It is in subpackage and in my code I only import previously generated metamodel classes. The reason is that I would like to have in the same namespace metamodel classes generated by Hibernate/Eclipse and use them appropriately. However if Hibernate generated metamodel classes could be also work with EclipseLink there won't be problem to using only one generation.

6) Moreover I cant use metamodel classes generated by EclipseLink persistence.xml property as they are regenerated each time I run/build my project. And I need in my code to manually modify two metamodel classes as they are inherited from single abstract metamodel class. Here I am overriding in subclasses AbstractType with ConcreteType on SetAttribute of metamodel class.

7) At the end I paste error I'm getting while running integration test with such configuration of metamodel classes

 Caused by: java.lang.NullPointerException
    at org.eclipse.persistence.internal.jpa.querydef.FromImpl.get(FromImpl.java:263)
    at pl.salonea.ejb.stateless.EmployeeFacade.findByMultipleCriteria(EmployeeFacade.java:295)
    at pl.salonea.ejb.stateless.EmployeeFacade.findByMultipleCriteria(EmployeeFacade.java:269)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081)
    at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153)
    at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4786)
    at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:656)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
    at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:46)
    at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:52)
    at sun.reflect.GeneratedMethodAccessor113.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:140)
    at sun.reflect.GeneratedMethodAccessor141.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
    at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:369)
    at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:4758)
    at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4746)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
    ... 149 more
Michał Ziobro
  • 10,759
  • 11
  • 88
  • 143

3 Answers3

2

-I'm checking EclipseLink sources:

public <Y> Path<Y> get(SingularAttribute<? super X, Y> att){
    if (att.getPersistentAttributeType().equals(
            PersistentAttributeType.BASIC)) {
        return new PathImpl<Y>(
                this, this.metamodel, att.getBindableJavaType(),
                this.currentNode.get(att.getName()), att);
    } else {
        Class<Y> clazz = att.getBindableJavaType();
        Join join = new JoinImpl<X, Y>(
                this, this.metamodel.managedType(clazz),
                this.metamodel, clazz,
                this.currentNode.get(att.getName()), att);
        this.joins.add(join);
        return join;
    }
}

FromImpl.java:263 is condition of if statement so it looks like att.getPersistentAttributeType() returns null.

It would be good if you'll file a bug against EclipseLink on https://bugs.eclipse.org/bugs/enter_bug.cgi?product=EclipseLink Component is JPA. Please copy-paste this description there and provide some test-case (sample application with this metamodel) to let us reproduce it and develop some fix.

Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
Tomas Kraus
  • 466
  • 2
  • 6
0

The problem can be in the failed initialization Canonical Metamodel. You can investigate yours eclipselink log for checking something like that:

Could not load the field named [...] on the class [...]
IllegalArgumentException: Can not set static ... field ... to ...

In my case after fixing initialization, NPE had gone.

-2

I know this is an old ticket but i still wanted to let you guys know how we fixed the problem. Especially the last nullpointer exception.

The problem is that your entitimanager is not loaded when you are using your Criteriabuilder for the first time. To solve this problem you can set following in you persistence.xml

<property name="eclipselink.deploy-on-startup" value="true" />