diff --git a/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/BasePersistable.java b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/BasePersistable.java new file mode 100644 index 00000000000..86948d16987 --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/BasePersistable.java @@ -0,0 +1,10 @@ +package org.eclipse.persistence.jpa.test.canonical; + +public interface BasePersistable { + + Long getId(); + + String getName(); + + void setName(String name); +} diff --git a/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainClass.java b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainClass.java new file mode 100644 index 00000000000..c34750f38e1 --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainClass.java @@ -0,0 +1,17 @@ +package org.eclipse.persistence.jpa.test.canonical; + +import javax.persistence.Entity; + +@Entity +public class DomainClass extends DomainPersistable { + + // Holds additional features that one can specify on the DomainInterface + // Essentially this is an enrichment of the persistable + + @Override + public Long doSomeBusinessOperation() { + + return null; + } + +} diff --git a/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainInterface.java b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainInterface.java new file mode 100644 index 00000000000..ddcc434cad2 --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainInterface.java @@ -0,0 +1,6 @@ +package org.eclipse.persistence.jpa.test.canonical; + +public interface DomainInterface extends BasePersistable { + + Long doSomeBusinessOperation(); +} diff --git a/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainInterface_.java b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainInterface_.java new file mode 100644 index 00000000000..ec2e753a53e --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainInterface_.java @@ -0,0 +1,11 @@ +package org.eclipse.persistence.jpa.test.canonical; + +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.StaticMetamodel; + +@StaticMetamodel(DomainPersistable.class) +public class DomainInterface_ { + + public static volatile SingularAttribute id; + public static volatile SingularAttribute name; +} diff --git a/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainPersistable.java b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainPersistable.java new file mode 100644 index 00000000000..ff33a513051 --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/DomainPersistable.java @@ -0,0 +1,32 @@ +package org.eclipse.persistence.jpa.test.canonical; + +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +@MappedSuperclass +public abstract class DomainPersistable implements DomainInterface { + + // Holds all standard fields, mapped to something that is going to be persisted in the database + + @Id + private Long id; + private String name; + + @Override + public Long getId() { + + return id; + } + + @Override + public String getName() { + + return name; + } + + @Override + public void setName(String name) { + + this.name = name; + } +} diff --git a/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/TestCanonicalMetaModel.java b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/TestCanonicalMetaModel.java new file mode 100644 index 00000000000..af917838297 --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/canonical/TestCanonicalMetaModel.java @@ -0,0 +1,100 @@ +package org.eclipse.persistence.jpa.test.canonical; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.util.Arrays; +import java.util.Properties; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; + +import org.eclipse.persistence.config.SessionCustomizer; +import org.eclipse.persistence.internal.jpa.deployment.SEPersistenceUnitInfo; +import org.eclipse.persistence.internal.sessions.AbstractSession; +import org.eclipse.persistence.jpa.PersistenceProvider; +import org.eclipse.persistence.sessions.Session; +import org.junit.Test; + +public class TestCanonicalMetaModel { + + @Test + public void testUseCanonicalModelFieldName() { + + PersistenceProvider persistenceProvider = new PersistenceProvider(); + SEPersistenceUnitInfo persistenceUnitInfo = new SEPersistenceUnitInfo(); + + // For ASM to do its work creating metaclasses + persistenceUnitInfo.setClassLoader(Thread.currentThread().getContextClassLoader()); + + // We only programmatically add 'leaf' domain classes to pui + persistenceUnitInfo.setManagedClassNames(Arrays.asList(DomainClass.class.getName())); + persistenceUnitInfo.setPersistenceUnitName("canonical-test"); + persistenceUnitInfo.setPersistenceUnitRootUrl(DomainClass.class.getProtectionDomain() + .getCodeSource().getLocation()); + + Properties properties = new Properties(); + readProperty(properties, "javax.persistence.jdbc.driver"); + readProperty(properties, "javax.persistence.jdbc.url"); + readProperty(properties, "javax.persistence.jdbc.user"); + readProperty(properties, "javax.persistence.jdbc.password"); + + // In our actual application we have a generic session customizer that binds a number + // of delegate session customizers in a 'logical' order - for this example however we + // only need to have this 'test' one - see below class + properties.setProperty("eclipselink.session.customizer", CanonicalMetaModelCustomizer.class.getName()); + + try (AutoCloseableEntityManagerFactory acemf = new AutoCloseableEntityManagerFactory(persistenceProvider, + persistenceUnitInfo, properties)) { + assertThat("The \"name\" field is properly initialized", DomainInterface_.name, notNullValue()); + } + + } + + private void readProperty(Properties properties, String key) { + + properties.setProperty(key, System.getProperty(key)); + } + + /** + * What it is doing is that it will be providing the link between an (impl) 'hidden' persistable and an + * api (exposed) canonical metamodel class. + */ + public static class CanonicalMetaModelCustomizer implements SessionCustomizer { + + @Override + public void customize(Session session) throws Exception { + + AbstractSession.class.cast(session).addStaticMetamodelClass( + DomainPersistable.class.getName(), DomainInterface_.class.getName()); + } + } + + /** + * Provides some small cleanup test helper facility. + */ + static class AutoCloseableEntityManagerFactory implements AutoCloseable { + + private final EntityManagerFactory entityManagerFactory; + private final EntityManager firstEntityManager; + + AutoCloseableEntityManagerFactory(PersistenceProvider persistenceProvider, + SEPersistenceUnitInfo persistenceUnitInfo, Properties properties) { + + entityManagerFactory = persistenceProvider.createContainerEntityManagerFactory(persistenceUnitInfo, properties); + firstEntityManager = entityManagerFactory.createEntityManager(); + } + + @Override + public void close() { + + if (firstEntityManager != null) { + firstEntityManager.close(); + } + + if (entityManagerFactory != null) { + entityManagerFactory.close(); + } + } + } +} diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/MetadataProject.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/MetadataProject.java index aa6e0379e48..4d17ba5c431 100644 --- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/MetadataProject.java +++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/MetadataProject.java @@ -1865,7 +1865,7 @@ public void processStage1() { */ public void processStage2() { // process metamodel mappedSuperclasses separately from entity descriptors - for (MappedSuperclassAccessor msAccessor : getMappedSuperclasses()) { + for (MappedSuperclassAccessor msAccessor : getMetamodelMappedSuperclasses()) { if (! msAccessor.isProcessed()) { msAccessor.processMetamodelDescriptor(); }