mirror of
https://github.com/jlengrand/helidon.git
synced 2026-03-10 08:21:17 +00:00
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:
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"annotated":[
|
||||
"javax.persistence.Entity"
|
||||
"javax.persistence.Entity",
|
||||
"javax.persistence.MappedSuperclass"
|
||||
],
|
||||
"class-hierarchy": [
|
||||
"javax.xml.stream.XMLEventFactory",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -62,4 +62,12 @@ public class DeleteIT {
|
||||
ClientUtils.callTest("/test/DeleteIT.testDeleteCriteria");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Viridian City.
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteViridianCity() {
|
||||
ClientUtils.callTest("/test/DeleteIT.testDeleteViridianCity");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
Reference in New Issue
Block a user