When class is annotated with @MappedSuperclass, its private fields can't be accessed from JPA with native image (#2127)

Signed-off-by: Tomas Kraus <Tomas.Kraus@oracle.com>
This commit is contained in:
Tomáš Kraus
2020-09-15 12:17:49 +02:00
committed by GitHub
parent d62d70ef53
commit 386a734d52
24 changed files with 1089 additions and 73 deletions

View File

@@ -1,6 +1,7 @@
{
"annotated":[
"javax.persistence.Entity"
"javax.persistence.Entity",
"javax.persistence.MappedSuperclass"
],
"class-hierarchy": [
"javax.xml.stream.XMLEventFactory",

View File

@@ -75,6 +75,7 @@ public class HelidonReflectionFeature implements Feature {
private static final boolean TRACE = NativeConfig.option("reflection.trace", false);
private static final String AT_ENTITY = "javax.persistence.Entity";
private static final String AT_MAPPED_SUPERCLASS = "javax.persistence.MappedSuperclass";
private static final String AT_REGISTER_REST_CLIENT = "org.eclipse.microprofile.rest.client.inject.RegisterRestClient";
private static final Map<Class<?>, Class<?>> PRIMITIVES_TO_OBJECT = new HashMap<>();
@@ -379,23 +380,35 @@ public class HelidonReflectionFeature implements Feature {
@SuppressWarnings("unchecked")
private void processEntity(BeforeAnalysisContext context) {
final Class<? extends Annotation> annotation = (Class<? extends Annotation>) context.access()
final Class<? extends Annotation> entityAnnotation = (Class<? extends Annotation>) context.access()
.findClassByName(AT_ENTITY);
if (annotation == null) {
final Class<? extends Annotation> superclassAnnotation = (Class<? extends Annotation>) context.access()
.findClassByName(AT_MAPPED_SUPERCLASS);
Set<Class<?>> annotatedSet = null;
traceParsing(() -> "Looking up annotated by " + AT_ENTITY);
if (entityAnnotation != null) {
annotatedSet = new HashSet<>(findAnnotated(context, AT_ENTITY));
}
traceParsing(() -> "Looking up annotated by " + AT_MAPPED_SUPERCLASS);
if (superclassAnnotation != null) {
if (annotatedSet == null) {
annotatedSet = new HashSet<>(findAnnotated(context, AT_MAPPED_SUPERCLASS));
} else {
annotatedSet.addAll(findAnnotated(context, AT_MAPPED_SUPERCLASS));
}
}
if (annotatedSet == null || annotatedSet.isEmpty()) {
return;
}
traceParsing(() -> "Looking up annotated by " + AT_ENTITY);
final List<Class<?>> annotatedList = findAnnotated(context, AT_ENTITY);
annotatedList.forEach(aClass -> {
annotatedSet.forEach(aClass -> {
traceParsing(() -> "Processing annotated class " + aClass.getName());
String resourceName = aClass.getName().replace('.', '/') + ".class";
InputStream resourceStream = aClass.getClassLoader().getResourceAsStream(resourceName);
Resources.registerResource(resourceName, resourceStream);
for (Field declaredField : aClass.getDeclaredFields()) {
if (!Modifier.isPublic(declaredField.getModifiers()) && declaredField.getAnnotations().length == 0) {
RuntimeReflection.register(declaredField);
if (TRACE) {
System.out.println(" non annotated field " + declaredField);
}
traceParsing(() -> " added non annotated field " + declaredField);
}
}
});

View File

@@ -15,8 +15,12 @@
*/
package io.helidon.tests.integration.jpa.appl;
import java.util.List;
import javax.persistence.EntityManager;
import io.helidon.tests.integration.jpa.model.Pokemon;
/**
* Database utilities.
*/
@@ -37,4 +41,22 @@ public class DbUtils {
em.getEntityManagerFactory().getCache().evictAll();
}
/**
* Find pokemon by name from pokemon List.
*
* @param pokemons List to search
* @param name name of pokemon
* @return found pokemon or null when no such pokemon exists
*/
public static Pokemon findPokemonByName(List<Pokemon> pokemons, String name) {
if (pokemons != null && !pokemons.isEmpty()) {
for (Pokemon pokemon : pokemons) {
if (pokemon.getName().equals(name)) {
return pokemon;
}
}
}
return null;
}
}

View File

@@ -27,7 +27,10 @@ import javax.persistence.criteria.Root;
import io.helidon.tests.integration.jpa.dao.Create;
import io.helidon.tests.integration.jpa.dao.Delete;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.Trainer;
/**
* Verify delete operations of ORM (server side).
@@ -47,6 +50,7 @@ public class DeleteIT {
@MPTest
public TestResult setup(TestResult result) {
Create.dbInsertMisty(em);
Create.dbInsertViridian(em);
return result;
}
@@ -59,6 +63,7 @@ public class DeleteIT {
@MPTest
public TestResult destroy(TestResult result) {
Delete.dbDeleteMisty(em);
Delete.dbDeleteViridian(em);
return result;
}
@@ -132,4 +137,31 @@ public class DeleteIT {
return result;
}
/**
* Delete Viridian City.
*
* @param result test execution result
* @return test execution result
*/
@MPTest
public TestResult testDeleteViridianCity(TestResult result) {
City city = em.createQuery(
"SELECT c FROM City c WHERE c.name = :name", City.class)
.setParameter("name", "Viridian City")
.getSingleResult();
Stadium stadium = city.getStadium();
Trainer trainer = stadium.getTrainer();
List<Pokemon> pokemons = trainer.getPokemons();
em.remove(city);
em.remove(trainer);
pokemons.forEach(poklemon -> em.remove(poklemon));
DbUtils.cleanEm(em);
List<City> cities = em.createQuery(
"SELECT c FROM City c WHERE c.name = :name", City.class)
.setParameter("name", "Viridian City")
.getResultList();
result.assertTrue(cities.isEmpty());
return result;
}
}

View File

@@ -17,13 +17,16 @@ package io.helidon.tests.integration.jpa.appl;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.Trainer;
import io.helidon.tests.integration.jpa.model.Type;
@@ -35,6 +38,8 @@ public class InsertIT {
private static final Set<Integer> DELETE_POKEMONS = new HashSet<>();
private static final Set<Integer> DELETE_TRAINERS = new HashSet<>();
private static final Set<Integer> DELETE_STADIUMS = new HashSet<>();
private static final Set<Integer> DELETE_TOWNS = new HashSet<>();
@PersistenceContext(unitName = "test")
private EntityManager em;
@@ -51,18 +56,30 @@ public class InsertIT {
em.createQuery("DELETE FROM Type t WHERE t.id = :id")
.setParameter("id", 20)
.executeUpdate();
// Towns cleanup
DELETE_TOWNS.forEach((id) -> {
em.createQuery("DELETE FROM City c WHERE c.id = :id")
.setParameter("id", id)
.executeUpdate();
});
// Stadiums cleanup
DELETE_STADIUMS.forEach((id) -> {
em.createQuery("DELETE FROM Stadium s WHERE s.id = :id")
.setParameter("id", id)
.executeUpdate();
});
// Pokemons cleanup
for (int id : DELETE_POKEMONS) {
DELETE_POKEMONS.forEach((id) -> {
em.createQuery("DELETE FROM Pokemon p WHERE p.id = :id")
.setParameter("id", id)
.executeUpdate();
}
});
// Trainers cleanup
for (int id : DELETE_TRAINERS) {
DELETE_TRAINERS.forEach((id) -> {
em.createQuery("DELETE FROM Trainer t WHERE t.id = :id")
.setParameter("id", id)
.executeUpdate();
}
});
return result;
}
@@ -131,4 +148,60 @@ public class InsertIT {
return result;
}
/**
* Verify complex create operation (persist) on a full ORM model (Lt. Surge in Vermilion City).
*
* @param result test execution result
* @return test execution result
*/
@MPTest
public TestResult testInsertTownWithStadium(TestResult result) {
final Trainer[] trainers = new Trainer[1];
final Pokemon[] pokemons = new Pokemon[6];
final Stadium[] stadiums = new Stadium[1];
final City[] cities = new City[1];
Type steel = em.find(Type.class, 9);
Type electric = em.find(Type.class, 13);
trainers[0] = new Trainer("Lt. Surge", 28);
pokemons[0] = new Pokemon(trainers[0], "Raichu", 1521, Arrays.asList(electric));
pokemons[1] = new Pokemon(trainers[0], "Manectric", 1589, Arrays.asList(electric));
pokemons[2] = new Pokemon(trainers[0], "Magnezone", 1853, Arrays.asList(electric));
pokemons[3] = new Pokemon(trainers[0], "Electrode", 1237, Arrays.asList(electric));
pokemons[4] = new Pokemon(trainers[0], "Pachirisu", 942, Arrays.asList(electric));
pokemons[5] = new Pokemon(trainers[0], "Electivire", 1931, Arrays.asList(electric));
stadiums[0] = new Stadium("Vermilion Gym", trainers[0]);
cities[0] = new City("Vermilion City", "Mina", stadiums[0]);
em.persist(trainers[0]);
em.persist(pokemons[0]);
em.persist(pokemons[1]);
em.persist(pokemons[2]);
em.persist(pokemons[3]);
em.persist(pokemons[4]);
em.persist(pokemons[5]);
//em.persist(stadiums[0]);
em.persist(cities[0]);
em.flush();
DbUtils.cleanEm(em);
City dbCity = em.find(City.class, cities[0].getId());
Stadium dbStadium = dbCity.getStadium();
Trainer dbTrainer = dbStadium.getTrainer();
List<Pokemon> dbPokemons = dbTrainer.getPokemons();
Set<Pokemon> pokemonSet = new HashSet<>(pokemons.length);
pokemonSet.addAll(Arrays.asList(pokemons));
dbPokemons.forEach((dbPokemon) -> {
result.assertTrue(pokemonSet.remove(dbPokemon));
});
result.assertTrue(pokemonSet.isEmpty());
result.assertEquals(trainers[0], dbTrainer);
result.assertEquals(stadiums[0], dbStadium);
result.assertEquals(cities[0], dbCity);
for (Pokemon pokemon : pokemons) {
DELETE_POKEMONS.add(pokemon.getId());
}
DELETE_TRAINERS.add(dbTrainer.getId());
DELETE_STADIUMS.add(dbStadium.getId());
DELETE_TOWNS.add(dbCity.getId());
return result;
}
}

View File

@@ -26,6 +26,7 @@ import javax.persistence.criteria.Root;
import io.helidon.tests.integration.jpa.dao.Create;
import io.helidon.tests.integration.jpa.dao.Delete;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Trainer;
@@ -49,6 +50,7 @@ public class QueryIT {
@MPTest
public TestResult setup(TestResult result) {
ASH_ID = Create.dbInsertAsh(em);
Create.dbInsertCeladon(em);
return result;
}
@@ -61,6 +63,7 @@ public class QueryIT {
@MPTest
public TestResult destroy(TestResult result) {
Delete.dbDeleteAsh(em);
Delete.dbDeleteCeladon(em);
return result;
}
@@ -117,4 +120,48 @@ public class QueryIT {
return result;
}
/**
* Query Celadon city using JPQL.
*
* @param result test execution result
* @return test execution result
*/
@MPTest
public TestResult testQueryCeladonJPQL(TestResult result) {
City city = em.createQuery(
"SELECT c FROM City c "
+ "JOIN FETCH c.stadium s "
+ "JOIN FETCH s.trainer t "
+ "WHERE c.name = :name", City.class)
.setParameter("name", "Celadon City")
.getSingleResult();
result.assertEquals(city.getName(), "Celadon City");
result.assertEquals(city.getStadium().getName(), "Celadon Gym");
result.assertEquals(city.getStadium().getTrainer().getName(), "Erika");
return result;
}
/**
* Query Celadon city using CriteriaQuery.
*
* @param result test execution result
* @return test execution result
*/
@MPTest
public TestResult testQueryCeladonCriteria(TestResult result) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<City> cq = cb.createQuery(City.class);
Root<City> cityRoot = cq.from(City.class);
cityRoot
.fetch("stadium")
.fetch("trainer");
cq.select(cityRoot)
.where(cb.equal(cityRoot.get("name"), "Celadon City"));
City city = em.createQuery(cq).getSingleResult();
result.assertEquals(city.getName(), "Celadon City");
result.assertEquals(city.getStadium().getName(), "Celadon Gym");
result.assertEquals(city.getStadium().getTrainer().getName(), "Erika");
return result;
}
}

View File

@@ -176,6 +176,27 @@ public class TestResult {
}
}
/**
* Test result check: boolean true
*
* @param value actual value to be checked
*/
public void assertTrue(Boolean value, String header) {
StringBuilder sb = new StringBuilder();
sb.append(header);
sb.append(" Expected: true");
sb.append(" Actual: ");
sb.append(Boolean.toString(value));
sb.append(" :: ");
sb.append(value ? "EQUAL" : "NOT EQUAL");
String message = sb.toString();
msg.add(message);
if (!value) {
ob.add("error", message);
failed = true;
}
}
/**
* Test result check: boolean false
*

View File

@@ -15,6 +15,11 @@
*/
package io.helidon.tests.integration.jpa.appl;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@@ -25,7 +30,10 @@ import javax.persistence.criteria.Root;
import io.helidon.tests.integration.jpa.dao.Create;
import io.helidon.tests.integration.jpa.dao.Delete;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.Trainer;
/**
* Verify update operations of ORM (server side).
@@ -46,6 +54,7 @@ public class UpdateIT {
@MPTest
public TestResult setup(TestResult result) {
Create.dbInsertBrock(em);
Create.dbInsertSaffron(em);
return result;
}
@@ -58,6 +67,7 @@ public class UpdateIT {
@MPTest
public TestResult destroy(TestResult result) {
Delete.dbDeleteBrock(em);
Delete.dbDeleteSaffron(em);
return result;
}
@@ -138,5 +148,58 @@ public class UpdateIT {
return result;
}
/**
* Update Saffron City data structure.
* Replace stadium trainer with new guy who will get all pokemons from previous trainer.
* Also Alakazam evolves to Mega Alakazam at the same time.
*
* @param result test execution result
* @return test execution result
*/
@MPTest
public TestResult testUpdateSaffron(TestResult result) {
City[] cities = new City[1];
Set<String> pokemonNames = new HashSet<>(6);
cities[0] = em.createQuery(
"SELECT c FROM City c WHERE c.name = :name", City.class)
.setParameter("name", "Saffron City")
.getSingleResult();
Stadium stadium = cities[0].getStadium();
Trainer sabrina = stadium.getTrainer();
Trainer janine = new Trainer("Janine", 24);
stadium.setTrainer(janine);
List<Pokemon> pokemons = sabrina.getPokemons();
janine.setPokemons(pokemons);
sabrina.setPokemons(Collections.EMPTY_LIST);
em.remove(sabrina);
em.persist(janine);
for (Pokemon pokemon : pokemons) {
pokemon.setTrainer(janine);
pokemonNames.add(pokemon.getName());
em.persist(pokemon);
}
em.persist(stadium);
Pokemon alkazam = DbUtils.findPokemonByName(pokemons, "Alakazam");
// Update pokemon by query
em.createQuery(
"UPDATE Pokemon p SET p.name = :newName, p.cp = :newCp WHERE p.id = :id")
.setParameter("newName", "Mega Alakazam")
.setParameter("newCp", 4348)
.setParameter("id", alkazam.getId())
.executeUpdate();
pokemonNames.remove("Alakazam");
pokemonNames.add("Mega Alakazam");
DbUtils.cleanEm(em);
City city = em.find(City.class, cities[0].getId());
stadium = city.getStadium();
Trainer trainer = stadium.getTrainer();
em.refresh(trainer);
pokemons = trainer.getPokemons();
result.assertEquals(trainer.getName(), "Janine");
for (Pokemon pokemon : pokemons) {
result.assertTrue(pokemonNames.remove(pokemon.getName()), "Pokemon " + pokemon.getName() + " is missing");
}
return result;
}
}

View File

@@ -22,6 +22,8 @@
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="test" transaction-type="JTA">
<class>io.helidon.tests.integration.jpa.model.City</class>
<class>io.helidon.tests.integration.jpa.model.Stadium</class>
<class>io.helidon.tests.integration.jpa.model.Type</class>
<class>io.helidon.tests.integration.jpa.model.Trainer</class>
<class>io.helidon.tests.integration.jpa.model.Pokemon</class>

View File

@@ -62,4 +62,12 @@ public class DeleteIT {
ClientUtils.callTest("/test/DeleteIT.testDeleteCriteria");
}
/**
* Delete Viridian City.
*/
@Test
public void testDeleteViridianCity() {
ClientUtils.callTest("/test/DeleteIT.testDeleteViridianCity");
}
}

View File

@@ -32,7 +32,7 @@ public class InsertIT {
* Verify simple create operation (persist) on a single database row.
*/
@Test
public void testUpdateEntity() {
public void testInsertType() {
ClientUtils.callTest("/test/InsertIT.testInsertType");
}
@@ -41,8 +41,16 @@ public class InsertIT {
* Relations are not marked for cascade persist operation so every entity instance has to be persisted separately.
*/
@Test
public void testUpdateJPQL() {
public void testInsertTrainerWithPokemons() {
ClientUtils.callTest("/test/InsertIT.testInsertTrainerWithPokemons");
}
/**
* Verify complex create operation (persist) on a full ORM model (Lt. Surge in Vermilion City).
*/
@Test
public void testInsertTownWithStadium() {
ClientUtils.callTest("/test/InsertIT.testInsertTownWithStadium");
}
}

View File

@@ -59,4 +59,20 @@ public class QueryIT {
ClientUtils.callTest("/test/QueryIT.testQueryCriteria");
}
/**
* Query Celadon city using JPQL.
*/
@Test
public void testQueryCeladonJPQL() {
ClientUtils.callTest("/test/QueryIT.testQueryCeladonJPQL");
}
/**
* Query Celadon city using CriteriaQuery.
*/
@Test
public void testQueryCeladonCriteria() {
ClientUtils.callTest("/test/QueryIT.testQueryCeladonCriteria");
}
}

View File

@@ -61,4 +61,14 @@ public class UpdateIT {
ClientUtils.callTest("/test/UpdateIT.testUpdateCriteria");
}
/**
* Update Saffron City data structure.
* Replace stadium trainer with new guy who will get all pokemons from previous trainer.
* Also Alakazam evolves to Mega Alakazam at the same time.
*/
@Test
public void testUpdateSaffron() {
ClientUtils.callTest("/test/UpdateIT.testUpdateSaffron");
}
}

View File

@@ -17,9 +17,12 @@ package io.helidon.tests.integration.jpa.dao;
import java.util.Arrays;
import java.util.List;
import javax.persistence.EntityManager;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Trainer;
import io.helidon.tests.integration.jpa.model.Type;
@@ -115,7 +118,7 @@ public class Create {
/**
* Create Misty and her pokemons.
* Misty and her pokemons are used for update tests only.
* Misty and her pokemons are used for delete tests only.
*
* @param em Entity manager instance
*/
@@ -137,4 +140,70 @@ public class Create {
em.getEntityManagerFactory().getCache().evictAll();
}
/**
* Create Celadon City with stadium and trainer.
* Used for query tests only.
*/
public static void dbInsertCeladon(final EntityManager em) {
Type poison = em.find(Type.class, 4);
Type grass = em.find(Type.class, 12);
Type psychic = em.find(Type.class, 14);
Trainer trainer = new Trainer("Erika", 16);
Stadium stadium = new Stadium("Celadon Gym", trainer);
City city = new City("Celadon City", "Madam Celadon", stadium);
em.persist(trainer);
em.persist(new Pokemon(trainer, "Gloom", 651, Arrays.asList(grass, poison)));
em.persist(new Pokemon(trainer, "Victreebel", 751, Arrays.asList(grass, poison)));
em.persist(new Pokemon(trainer, "Tangela", 234, Arrays.asList(grass)));
em.persist(new Pokemon(trainer, "Vileplume", 1571, Arrays.asList(grass, poison)));
em.persist(new Pokemon(trainer, "Weepinbell", 1923, Arrays.asList(grass, poison)));
em.persist(new Pokemon(trainer, "Exeggcute", 317, Arrays.asList(grass, psychic)));
//em.persist(stadium);
em.persist(city);
}
/**
* Create Saffron City with stadium and trainer.
* Used for update tests only.
*/
public static void dbInsertSaffron(final EntityManager em) {
Type fighting = em.find(Type.class, 2);
Type psychic = em.find(Type.class, 14);
Type ice = em.find(Type.class, 15);
Trainer trainer = new Trainer("Sabrina", 23);
Stadium stadium = new Stadium("Saffron Gym", trainer);
City city = new City("Saffron City", "Koichi", stadium);
em.persist(trainer);
em.persist(new Pokemon(trainer, "Alakazam", 2178, Arrays.asList(psychic)));
em.persist(new Pokemon(trainer, "Espeon", 2745, Arrays.asList(psychic)));
em.persist(new Pokemon(trainer, "Mr. Mime", 1478, Arrays.asList(psychic)));
em.persist(new Pokemon(trainer, "Jynx", 2471, Arrays.asList(psychic, ice)));
em.persist(new Pokemon(trainer, "Wobbuffet", 1478, Arrays.asList(psychic)));
em.persist(new Pokemon(trainer, "Gallade", 2147, Arrays.asList(psychic, fighting)));
//em.persist(stadium);
em.persist(city);
}
/**
* Create Viridian City with stadium and trainer.
* Used for delete tests only.
*/
public static void dbInsertViridian(final EntityManager em) {
Type poison = em.find(Type.class, 4);
Type ground = em.find(Type.class, 5);
Type rock = em.find(Type.class, 6);
Trainer trainer = new Trainer("Giovanni", 37);
Stadium stadium = new Stadium("Viridian Gym", trainer);
City city = new City("Viridian City", "Koichi", stadium);
em.persist(trainer);
em.persist(new Pokemon(trainer, "Rhyperior", 3841, Arrays.asList(ground, rock)));
em.persist(new Pokemon(trainer, "Golem", 3651, Arrays.asList(ground, rock)));
em.persist(new Pokemon(trainer, "Nidoking", 2451, Arrays.asList(ground, poison)));
em.persist(new Pokemon(trainer, "Marowak", 2249, Arrays.asList(ground)));
em.persist(new Pokemon(trainer, "Sandslash", 1953, Arrays.asList(ground)));
em.persist(new Pokemon(trainer, "Nidoqueen", 3147, Arrays.asList(ground)));
//em.persist(stadium);
em.persist(city);
}
}

View File

@@ -19,7 +19,9 @@ import java.util.List;
import javax.persistence.EntityManager;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.Trainer;
/**
@@ -61,6 +63,60 @@ public class Delete {
dbDeleteTrainerAndHisPokemons(em, "Ash Ketchum");
}
/**
* Delete Celadon City.
* Celadon City is used for query tests only.
*
* @param em Entity manager instance
*/
public static void dbDeleteCeladon(final EntityManager em) {
dbDeleteCity(em, "Celadon City");
}
/**
* Delete Saffron City.
* Saffron City is used for update tests only.
*
* @param em Entity manager instance
*/
public static void dbDeleteSaffron(final EntityManager em) {
dbDeleteCity(em, "Saffron City");
}
/**
* Delete Viridian City.
* Viridian City is used for update tests only.
*
* @param em Entity manager instance
*/
public static void dbDeleteViridian(final EntityManager em) {
dbDeleteCity(em, "Viridian City");
}
/**
* Delete city.
*
* @param em Entity manager instance
* @param name name of city to delete
*/
public static void dbDeleteCity(final EntityManager em, final String name) {
List<City> cities = em.createQuery(
"SELECT c FROM City c WHERE c.name = :name", City.class)
.setParameter("name", name)
.getResultList();
if (!cities.isEmpty()) {
cities.forEach((city) -> {
Stadium stadium = city.getStadium();
Trainer trainer = stadium.getTrainer();
List<Pokemon> pokemons = trainer.getPokemons();
em.remove(city);
//em.remove(stadium);
pokemons.forEach((pokemon) -> em.remove(pokemon));
em.remove(trainer);
});
}
}
/**
* Delete trainer and his pokemons.
* Trainer is identified by his name.
@@ -69,16 +125,20 @@ public class Delete {
* @param name name of trainer to delete
*/
public static void dbDeleteTrainerAndHisPokemons(final EntityManager em, final String name) {
Trainer trainer = em.createQuery(
List<Trainer> trainers = em.createQuery(
"SELECT t FROM Trainer t WHERE t.name = :name", Trainer.class)
.setParameter("name", name)
.getSingleResult();
List<Pokemon> pokemons = em.createQuery(
"SELECT p FROM Pokemon p INNER JOIN p.trainer t WHERE t.name = :name", Pokemon.class)
.setParameter("name", name)
.getResultList();
pokemons.forEach((pokemon) -> em.remove(pokemon));
em.remove(trainer);
if (!trainers.isEmpty()) {
trainers.forEach((trainer) -> {
List<Pokemon> pokemons = em.createQuery(
"SELECT p FROM Pokemon p INNER JOIN p.trainer t WHERE t.name = :name", Pokemon.class)
.setParameter("name", name)
.getResultList();
pokemons.forEach((pokemon) -> em.remove(pokemon));
em.remove(trainer);
});
}
}
/**
@@ -108,12 +168,32 @@ public class Delete {
em.createQuery("DELETE FROM Type").executeUpdate();
}
/**
* Delete all cities.
*
* @param em Entity manager instance
*/
public static void deleteCities(final EntityManager em) {
em.createQuery("DELETE FROM City").executeUpdate();
}
/**
* Delete all stadiums.
*
* @param em Entity manager instance
*/
public static void deleteStadiums(final EntityManager em) {
em.createQuery("DELETE FROM Stadium").executeUpdate();
}
/**
* Delete all database records.
*
* @param em Entity manager instance
*/
public static void dbCleanup(final EntityManager em) {
deleteCities(em);
deleteStadiums(em);
deletePokemons(em);
deleteTrainers(em);
deleteTypes(em);

View File

@@ -0,0 +1,116 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.tests.integration.jpa.model;
import java.util.Objects;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.MapsId;
import javax.persistence.OneToOne;
/**
* City in pokemon world
*/
@Entity
public class City extends Settlement {
private String mayor;
@OneToOne(cascade = CascadeType.ALL)
@MapsId
private Stadium stadium;
public City() {
}
public City(String name, String mayor, Stadium stadium) {
super(name);
this.mayor = mayor;
this.stadium = stadium;
}
public String getMayor() {
return mayor;
}
public void setMayor(String mayor) {
this.mayor = mayor;
}
public Stadium getStadium() {
return stadium;
}
public void setStadium(Stadium stadium) {
this.stadium = stadium;
}
@Override
public boolean equals(Object oth) {
if (this == oth) {
return true;
}
if (oth == null) {
return false;
}
if (super.equals(oth) && (oth instanceof City)) {
return Objects.equals(mayor, ((City) oth).mayor)
&& Objects.equals(stadium, ((City) oth).stadium);
}
return false;
}
@Override
public int hashCode() {
int hashCode = super.hashCode();
if (mayor != null) {
hashCode = hashCode * 31 + mayor.hashCode();
}
if (stadium != null) {
hashCode = hashCode * 31 + stadium.hashCode();
}
return hashCode;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Town: {id=");
sb.append(getId());
sb.append(", name=");
if (getName() != null) {
sb.append('"').append(getName()).append('"');
} else {
sb.append("<null>");
}
sb.append(", mayor=");
if (mayor != null) {
sb.append('"').append(mayor).append('"');
} else {
sb.append("<null>");
}
sb.append(", stadium=");
if (stadium != null) {
sb.append('"').append(stadium.toString()).append('"');
} else {
sb.append("<null>");
}
sb.append('}');
return sb.toString();
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.tests.integration.jpa.model;
import java.util.Objects;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
/**
* Settlement in pokemon world.
*/
@MappedSuperclass
public class Settlement {
@Id
@GeneratedValue
private int id;
private String name;
public Settlement() {
}
public Settlement(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object oth) {
if (this == oth) {
return true;
}
if (oth == null) {
return false;
}
if (oth instanceof Settlement) {
return id == ((Settlement)oth).id
&& Objects.equals(name, ((Settlement)oth).name);
}
return false;
}
@Override
public int hashCode() {
int hashCode = id;
if (name != null) {
hashCode = hashCode * 31 + name.hashCode();
}
return hashCode;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Settlement: {id=");
sb.append(id);
sb.append(", name=");
if (name != null) {
sb.append('"').append(name).append('"');
} else {
sb.append("<null>");
}
sb.append('}');
return sb.toString();
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.tests.integration.jpa.model;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
/**
* Pokemon stadium.
*/
@Entity
public class Stadium {
@Id
@GeneratedValue
private int id;
private String name;
@ManyToOne
@JoinColumn(name = "trainer_id")
private Trainer trainer;
public Stadium() {
}
public Stadium(String name, Trainer trainer) {
this.name = name;
this.trainer = trainer;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Trainer getTrainer() {
return trainer;
}
public void setTrainer(Trainer trainer) {
this.trainer = trainer;
}
@Override
public boolean equals(Object oth) {
if (this == oth) {
return true;
}
if (oth == null) {
return false;
}
if (oth instanceof Stadium) {
return id == ((Stadium) oth).id
&& Objects.equals(name, ((Stadium) oth).name)
&& Objects.equals(trainer, ((Stadium) oth).trainer);
}
return false;
}
@Override
public int hashCode() {
int hashCode = id;
if (name != null) {
hashCode = hashCode * 31 + name.hashCode();
}
if (name != null) {
hashCode = hashCode * 31 + trainer.hashCode();
}
return hashCode;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Stadium: {id=");
sb.append(id);
sb.append(", name=");
if (name != null) {
sb.append('"').append(name).append('"');
} else {
sb.append("<null>");
}
sb.append(", trainer=");
if (trainer != null) {
sb.append('"').append(trainer.toString()).append('"');
} else {
sb.append("<null>");
}
sb.append('}');
return sb.toString();
}
}

View File

@@ -42,34 +42,15 @@ public class DbUtils {
* @param pu persistence unit context
*/
public static void dbInit(PU pu) {
dbInsertTypes(pu);
dbInsertAsh(pu);
Create.dbInsertTypes(pu.getEm());
ASH_ID = Create.dbInsertAsh(pu.getEm());
Create.dbInsertCeladon(pu.getEm());
pu.getEm().flush();
pu.getEm().clear();
pu.getEm().getEntityManagerFactory().getCache().evictAll();
}
/**
* Insert pokemon types.
*
* @param pu persistence unit context
*/
public static void dbInsertTypes(PU pu) {
final EntityManager em = pu.getEm();
Create.dbInsertTypes(em);
}
/**
* Insert trainer Ash and his pokemons.
*
* @param pu persistence unit context
*/
public static void dbInsertAsh(PU pu) {
final EntityManager em = pu.getEm();
ASH_ID = Create.dbInsertAsh(em);
}
/**
* Delete all database records.
*
@@ -108,4 +89,22 @@ public class DbUtils {
return q.getResultList();
}
/**
* Find pokemon by name from pokemon List.
*
* @param pokemons List to search
* @param name name of pokemon
* @return found pokemon or null when no such pokemon exists
*/
public static Pokemon findPokemonByName(List<Pokemon> pokemons, String name) {
if (pokemons != null && !pokemons.isEmpty()) {
for (Pokemon pokemon : pokemons) {
if (pokemon.getName().equals(name)) {
return pokemon;
}
}
}
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (city) 2020 Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,10 @@ import javax.persistence.criteria.Root;
import io.helidon.tests.integration.jpa.dao.Create;
import io.helidon.tests.integration.jpa.dao.Delete;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.Trainer;
import io.helidon.tests.integration.jpa.simple.PU;
import org.junit.jupiter.api.AfterAll;
@@ -48,6 +51,7 @@ public class DeleteIT {
pu.tx(pu -> {
final EntityManager em = pu.getEm();
Create.dbInsertMisty(em);
Create.dbInsertViridian(em);
});
}
@@ -56,6 +60,7 @@ public class DeleteIT {
pu.tx(pu -> {
final EntityManager em = pu.getEm();
Delete.dbDeleteMisty(em);
Delete.dbDeleteViridian(em);
});
}
@@ -145,4 +150,32 @@ public class DeleteIT {
});
}
/**
* Delete Viridian City.
*/
@Test
public void testDeleteViridianCity() {
pu.tx(pu -> {
final EntityManager em = pu.getEm();
City city = em.createQuery(
"SELECT c FROM City c WHERE c.name = :name", City.class)
.setParameter("name", "Viridian City")
.getSingleResult();
Stadium stadium = city.getStadium();
Trainer trainer = stadium.getTrainer();
List<Pokemon> pokemons = trainer.getPokemons();
em.remove(city);
em.remove(trainer);
pokemons.forEach(poklemon -> em.remove(poklemon));
});
pu.tx(pu -> {
final EntityManager em = pu.getCleanEm();
List<City> cities = em.createQuery(
"SELECT c FROM City c WHERE c.name = :name", City.class)
.setParameter("name", "Viridian City")
.getResultList();
assertTrue(cities.isEmpty());
});
}
}

View File

@@ -17,11 +17,14 @@ package io.helidon.tests.integration.jpa.simple.test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Trainer;
import io.helidon.tests.integration.jpa.model.Type;
import io.helidon.tests.integration.jpa.simple.PU;
@@ -31,6 +34,7 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Verify create/insert operations of ORM.
@@ -41,6 +45,8 @@ public class InsertIT {
private static final Set<Integer> DELETE_POKEMONS = new HashSet<>();
private static final Set<Integer> DELETE_TRAINERS = new HashSet<>();
private static final Set<Integer> DELETE_STADIUMS = new HashSet<>();
private static final Set<Integer> DELETE_TOWNS = new HashSet<>();
@BeforeAll
public static void setup() {
@@ -55,18 +61,30 @@ public class InsertIT {
em.createQuery("DELETE FROM Type t WHERE t.id = :id")
.setParameter("id", 20)
.executeUpdate();
// Towns cleanup
DELETE_TOWNS.forEach((id) -> {
em.createQuery("DELETE FROM City c WHERE c.id = :id")
.setParameter("id", id)
.executeUpdate();
});
// Stadiums cleanup
DELETE_STADIUMS.forEach((id) -> {
em.createQuery("DELETE FROM Stadium s WHERE s.id = :id")
.setParameter("id", id)
.executeUpdate();
});
// Pokemons cleanup
for (int id : DELETE_POKEMONS) {
DELETE_POKEMONS.forEach((id) -> {
em.createQuery("DELETE FROM Pokemon p WHERE p.id = :id")
.setParameter("id", id)
.executeUpdate();
}
});
// Trainers cleanup
for (int id : DELETE_TRAINERS) {
DELETE_TRAINERS.forEach((id) -> {
em.createQuery("DELETE FROM Trainer t WHERE t.id = :id")
.setParameter("id", id)
.executeUpdate();
}
});
});
pu = null;
}
@@ -142,4 +160,63 @@ public class InsertIT {
});
}
/**
* Verify complex create operation (persist) on a full ORM model (Lt. Surge in Vermilion City).
*/
@Test
void testTownWithStadium() {
final Trainer[] trainers = new Trainer[1];
final Pokemon[] pokemons = new Pokemon[6];
final Stadium[] stadiums = new Stadium[1];
final City[] cities = new City[1];
pu.tx(pu -> {
final EntityManager em = pu.getEm();
Type steel = em.find(Type.class, 9);
Type electric = em.find(Type.class, 13);
trainers[0] = new Trainer("Lt. Surge", 28);
pokemons[0] = new Pokemon(trainers[0], "Raichu", 1521, Arrays.asList(electric));
pokemons[1] = new Pokemon(trainers[0], "Manectric", 1589, Arrays.asList(electric));
pokemons[2] = new Pokemon(trainers[0], "Magnezone", 1853, Arrays.asList(electric));
pokemons[3] = new Pokemon(trainers[0], "Electrode", 1237, Arrays.asList(electric));
pokemons[4] = new Pokemon(trainers[0], "Pachirisu", 942, Arrays.asList(electric));
pokemons[5] = new Pokemon(trainers[0], "Electivire", 1931, Arrays.asList(electric));
stadiums[0] = new Stadium("Vermilion Gym", trainers[0]);
cities[0] = new City("Vermilion City", "Mina", stadiums[0]);
em.persist(trainers[0]);
em.persist(pokemons[0]);
em.persist(pokemons[1]);
em.persist(pokemons[2]);
em.persist(pokemons[3]);
em.persist(pokemons[4]);
em.persist(pokemons[5]);
//em.persist(stadiums[0]);
em.persist(cities[0]);
em.flush();
});
pu.tx(pu -> {
final EntityManager em = pu.getCleanEm();
City dbCity = em.find(City.class, cities[0].getId());
Stadium dbStadium = dbCity.getStadium();
Trainer dbTrainer = dbStadium.getTrainer();
List<Pokemon> dbPokemons = dbTrainer.getPokemons();
Set<Pokemon> pokemonSet = new HashSet<>(pokemons.length);
for (Pokemon pokemon : pokemons) {
pokemonSet.add(pokemon);
}
for (Pokemon dbPokemon : dbPokemons) {
assertTrue(pokemonSet.remove(dbPokemon));
}
assertTrue(pokemonSet.isEmpty());
assertEquals(trainers[0], dbTrainer);
assertEquals(stadiums[0], dbStadium);
assertEquals(cities[0], dbCity);
for (Pokemon pokemon : pokemons) {
DELETE_POKEMONS.add(pokemon.getId());
}
DELETE_TRAINERS.add(dbTrainer.getId());
DELETE_STADIUMS.add(dbStadium.getId());
DELETE_TOWNS.add(dbCity.getId());
});
}
}

View File

@@ -20,9 +20,12 @@ import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.Trainer;
import io.helidon.tests.integration.jpa.simple.DbUtils;
import io.helidon.tests.integration.jpa.simple.PU;
@@ -31,6 +34,7 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -83,7 +87,7 @@ public class QueryIT {
}
/**
* Query trainer Ash and his pokemons using JPQL.
* Query trainer Ash and his pokemons using CriteriaQuery.
*/
@Test
public void testQueryCriteria() {
@@ -101,4 +105,46 @@ public class QueryIT {
});
}
}
/**
* Query Celadon city using JPQL.
*/
@Test
public void testQueryCeladonJPQL() {
pu.tx(pu -> {
final EntityManager em = pu.getCleanEm();
City city = em.createQuery(
"SELECT c FROM City c "
+ "JOIN FETCH c.stadium s "
+ "JOIN FETCH s.trainer t "
+ "WHERE c.name = :name", City.class)
.setParameter("name", "Celadon City")
.getSingleResult();
assertEquals(city.getName(), "Celadon City");
assertEquals(city.getStadium().getName(), "Celadon Gym");
assertEquals(city.getStadium().getTrainer().getName(), "Erika");
});
}
/**
* Query Celadon city using CriteriaQuery.
*/
@Test
public void testQueryCeladonCriteria() {
pu.tx(pu -> {
final EntityManager em = pu.getCleanEm();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<City> cq = cb.createQuery(City.class);
Root<City> cityRoot = cq.from(City.class);
cityRoot
.fetch("stadium")
.fetch("trainer");
cq.select(cityRoot)
.where(cb.equal(cityRoot.get("name"), "Celadon City"));
City city = em.createQuery(cq).getSingleResult();
assertEquals(city.getName(), "Celadon City");
assertEquals(city.getStadium().getName(), "Celadon Gym");
assertEquals(city.getStadium().getTrainer().getName(), "Erika");
});
}
}

View File

@@ -15,6 +15,11 @@
*/
package io.helidon.tests.integration.jpa.simple.test;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
@@ -23,7 +28,11 @@ import javax.persistence.criteria.Root;
import io.helidon.tests.integration.jpa.dao.Create;
import io.helidon.tests.integration.jpa.dao.Delete;
import io.helidon.tests.integration.jpa.model.City;
import io.helidon.tests.integration.jpa.model.Pokemon;
import io.helidon.tests.integration.jpa.model.Stadium;
import io.helidon.tests.integration.jpa.model.Trainer;
import io.helidon.tests.integration.jpa.simple.DbUtils;
import io.helidon.tests.integration.jpa.simple.PU;
import org.junit.jupiter.api.AfterAll;
@@ -31,6 +40,7 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Verify update operations on ORM.
@@ -39,32 +49,24 @@ public class UpdateIT {
private static PU pu;
// Brock and his pokemons are used for update tests only
private static void dbInsertBrock() {
pu.tx(pu -> {
final EntityManager em = pu.getEm();
Create.dbInsertBrock(em);
});
}
// Delete Brock and his pokemons after update tests
private static void dbDeleteBrock() {
pu.tx(pu -> {
final EntityManager em = pu.getEm();
Delete.dbDeleteBrock(em);
});
}
@BeforeAll
public static void setup() {
pu = PU.getInstance();
dbInsertBrock();
pu.tx(pu -> {
final EntityManager em = pu.getEm();
Create.dbInsertBrock(em);
Create.dbInsertSaffron(em);
});
}
@AfterAll
public static void destroy() {
dbDeleteBrock();
pu = null;
pu.tx(pu -> {
final EntityManager em = pu.getEm();
Delete.dbDeleteBrock(em);
Delete.dbDeleteSaffron(em);
pu = null;
});
}
/**
@@ -146,6 +148,61 @@ public class UpdateIT {
assertEquals(1568, dbUrsaring.getCp());
});
}
/**
* Update Saffron City data structure.
* Replace stadium trainer with new guy who will get all pokemons from previous trainer.
* Also Alakazam evolves to Mega Alakazam at the same time.
*/
@Test
public void testUpdateSaffron() {
City[] cities = new City[1];
Set<String> pokemonNames = new HashSet<>(6);
pu.tx(pu -> {
final EntityManager em = pu.getEm();
cities[0] = em.createQuery(
"SELECT c FROM City c WHERE c.name = :name", City.class)
.setParameter("name", "Saffron City")
.getSingleResult();
Stadium stadium = cities[0].getStadium();
Trainer sabrina = stadium.getTrainer();
Trainer janine = new Trainer("Janine", 24);
stadium.setTrainer(janine);
List<Pokemon> pokemons = sabrina.getPokemons();
janine.setPokemons(pokemons);
sabrina.setPokemons(Collections.EMPTY_LIST);
em.remove(sabrina);
em.persist(janine);
for (Pokemon pokemon : pokemons) {
pokemon.setTrainer(janine);
pokemonNames.add(pokemon.getName());
em.persist(pokemon);
}
em.persist(stadium);
Pokemon alkazam = DbUtils.findPokemonByName(pokemons, "Alakazam");
System.out.println("TRAINER: "+alkazam.getTrainer().getName());
// Update pokemon by query
em.createQuery(
"UPDATE Pokemon p SET p.name = :newName, p.cp = :newCp WHERE p.id = :id")
.setParameter("newName", "Mega Alakazam")
.setParameter("newCp", 4348)
.setParameter("id", alkazam.getId())
.executeUpdate();
pokemonNames.remove("Alakazam");
pokemonNames.add("Mega Alakazam");
});
pu.tx(pu -> {
final EntityManager em = pu.getCleanEm();
City city = em.find(City.class, cities[0].getId());
Stadium stadium = city.getStadium();
Trainer trainer = stadium.getTrainer();
em.refresh(trainer);
List<Pokemon> pokemons = trainer.getPokemons();
assertEquals(trainer.getName(), "Janine");
for (Pokemon pokemon : pokemons) {
assertTrue(pokemonNames.remove(pokemon.getName()), "Pokemon " + pokemon.getName() + " is missing");
}
});
}
}

View File

@@ -25,6 +25,8 @@
<class>io.helidon.tests.integration.jpa.model.Type</class>
<class>io.helidon.tests.integration.jpa.model.Trainer</class>
<class>io.helidon.tests.integration.jpa.model.Pokemon</class>
<class>io.helidon.tests.integration.jpa.model.Stadium</class>
<class>io.helidon.tests.integration.jpa.model.City</class>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.create-source" value="metadata"/>