websphereeclipselinkwebsphere-liberty

ClassCastException using EclipseLink DescriptorCustomizer API in Liberty


We are using websphere-liberty:23.0.0.11-kernel-java17-openj9-ubi

with feature

<feature>persistence-3.0</feature> 

and we want to use EclipseLink History https://wiki.eclipse.org/EclipseLink/Examples/JPA/History

we add

@Customizer(HistoryCustomizer.class)

to our Entity class but we get code exceptions all the time The question is which artifactId/version should we add to the pom.xml to support EclipseLink with Liberty with persistence 3.0?

I added such depedency

    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.core</artifactId>
        <version>3.0.4</version>
        <scope>compile</scope>
    </dependency>

and my DescriptorCustomizer

import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.history.HistoryPolicy;

public class HistoryCustomizer implements DescriptorCustomizer {

    public void customize(ClassDescriptor descriptor) {
        HistoryPolicy policy = new HistoryPolicy();
        policy.addHistoryTableName("EMPLOYEE_HIST");
        policy.addStartFieldName("START_DATE");
        policy.addEndFieldName("END_DATE");
        descriptor.setHistoryPolicy(policy);
    }
}

, but i got error message about ClassCastException

jakarta.persistence.PersistenceException: Exception [EclipseLink-28019] (Eclipse Persistence Services - 3.0.3.v202208190922): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Deployment of PersistenceUnit [jpa-unit] failed. Close all factories for this PersistenceUnit.
Internal Exception: java.lang.ClassCastException: class com.ibm.saas.siusermgr.application.scope.HistoryCustomizer cannot be cast to class org.eclipse.persistence.config.DescriptorCustomizer (com.ibm.saas.siusermgr.application.scope.HistoryCustomizer is in unnamed module of loader com.ibm.ws.classloading.internal.AppClassLoader @2bba175e; org.eclipse.persistence.config.DescriptorCustomizer is in unnamed module of loader org.eclipse.osgi.internal.loader.EquinoxClassLoader @3cab2487)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.createDeployFailedPersistenceException(EntityManagerSetupImpl.java:907)

Solution

  • Configure access to Third Party APIs

    As mentioned in the doc:

    By default, applications do not have access to the third-party APIs that are available in Open Liberty

    So even though the persistence-3.0 feature documents providing APIs like org.eclipse.persistence.config.DescriptorCustomizer, (plus HistoryPolicy and the other EclipseLink classes), these will not be available to your application without one additional piece of server configuration.

    server.xml

    Configure a <classloader> element for your application like:

    <application id="testApp" name="testApp" type="war" location="testApp.war">
        <classloader apiTypeVisibility="+third-party" />
    </application>
    

    Suggest 'provided'-scope dependency

    There's probably less opportunity for confusion to use a provided-scope dependency to clearly load these classes from the runtime-provided version of the library rather than packaging it within your application. It's true that the default "parent-first" classloading might make this not really matter, at first. Still, I'd suggest this as a better starting point, unless/until you really need to consider using your own version (beyond the scope of this post). It's also a bit smaller footprint.

    pom.xml

        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.core</artifactId>
            <version>3.0.4</version>
            <scope>provided</scope>
        </dependency>
    

    References