Skip to content

Commit

Permalink
jakartaee/persistence#447 - add new operations to PersistenceUnitUtil
Browse files Browse the repository at this point in the history
Signed-off-by: Tomáš Kraus <[email protected]>
  • Loading branch information
Tomas-Kraus authored and lukasj committed Nov 30, 2023
1 parent 87f54d9 commit 384556f
Show file tree
Hide file tree
Showing 12 changed files with 422 additions and 70 deletions.
28 changes: 28 additions & 0 deletions jpa/eclipselink.jpa.testapps/jpa.test.persistence32/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,34 @@
</execution>
</executions>
</plugin>
<!-- Static metamodel is used in tests -->
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>4.5</version>
<executions>
<execution>
<id>eclipselink-jpa-metamodel</id>
<goals>
<goal>process</goal>
</goals>
<phase>process-resources</phase>
<configuration>
<processors>
<processor>org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor</processor>
</processors>
<outputDirectory>${project.build.directory}/generated-sources/meta-model</outputDirectory>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@
import jakarta.persistence.NamedNativeQuery;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.Table;
import org.eclipse.persistence.annotations.FetchAttribute;
import org.eclipse.persistence.annotations.FetchGroup;
import org.eclipse.persistence.annotations.FetchGroups;

@Entity
@Table(name="PERSISTENCE32_POKEMON")
@NamedQuery(name="Pokemon.get", query="SELECT p FROM Pokemon p WHERE p.id = :id")
@NamedNativeQuery(name="Pokemon.deleteAllTypes", query="DELETE FROM PERSISTENCE32_POKEMON_TYPE")
@NamedNativeQuery(name="Pokemon.deleteAll", query="DELETE FROM PERSISTENCE32_POKEMON")
@FetchGroups({
@FetchGroup(name = "FetchTypes", attributes = {@FetchAttribute(name = "types")})
})
public class Pokemon {

// ID is assigned in tests to avoid collisions
Expand Down Expand Up @@ -63,8 +69,10 @@ public Pokemon(String name, Trainer trainer, Collection<Type> types) {
this.types = types;
}

// Required for testUnionWithMultiselectEntityParametersInSelection
// to select ResultType.CONSTRUCTOR for the query.
public Pokemon(int id, String name) {
this(name, null, Collections.EMPTY_LIST);
this(name, null, Collections.emptyList());
this.id = id;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,13 @@

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedNativeQuery;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import org.eclipse.persistence.annotations.JoinFetch;
import org.eclipse.persistence.annotations.JoinFetchType;
import org.eclipse.persistence.annotations.Property;

import static jakarta.persistence.FetchType.EAGER;
import static jakarta.persistence.FetchType.LAZY;

@Entity
@Table(name="PERSISTENCE32_TRAINER")
Expand All @@ -40,7 +36,7 @@ public class Trainer {

private String name;

@ManyToOne
@ManyToOne(fetch = LAZY)
private Team team;

@OneToMany(mappedBy = "trainer")
Expand Down Expand Up @@ -98,8 +94,7 @@ public boolean equals(Object obj) {

@Override
public int hashCode() {
int result = Objects.hash(id, name);
return result;
return Objects.hash(id, name);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ Map<Integer, Type> pokemonTypes(EntityManager em) {
*/
public void testSetup() {
new Persistence32TableCreator().replaceTables(JUnitTestCase.getServerSession(getPersistenceUnitName()));
clearCache();
emf.runInTransaction(em -> {
for (int i = 1; i < TEAMS.length; i++) {
em.persist(TEAMS[i]);
Expand All @@ -141,6 +140,7 @@ public void testSetup() {
em.persist(TYPES[i]);
}
});
clearCache();
}

/**
Expand All @@ -157,4 +157,10 @@ public void testCleanup() {
});
}

@Override
public void clearCache() {
emf.getCache().evictAll();
super.clearCache();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
*/
package org.eclipse.persistence.testing.tests.jpa.persistence32;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -24,9 +26,15 @@
import jakarta.persistence.PersistenceConfiguration;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.PersistenceUnitTransactionType;
import jakarta.persistence.PersistenceUnitUtil;
import junit.framework.Test;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.FetchGroupManager;
import org.eclipse.persistence.jpa.JpaEntityManagerFactory;
import org.eclipse.persistence.testing.models.jpa.persistence32.Pokemon;
import org.eclipse.persistence.testing.models.jpa.persistence32.Trainer;
import org.eclipse.persistence.testing.models.jpa.persistence32.Trainer_;
import org.eclipse.persistence.testing.models.jpa.persistence32.Type;

public class EntityManagerFactoryTest extends AbstractPokemon {
Expand All @@ -40,7 +48,15 @@ public static Test suite() {
new EntityManagerFactoryTest("testCallWithConnection"),
new EntityManagerFactoryTest("testCreateCustomEntityManagerFactory"),
new EntityManagerFactoryTest("testCreateConflictingCustomEntityManagerFactory"),
new EntityManagerFactoryTest("testCreateConflictingConfiguredEntityManagerFactory"));
new EntityManagerFactoryTest("testCreateConflictingConfiguredEntityManagerFactory"),
new EntityManagerFactoryTest("testIsLoadedEntityAttribute"),
new EntityManagerFactoryTest("testLoadEntityAttribute"),
new EntityManagerFactoryTest("testIsLoadedEntityNamedAttribute"),
new EntityManagerFactoryTest("testLoadEntityNamedAttribute"),
new EntityManagerFactoryTest("testVerifyPokemonFetchGroups"),
new EntityManagerFactoryTest("testIsLoadedEntity"),
new EntityManagerFactoryTest("testLoadEntity")
);
}

public EntityManagerFactoryTest() {
Expand Down Expand Up @@ -209,6 +225,113 @@ public void testCreateConflictingConfiguredEntityManagerFactory() {
}
}

public void testIsLoadedEntityAttribute() {
Trainer t = emf.callInTransaction(
em -> em.createQuery("SELECT t FROM Trainer t WHERE t.name = :name", Trainer.class)
.setParameter("name", "Ash")
.getSingleResult());
PersistenceUnitUtil util = emf.getPersistenceUnitUtil();
// This mapping is lazy, so it shall not be loaded
assertFalse("Entity lazy attribute Trainer.team should not be loaded", util.isLoaded(t, Trainer_.team));
}

public void testLoadEntityAttribute() {
Trainer t = emf.callInTransaction(
em -> em.createQuery("SELECT t FROM Trainer t WHERE t.name = :name", Trainer.class)
.setParameter("name", "Ash")
.getSingleResult());
PersistenceUnitUtil util = emf.getPersistenceUnitUtil();
// This mapping is lazy, so it shall not be loaded
assertFalse("Entity lazy attribute Trainer.team should not be loaded", util.isLoaded(t, Trainer_.team));
util.load(t, Trainer_.team);
assertTrue("Entity lazy attribute Trainer.team should be loaded after load call", util.isLoaded(t, Trainer_.team));
}

public void testIsLoadedEntityNamedAttribute() {
Trainer t = emf.callInTransaction(
em -> em.createQuery("SELECT t FROM Trainer t WHERE t.name = :name", Trainer.class)
.setParameter("name", "Ash")
.getSingleResult());
PersistenceUnitUtil util = emf.getPersistenceUnitUtil();
// This mapping is lazy, so it shall not be loaded
assertFalse("Entity lazy attribute Trainer.team should not be loaded", util.isLoaded(t, "team"));
}

public void testLoadEntityNamedAttribute() {
Trainer t = emf.callInTransaction(
em -> em.createQuery("SELECT t FROM Trainer t WHERE t.name = :name", Trainer.class)
.setParameter("name", "Ash")
.getSingleResult());
PersistenceUnitUtil util = emf.getPersistenceUnitUtil();
// This mapping is lazy, so it shall not be loaded
assertFalse("Entity lazy attribute Trainer.team should not be loaded",
util.isLoaded(t, "team"));
util.load(t, "team");
assertTrue("Entity lazy attribute Trainer.team should be loaded after load call",
util.isLoaded(t, "team"));
}

public void testVerifyPokemonFetchGroups() {
if (isWeavingEnabled()) {
ClassDescriptor pokemonsDescriptor = getPersistenceUnitServerSession().getDescriptor(Pokemon.class);
FetchGroupManager pokemonsFetchGroupManager = pokemonsDescriptor.getFetchGroupManager();
assertEquals("Wrong number of fetch groups for Pokemon", 1, pokemonsFetchGroupManager.getFetchGroups().size());
assertNotNull("The 'FetchTypes' fetch group was not found for Pokemon", pokemonsFetchGroupManager.getFetchGroup("FetchTypes"));
}
}

public void testIsLoadedEntity() {
if (isWeavingEnabled()) {
Pokemon ekans = new Pokemon(6, TRAINERS[2], "Ekans", List.of(TYPES[4]));
emf.runInTransaction(em -> em.persist(ekans));
clearCache();
Map<String, Object> properties = new HashMap<>();
properties.put(QueryHints.FETCH_GROUP_NAME, "FetchTypes");
Class<Pokemon> pokemonClass = Pokemon.class;
EntityManager em = createEntityManager();
try {
Pokemon pokemon = em.find(pokemonClass, ekans.getId(), properties);
verifyFetchedField(pokemonClass.getDeclaredField("types"), pokemon, ekans.getTypes());
verifyNonFetchedField(pokemonClass.getDeclaredField("name"), pokemon);
verifyNonFetchedField(pokemonClass.getDeclaredField("trainer"), pokemon);
PersistenceUnitUtil util = em.getEntityManagerFactory().getPersistenceUnitUtil();
// This mapping is lazy, so it shall not be loaded
assertFalse("Pokemon lazy attributes name and trainer should not be loaded", util.isLoaded(pokemon));
} catch (Exception e) {
fail("Error verifying field content: " + e.getMessage());
} finally {
closeEntityManager(em);
}
}
}

public void testLoadEntity() {
if (isWeavingEnabled()) {
Pokemon arbok = new Pokemon(7, TRAINERS[2], "Arbok", List.of(TYPES[4]));
emf.runInTransaction(em -> em.persist(arbok));
clearCache();
Map<String, Object> properties = new HashMap<>();
properties.put(QueryHints.FETCH_GROUP_NAME, "FetchTypes");
Class<Pokemon> pokemonClass = Pokemon.class;
EntityManager em = createEntityManager();
try {
Pokemon pokemon = em.find(pokemonClass, arbok.getId(), properties);
verifyFetchedField(pokemonClass.getDeclaredField("types"), pokemon, arbok.getTypes());
verifyNonFetchedField(pokemonClass.getDeclaredField("name"), pokemon);
verifyNonFetchedField(pokemonClass.getDeclaredField("trainer"), pokemon);
PersistenceUnitUtil util = em.getEntityManagerFactory().getPersistenceUnitUtil();
// This mapping is lazy, so it shall not be loaded
assertFalse("Pokemon lazy attributes name and trainer should not be loaded", util.isLoaded(pokemon));
util.load(pokemon);
assertTrue("Pokemon lazy attributes name and trainer should be loaded after load call", util.isLoaded(pokemon));
} catch (Exception e) {
fail("Error verifying field content: " + e.getMessage());
} finally {
closeEntityManager(em);
}
}
}

private static PersistenceConfiguration createPersistenceConfiguration(JpaEntityManagerFactory emf, String puName) {
PersistenceConfiguration configuration = new PersistenceConfiguration(puName);
configuration.properties(emf.getProperties());
Expand All @@ -221,4 +344,22 @@ private static PersistenceConfiguration createPersistenceConfiguration(JpaEntity
return configuration;
}

private static void verifyFetchedField(Field field, Object obj, Object value) {
try {
field.setAccessible(true);
assertEquals("The field [" + field.getName() + "] was not fetched", field.get(obj), value);
} catch (IllegalAccessException e) {
fail("Error verifying field content: " + e.getMessage());
}
}

private static void verifyNonFetchedField(Field field, Object obj) {
try {
field.setAccessible(true);
assertNull("The field [" + field.getName() + "] was fetched", field.get(obj));
} catch (IllegalAccessException e) {
fail("Error verifying field content: " + e.getMessage());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ public void testUnionWithEntityParameterInSelection() {
}
}

// Requires Pokemon(int id, String name) constructor to set ResultType.CONSTRUCTOR in multiselect call
@SuppressWarnings("deprecation")
public void testUnionWithMultiselectEntityParametersInSelection() {
try (EntityManager em = emf.createEntityManager()) {
Expand Down Expand Up @@ -414,6 +415,9 @@ public void testUnionWithMultiselectEntityParametersInSelection() {
}
}

// TODO testUnionWithMultiselectEntityParametersInSelection without supporting constructor
// to validate ResultType.PARTIAL with compound query

public void testUnionWithMultiselectEntityInSelection() {
try (EntityManager em = emf.createEntityManager()) {
EntityTransaction et = em.getTransaction();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,39 +739,34 @@ public boolean isLoaded(Object entity) {
EntityManagerFactoryImpl.isLoaded(entity, session));
}

// TODO-API-3.2
@Override
public void load(Object entity, String attributeName) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
EntityManagerFactoryImpl.load(entity, attributeName, session);
}

// TODO-API-3.2
@Override
public <E> void load(E entity, Attribute<? super E, ?> attribute) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
EntityManagerFactoryImpl.load(entity, attribute.getName(), session);
}

// TODO-API-3.2
@Override
public void load(Object entity) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
EntityManagerFactoryImpl.load(entity, session);
}

// TODO-API-3.2
@Override
public boolean isInstance(Object entity, Class<?> entityClass) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
return EntityManagerFactoryImpl.isInstance(entity, entityClass, session);
}

@Override
public String getName() {
return setupImpl.getPersistenceUnitUniqueName();
}

// TODO-API-3.2
@Override
public <T> Class<? extends T> getClass(T entity) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
return EntityManagerFactoryImpl.getClass(entity, session);
}

/**
Expand Down
Loading

0 comments on commit 384556f

Please sign in to comment.