blob: 8a238ae8fcf2a034357f151be8506a61f4366cd0 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
// 04/07/2012-2.5 Guy Pelletier
// - 384275: Customizer from a mapped superclass is not overridden by an entity customizer
package org.eclipse.persistence.testing.tests.jpa.inheritance;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.persistence.config.HintValues;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.invalidation.TimeToLiveCacheInvalidationPolicy;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.indirection.IndirectList;
import org.eclipse.persistence.indirection.IndirectSet;
import org.eclipse.persistence.mappings.CollectionMapping;
import org.eclipse.persistence.sessions.server.ServerSession;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import org.eclipse.persistence.testing.models.jpa.inheritance.AAA;
import org.eclipse.persistence.testing.models.jpa.inheritance.Betta;
import org.eclipse.persistence.testing.models.jpa.inheritance.Bicycle;
import org.eclipse.persistence.testing.models.jpa.inheritance.Bus;
import org.eclipse.persistence.testing.models.jpa.inheritance.CitrusFruit;
import org.eclipse.persistence.testing.models.jpa.inheritance.Company;
import org.eclipse.persistence.testing.models.jpa.inheritance.DDD;
import org.eclipse.persistence.testing.models.jpa.inheritance.Fish;
import org.eclipse.persistence.testing.models.jpa.inheritance.FishTank;
import org.eclipse.persistence.testing.models.jpa.inheritance.InheritanceTableCreator;
import org.eclipse.persistence.testing.models.jpa.inheritance.PerformanceTireInfo;
import org.eclipse.persistence.testing.models.jpa.inheritance.Seed;
import org.eclipse.persistence.testing.models.jpa.inheritance.SeededFruit;
import org.eclipse.persistence.testing.models.jpa.inheritance.SeniorEngineer;
import org.eclipse.persistence.testing.models.jpa.inheritance.SportsCar;
import org.eclipse.persistence.testing.models.jpa.inheritance.Car;
import org.eclipse.persistence.testing.models.jpa.inheritance.Person;
import org.eclipse.persistence.testing.models.jpa.inheritance.PetStore;
import org.eclipse.persistence.testing.models.jpa.inheritance.Engineer;
import org.eclipse.persistence.testing.models.jpa.inheritance.Computer;
import org.eclipse.persistence.testing.models.jpa.inheritance.ComputerPK;
import org.eclipse.persistence.testing.models.jpa.inheritance.Desktop;
import org.eclipse.persistence.testing.models.jpa.inheritance.Laptop;
import org.eclipse.persistence.testing.models.jpa.inheritance.TireInfo;
import org.eclipse.persistence.testing.models.jpa.inheritance.VehicleDirectory;
import junit.framework.Test;
import junit.framework.TestSuite;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.Query;
public class EntityManagerJUnitTestCase extends JUnitTestCase {
public EntityManagerJUnitTestCase() {
super();
}
public EntityManagerJUnitTestCase(String name) {
super(name);
}
public static Test suite() {
TestSuite suite = new TestSuite();
suite.setName("EntityManagerJUnitTestCase");
suite.addTest(new EntityManagerJUnitTestCase("testSetup"));
suite.addTest(new EntityManagerJUnitTestCase("testOverriddenCustomizer"));
suite.addTest(new EntityManagerJUnitTestCase("testAddToUninstantiatedSet"));
suite.addTest(new EntityManagerJUnitTestCase("testAddDuplicateToUninstantiatedSet"));
suite.addTest(new EntityManagerJUnitTestCase("testAssociationWithEmbeddedIdSubclassEntityInJoinedStrategy"));
suite.addTest(new EntityManagerJUnitTestCase("testGenericCollectionOnSuperclass"));
suite.addTest(new EntityManagerJUnitTestCase("testLazyListInstantiationEager"));
suite.addTest(new EntityManagerJUnitTestCase("testLazyListInstantiationLazy"));
suite.addTest(new EntityManagerJUnitTestCase("testLazySetInstantiationEager"));
suite.addTest(new EntityManagerJUnitTestCase("testMapKeyInheritance"));
suite.addTest(new EntityManagerJUnitTestCase("testPersistPolymorphicRelationship"));
suite.addTest(new EntityManagerJUnitTestCase("testRemoveInheritedManyToMany"));
suite.addTest(new EntityManagerJUnitTestCase("testUpateTireInfo"));
suite.addTest(new EntityManagerJUnitTestCase("testUpateTireInfo"));
// EL bug 336486
suite.addTest(new EntityManagerJUnitTestCase("testCacheExpiryInitializationForInheritance"));
// Bug 404071
suite.addTest(new EntityManagerJUnitTestCase("testJoinedInheritanceOneToManyJoinFetch"));
// Bug 415526
suite.addTest(new EntityManagerJUnitTestCase("testCascadeMergeWithTargetInheritance"));
// Bug 458177
suite.addTest(new EntityManagerJUnitTestCase("testJoinedInheritanceWithAbstractSuperclass"));
// Bug 355721
suite.addTest(new EntityManagerJUnitTestCase("testJoinedInheritancePersistWithReadOnlyEntity"));
return suite;
}
/**
* The setup is done as a test, both to record its failure, and to allow execution in the server.
*/
public void testSetup() {
new InheritanceTableCreator().replaceTables(JUnitTestCase.getServerSession());
clearCache();
}
// gf issue 1356 - persisting a polymorphic relationship throws a NPE.
// The order of persist operations is important for this test.
public void testPersistPolymorphicRelationship() {
EntityManager em = createEntityManager();
beginTransaction(em);
Person p = new Person();
p.setName("Evil Knievel");
SportsCar c = new SportsCar();
c.setDescription("Ferrari");
c.setMaxSpeed(200);
p.setCar(c);
try {
em.persist(c);
em.persist(p);
commitTransaction(em);
} catch (Exception exception ) {
fail("Error persisting polymorphic relationship: " + exception.getMessage());
} finally {
closeEntityManager(em);
}
}
public void testCacheExpiryInitializationForInheritance() {
ServerSession session = JUnitTestCase.getServerSession();
ClassDescriptor personDescriptor = session.getDescriptor(Person.class); // parent
ClassDescriptor engineerDescriptor = session.getDescriptor(Engineer.class); // subclass
ClassDescriptor seniorEngineerDescriptor = session.getDescriptor(SeniorEngineer.class); // subclass of subclass
// Policy existence check
assertNotNull("personDescriptor's cacheInvalidationPolicy should not be null",
personDescriptor.getCacheInvalidationPolicy());
assertNotNull("engineerDescriptor's cacheInvalidationPolicy should not be null",
engineerDescriptor.getCacheInvalidationPolicy());
assertNotNull("seniorEngineerDescriptor's cacheInvalidationPolicy should not be null",
seniorEngineerDescriptor.getCacheInvalidationPolicy());
// Policy class check
assertTrue("personDescriptor's cacheInvalidationPolicy should be TimeToLiveCacheInvalidationPolicy",
personDescriptor.getCacheInvalidationPolicy() instanceof TimeToLiveCacheInvalidationPolicy);
assertTrue("engineerDescriptor's cacheInvalidationPolicy should be TimeToLiveCacheInvalidationPolicy",
engineerDescriptor.getCacheInvalidationPolicy() instanceof TimeToLiveCacheInvalidationPolicy);
assertTrue("seniorEngineerDescriptor's cacheInvalidationPolicy should be TimeToLiveCacheInvalidationPolicy",
seniorEngineerDescriptor.getCacheInvalidationPolicy() instanceof TimeToLiveCacheInvalidationPolicy);
// Subclass clone check
assertFalse("engineerDescriptor's cacheInvalidationPolicy should be a clone",
engineerDescriptor.getCacheInvalidationPolicy() == personDescriptor.getCacheInvalidationPolicy());
assertFalse("seniorEngineerDescriptor's cacheInvalidationPolicy should be a clone",
seniorEngineerDescriptor.getCacheInvalidationPolicy() == personDescriptor.getCacheInvalidationPolicy());
// Subclass TTL check
long ttl = ((TimeToLiveCacheInvalidationPolicy)personDescriptor.getCacheInvalidationPolicy()).getTimeToLive();
assertEquals("engineerDescriptor's invalidation TTL should be " + ttl,
ttl, ((TimeToLiveCacheInvalidationPolicy)engineerDescriptor.getCacheInvalidationPolicy()).getTimeToLive());
assertEquals("seniorEngineerDescriptor's invalidation TTL should be " + ttl,
ttl, ((TimeToLiveCacheInvalidationPolicy)seniorEngineerDescriptor.getCacheInvalidationPolicy()).getTimeToLive());
}
/**
* Verifies that alias name is not customized from an invalid customizer.
*/
public void testOverriddenCustomizer() {
ServerSession session = JUnitTestCase.getServerSession();
ClassDescriptor computerDescriptor = session.getDescriptor(Computer.class);
assertFalse("Computer alias was incorrect", computerDescriptor.getAlias().equals("InvalidAliasName"));
}
// test if we can associate with a subclass entity
// whose root entity has EmbeddedId in Joined inheritance strategy
// Issue: GF#1153 && GF#1586 (desktop amendment)
public void testAssociationWithEmbeddedIdSubclassEntityInJoinedStrategy() {
EntityManager em = createEntityManager();
beginTransaction(em);
try {
Engineer engineer = new Engineer();
em.persist(engineer);
ComputerPK laptopPK = new ComputerPK("Dell", 10001);
Laptop laptop = em.find(Laptop.class, laptopPK);
if (laptop == null){
laptop = new Laptop(laptopPK);
em.persist(laptop);
}
ComputerPK desktopPK = new ComputerPK("IBM", 10002);
Desktop desktop = em.find(Desktop.class, desktopPK);
if (desktop == null){
desktop = new Desktop(desktopPK);
em.persist(desktop);
}
// associate many-to-many relationships
engineer.getLaptops().add(laptop);
engineer.getDesktops().add(desktop);
commitTransaction(em);
} catch(RuntimeException ex) {
if (isTransactionActive(em)) {
rollbackTransaction(em);
}
throw ex;
} finally {
closeEntityManager(em);
}
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=241979
public void testUpateTireInfo(){
EntityManager em = createEntityManager();
beginTransaction(em);
TireInfo tireInfo = new TireInfo();
tireInfo.setPressure(35);
em.persist(tireInfo);
commitTransaction(em);
beginTransaction(em);
TireInfo localTire = em.find(TireInfo.class, tireInfo.getId());
assertTrue("TireInfo was not persisted with the proper pressure", localTire.getPressure().equals(35));
localTire.setPressure(40);
commitTransaction(em);
em.clear();
localTire = em.find(TireInfo.class, tireInfo.getId());
assertTrue("TireInfo was not updated", localTire.getPressure().equals(40));
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=312253
// Note: this test will potentially fail in a number of different ways
// see the above bug for details of the non-derminism
// also: This test only tests the above bug when weaving is disabled
// also note: This test is testing for exceptions on the final flush, that
// is why where are no asserts
public void testMapKeyInheritance(){
EntityManager em = createEntityManager();
beginTransaction(em);
VehicleDirectory directory = new VehicleDirectory();
directory.setName("MyVehicles");
em.persist(directory);
Company company = new Company();
company.setName("A Blue Company");
em.persist(company);
em.flush();
Car car = new Car();
car.setDescription("a Blue Car");
car.setOwner(company);
em.persist(car);
directory.getVehicleDirectory().put(car.getOwner(), car);
company.getVehicles().add(car);
try{
em.flush();
} catch(RuntimeException e){
fail("Exception was thrown while flushing a MapKey with inheritance. " + e.getMessage());
}
rollbackTransaction(em);;
}
public void testRemoveInheritedManyToMany(){
EntityManager em = createEntityManager();
beginTransaction(em);
try{
SeniorEngineer eng = new SeniorEngineer();
eng.setName("Vela");
em.persist(eng);
Laptop laptop = new Laptop();
ComputerPK pk = new ComputerPK("Dell", 2111);
laptop.setComputerPK(pk);
em.persist(laptop);
eng.getLaptops().add(laptop);
em.flush();
em.remove(eng);
em.flush();
} catch (PersistenceException ex){
if (ex.getCause() instanceof DatabaseException){
// An Integrity Constraint Violation was the reason for the initial exception
fail("SQLException thrown when removing an object that inherits a ManyToMany");
} else {
fail("UnexpectedException thrown");
}
} finally {
rollbackTransaction(em);
}
}
// Bug 336133
public void testGenericCollectionOnSuperclass(){
EntityManager em = createEntityManager();
beginTransaction(em);
try{
Bus bus = new Bus();
bus.setDescription("a fast bus");
PerformanceTireInfo tire = new PerformanceTireInfo();
tire.setPressure(100);
bus.getTires().add(tire);
em.persist(bus);
em.flush();
em.clear();
clearCache();
bus = em.find(Bus.class, bus.getId());
assertNotNull("Bus is null.", bus);
assertTrue("Bus has no tires.", bus.getTires().size() == 1);
} finally {
rollbackTransaction(em);
}
}
// bug 325035
public void testAddToUninstantiatedSet(){
EntityManager em = createEntityManager();
beginTransaction(em);
AAA a = new AAA();
em.persist(a);
DDD d = new DDD();
em.persist(d);
Set<DDD> ds = new HashSet<DDD>();
ds.add(d);
a.setDdds(ds);
d.setAaa(a);
commitTransaction(em);
clearCache();
try{
em = createEntityManager();
beginTransaction(em);
a = em.getReference(AAA.class, a.getId());
a.getDdds().add(d);
d.setAaa(a);
commitTransaction(em);
assertTrue("The collection contains too many elements", a.getDdds().size() == 1);
} finally {
em = createEntityManager();
beginTransaction(em);
a = em.find(AAA.class, a.getId());
d = em.find(DDD.class, d.getId());
em.remove(a);
em.remove(d);
commitTransaction(em);
}
}
// bug391833 - Duplicate insert on lazy set with attribute change tracking
public void testAddDuplicateToUninstantiatedSet(){
String string1 = "String1";
EntityManager em = createEntityManager();
beginTransaction(em);
try{
AAA a = new AAA();
Set<String> ds = new HashSet<String>();
ds.add(string1);
a.setStringSet(ds);
em.persist(a);
em.flush();
em.clear();
a = em.find(AAA.class, a.getId());
em.refresh(a);
a.getStringSet().add(string1);
em.flush();
assertTrue("The collection contains too many elements", a.getStringSet().size() == 1);
java.util.List results = em.createQuery("select s from AAA a join a.stringSet s where a.id = "+a.getId()).getResultList();
assertTrue("The Database contains too many elements", results.size() == 1);
} finally {
if (this.isTransactionActive(em)) {
this.rollbackTransaction(em);
}
this.closeEntityManager(em);
}
}
// bug 325035
public void testLazySetInstantiationLazy(){
if (!isWeavingEnabled()){
return;
}
EntityManager em = createEntityManager();
CollectionMapping mapping = ((CollectionMapping)getServerSession().getProject().getClassDescriptor(AAA.class).getMappingForAttributeName("ddds"));
Boolean lazyIndirection = mapping.shouldUseLazyInstantiationForIndirectCollection();
mapping.setUseLazyInstantiationForIndirectCollection(true);
beginTransaction(em);
AAA a = new AAA();
em.persist(a);
DDD d = new DDD();
em.persist(d);
Set<DDD> ds = new HashSet<DDD>();
ds.add(d);
a.setDdds(ds);
d.setAaa(a);
commitTransaction(em);
clearCache();
try{
em = createEntityManager();
a = em.find(AAA.class, a.getId());
a.getDdds().add(new DDD());
assertTrue("Lazy instantiation was not enabled for IndirectSet.", ((IndirectSet)a.getDdds()).getAddedElements().size() == 1);
} finally {
em = createEntityManager();
beginTransaction(em);
a = em.find(AAA.class, a.getId());
d = em.find(DDD.class, d.getId());
em.remove(a);
em.remove(d);
commitTransaction(em);
mapping.setUseLazyInstantiationForIndirectCollection(lazyIndirection);
}
}
// bug 325035
public void testLazySetInstantiationEager(){
EntityManager em = createEntityManager();
beginTransaction(em);
AAA a = new AAA();
em.persist(a);
DDD d = new DDD();
em.persist(d);
Set<DDD> ds = new HashSet<DDD>();
ds.add(d);
a.setDdds(ds);
d.setAaa(a);
commitTransaction(em);
clearCache();
try{
em = createEntityManager();
a = em.find(AAA.class, a.getId());
a.getDdds().add(new DDD());
assertTrue("Lazy instantiation was not disabled for IndirectSet.", ((IndirectSet)a.getDdds()).getAddedElements().size() == 0);
} finally {
em = createEntityManager();
beginTransaction(em);
a = em.find(AAA.class, a.getId());
d = em.find(DDD.class, d.getId());
em.remove(a);
em.remove(d);
commitTransaction(em);
}
}
// bug 325035
public void testLazyListInstantiationLazy(){
if (!isWeavingEnabled()){
return;
}
EntityManager em = createEntityManager();
beginTransaction(em);
Company company = new Company();
company.setName("ListCo");
em.persist(company);
Car car = new Car();
em.persist(car);
company.getVehicles().add(car);
car.setOwner(company);
commitTransaction(em);
clearCache();
try{
em = createEntityManager();
company = em.find(Company.class, company.getId());
company.getVehicles().add(new Car());
assertTrue("Lazy instantiation was not enabled for IndirectList.", ((IndirectList)company.getVehicles()).getAddedElements().size() == 1);
} finally {
em = createEntityManager();
beginTransaction(em);
company = em.find(Company.class, company.getId());
car = em.find(Car.class, car.getId());
em.remove(company);
em.remove(car);
commitTransaction(em);
}
}
// bug 325035
public void testLazyListInstantiationEager(){
EntityManager em = createEntityManager();
CollectionMapping mapping = ((CollectionMapping)getServerSession().getProject().getClassDescriptor(Company.class).getMappingForAttributeName("vehicles"));
Boolean lazyIndirection = mapping.shouldUseLazyInstantiationForIndirectCollection();
mapping.setUseLazyInstantiationForIndirectCollection(false);
beginTransaction(em);
Company company = new Company();
company.setName("ListCo");
em.persist(company);
Car car = new Car();
em.persist(car);
company.getVehicles().add(car);
car.setOwner(company);
commitTransaction(em);
clearCache();
try{
em = createEntityManager();
company = em.find(Company.class, company.getId());
company.getVehicles().add(new Car());
assertTrue("Lazy instantiation was not disabled for IndirectList.", ((IndirectList)company.getVehicles()).getAddedElements().size() == 0);
} finally {
em = createEntityManager();
beginTransaction(em);
company = em.find(Company.class, company.getId());
car = em.find(Car.class, car.getId());
em.remove(company);
em.remove(car);
commitTransaction(em);
mapping.setUseLazyInstantiationForIndirectCollection(lazyIndirection);
}
}
// Bug 404071
public void testJoinedInheritanceOneToManyJoinFetch() {
EntityManager em = createEntityManager();
try {
beginTransaction(em);
CitrusFruit fruit = new CitrusFruit();
fruit.setName("Orange");
fruit.setGrade(1);
for (int i = 0; i < 4; i++) {
fruit.addSeed(new Seed());
}
em.persist(fruit);
commitTransaction(em);
em.clear();
clearCache();
// query on superclass
SeededFruit fruitRead = em.find(SeededFruit.class, fruit.getId());
assertNotNull("Fruit should not be null", fruitRead);
assertNotNull("Fruit's seeds should not be null", fruitRead.getSeeds());
assertTrue("Fruit's seeds should contain 4 elements", fruitRead.getSeeds().size() == 4);
} finally {
closeEntityManager(em);
}
}
// Bug 415526
public void testCascadeMergeWithTargetInheritance() {
EntityManager em = createEntityManager();
beginTransaction(em);
try {
Company company = new Company();
company.setName("CascadeMerge, Inc");
em.persist(company);
em.flush();
Bicycle bicycle = new Bicycle();
bicycle.setDescription("road bike");
company.getVehicles().add(bicycle);
bicycle.setOwner(company);
company = em.merge(company);
em.flush();
Number bicycleId = company.getVehicles().iterator().next().getId();
String classDiscriminatorValue = (String)em.createNativeQuery("SELECT VEH_TYPE FROM CMP3_VEHICLE WHERE ID = " + bicycleId).getSingleResult();
if (classDiscriminatorValue == null) {
fail("Class discriminator value written into the db for the merged Bicycle is null");
}
} finally {
rollbackTransaction(em);
closeEntityManager(em);
}
}
/*
* Added for Bug 458177
* - Instantiate a FishTank, unidirectionally lazy-referencing an
* abstract Entity (Fish). Persist.
* - Instantiate a Betta (concrete extension of Fish) and reference
* from FishTank's 'fishes' collection. Persist and commit.
* - Acquire new EM and retrieve cached FishTank. Remove Entity.
* - This 'simple' operation previously attempted to instantiate the abstract
* Fish class during UOW resume (Resulting in InstantiationException).
*/
public void testJoinedInheritanceWithAbstractSuperclass() {
Long tankId = null;
EntityManager em = createEntityManager();
try {
beginTransaction(em);
Betta fish = new Betta();
fish.setName("swimmy");
fish.setColor("blue");
em.persist(fish);
FishTank fishTank = new FishTank();
List<Fish> list = new ArrayList<Fish>();
list.add(fish);
fishTank.setFishes(list);
em.persist(fishTank);
tankId = fishTank.getId();
commitTransaction(em);
} finally {
closeEntityManager(em);
}
assertNotNull("FishTank ID should not be null", tankId);
em = createEntityManager();
try {
beginTransaction(em);
FishTank fishTank = em.find(FishTank.class, tankId);
assertNotNull("FishTank should not be null", fishTank);
em.remove(fishTank);
commitTransaction(em);
} finally {
closeEntityManager(em);
}
}
/*
* Added for Bug 355721
* - Instantiate and persist (but do not associate) a FishTank Entity and
* PetStore Entity.
* - Clear the EMF cache
* - Acquire new EM and retrieve the PetStore Entity
* - Retrieve all FishTank Entities with a RO NamedQuery
* - Associate the PetStore (lazy unidirectional 1:M) with a FishTank, persist.
* - This operation previously failed with a ClassCastException.
*/
public void testJoinedInheritancePersistWithReadOnlyEntity() {
EntityManager em = createEntityManager();
Long petStoreId = null;
try {
beginTransaction(em);
FishTank fishTank = new FishTank();
em.persist(fishTank);
PetStore petStore = new PetStore();
petStore.setStoreName("Bob's Fish");
petStore.setFishTanks(new ArrayList<FishTank>());
em.persist(petStore);
petStoreId = petStore.getId();
commitTransaction(em);
} finally {
closeEntityManager(em);
}
// cache clear is necessary (reset lazy loading)
getEntityManagerFactory().getCache().evictAll();
em = createEntityManager();
try {
beginTransaction(em);
PetStore petStore = em.find(PetStore.class, petStoreId);
Query query = em.createNamedQuery("findAllFishTanks");
query.setHint(QueryHints.READ_ONLY, HintValues.TRUE);
List<FishTank> allFishTanks = query.getResultList();
FishTank fishTank = allFishTanks.get(0);
// add read-only entity to referencing unidirectional relationship
petStore.getFishTanks().add(fishTank);
em.persist(petStore);
commitTransaction(em);
} finally {
closeEntityManager(em);
}
}
}