Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 320273

Summary: JPA2: On Spring 3.0: Metamodel initialize() must filter (valid) null key/value pairs in session.getDescriptors Map
Product: z_Archived Reporter: Michael OBrien <michael.f.obrien>
Component: EclipselinkAssignee: Michael OBrien <michael.f.obrien>
Status: RESOLVED FIXED QA Contact:
Severity: major    
Priority: P3 CC: eclipselink.orm-inbox, michael.f.obrien
Version: unspecifiedFlags: michael.f.obrien: documentation+
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
URL: http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#DI_106:_20100810:_322585:Metamodel_initialization_via_EMF.getMetamodel.28.29_before_EM_deploy_results_in_an_invalid_Metamodel_because_of_UNINITIALIZED_descriptor.initializationStage
Whiteboard:
Bug Depends on: 266912, 322585    
Bug Blocks: 303063    
Attachments:
Description Flags
Do a getServerSession that will do a login/deploy as part of an entityManagerFactory.predeploy() so all metadata processing, ddlgeneration and metamodel initialization is complete before a create em
none
Option 7 (in use): Do a getServerSession that does a deploy/login that calls initializeDescriptors only for early emf.getMetamodel() users - em.getMetamodel() users do not login none

Description Michael OBrien CLA 2010-07-19 10:41:06 EDT
>We must not process null descriptor values during entity/embeddable initialization processing in getMetamodel()
- this is because on spring at this point we may only have the className and not the javaClass set yet
- spring deployment may need a further delay in metamodel preprocessing


>see my comment in Feb 2010 about descriptors not fully initialized on the spring container
https://jira.springsource.org/browse/SPR-6826

public class MetamodelImpl implements Metamodel, Serializable {
   private void initialize() {
        // Process all Entity and Embeddable types (MappedSuperclasses are handled later)
        for (Object descriptor : this.getSession().getDescriptors().values()) {
            // The ClassDescriptor is always of type RelationalDescriptor - the cast is safe
            ManagedTypeImpl<?> managedType = ManagedTypeImpl.create(this, (RelationalDescriptor)descriptor);
            putType(managedType.getJavaType(), managedType);
Comment 1 Michael OBrien CLA 2010-08-17 22:19:43 EDT
Created attachment 176856 [details]
Do a getServerSession that will do a login/deploy as part of an entityManagerFactory.predeploy() so all metadata processing, ddlgeneration and metamodel initialization is complete before a create em

>See design issue 106 option 3 for bug # 322585
http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#DI_106:_20100810:_322585:Metamodel_initialization_via_EMF.getMetamodel.28.29_before_EM_deploy_results_in_an_invalid_Metamodel_because_of_UNINITIALIZED_descriptor.initializationStage

After trying 2 locations of a getServerSession() call in order to do a login before an official deploy() on createEntityManager - I came across code that already exists for JPA validation that will do a login for us and effect a deploy just after the predeploy finishes on the EMF. 

>shouldGetSessionOnCreateFactory()

>Performance Results 106-3
The following show that that the time taken to update the session, do DDL generation and intialize the metamodel and canonical metamodel has shifted to the EMF creation from the EM creation. In essence an emf.createEntityManager() now takes just a couple microseconds instead of seconds. 
Doing all the following in the predeploy 
  updateServerSession 
  session.login 
  generateDDL 
  metamodel initalization 
  canonical metamodel initialization 
takes in SE 
> with change 
  predeploy() = 2.6 sec 
   [EL Finest]: 2010-08-17 18:01:12.002--ServerSession(27196165)--Thread(Thread[main,5,main])--Begin predeploying Persistence Unit dao.create.tables.derby; session default-session; state Initial; factoryCount 0 
   [EL Finest]: 2010-08-17 18:01:14.67--ServerSession(27196165)--Thread(Thread[main,5,main])--End deploying Persistence Unit dao.create.tables.derby; session default-session; state Deployed; factoryCount 1 
  deploy() = 0.09 sec 
   [EL Finest]: 2010-08-17 18:01:14.67--ServerSession(27196165)--Thread(Thread[main,5,main])--End deploying Persistence Unit dao.create.tables.derby; session default-session; state Deployed; factoryCount 1 
   [EL Finer]: 2010-08-17 18:01:14.763--ServerSession(27196165)--Thread(Thread[main,5,main])--client acquired 
 
> without change 
  predeploy() = 0.75 sec 
   [EL Finest]: 2010-08-17 17:58:29.169--ServerSession(2279771)--Thread(Thread[main,5,main])--Begin predeploying Persistence Unit dao.create.tables.derby; session default-session; state Initial; factoryCount 0 
   [EL Finest]: 2010-08-17 17:58:29.934--ServerSession(2279771)--Thread(Thread[main,5,main])--End predeploying Persistence Unit dao.create.tables.derby; session default-session; state Predeployed; factoryCount 1 
  deploy() = 1.87 sec 
   [EL Finest]: 2010-08-17 17:58:29.934--ServerSession(2279771)--Thread(Thread[main,5,main])--Begin deploying Persistence Unit dao.create.tables.derby; session default-session; state Predeployed; factoryCount 1 
   [EL Finer]: 2010-08-17 17:58:31.806--ServerSession(2279771)--Thread(Thread[main,5,main])--client acquired 

On emf.createEntityManager() we just skip deploy/login in getServerSession(), login in createEntityManagerImpl as well as deploy/login in getServerSession() in the EntityManagerImpl constructor 
because the emf.createEntityManager() does virtually nothing after this change 

EE Server testing on WebLogic 10.3.3.0 via standard @PersitenceContext injection on a SSB @EJB injected on a servlet client is OK 

Notice that a predeploy also does a deploy now - previously the deploy was only done when the client persisted or read from the persistence unit (via injection) 

Daemon Thread [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'] (Suspended (breakpoint at line 314 in EntityManagerSetupImpl))	
	EntityManagerSetupImpl.deploy(ClassLoader, Map) line: 314	
	EntityManagerFactoryImpl.getServerSession() line: 157	
	PersistenceProvider.createContainerEntityManagerFactory(PersistenceUnitInfo, Map) line: 243	
	PersistenceUnitInfoImpl.createEntityManagerFactory(boolean) line: 352	
	PersistenceUnitInfoImpl.createEntityManagerFactory() line: 332	
	PersistenceUnitInfoImpl.<init>(PersistenceUnitBean, PersistenceUnitConfigurationBean, GenericClassLoader, String, URL, URL) line: 134	
	ModulePersistenceUnitRegistry(AbstractPersistenceUnitRegistry).storeDescriptors(Map, Map) line: 336	
	ModulePersistenceUnitRegistry(AbstractPersistenceUnitRegistry).loadPersistenceDescriptor(VirtualJarFile, boolean, File) line: 250	
	ModulePersistenceUnitRegistry.<init>(GenericClassLoader, ApplicationContextInternal, Module, boolean) line: 69	
	EJBModule.setupPersistenceUnitRegistry() line: 221	
	EJBModule$1.execute() line: 322	
	PersistenceUnitRegistryInitializer.setupPersistenceUnitRegistries() line: 62	
	WebAppModule.prepare() line: 398	
	ScopedModuleDriver.prepare() line: 176	
	ModuleListenerInvoker.prepare() line: 199	
	DeploymentCallbackFlow$1.next(Object) line: 507	
	StateMachineDriver.nextState(StateChange, Object[]) line: 41	
	DeploymentCallbackFlow.prepare(Module[]) line: 149	
	DeploymentCallbackFlow.prepare() line: 45	
	BaseDeployment$1.next(Object) line: 1221	
	StateMachineDriver.nextState(StateChange, Object[]) line: 41	
	EarDeployment(BaseDeployment).prepare(DeploymentContext) line: 367	
	EarDeployment.prepare(DeploymentContext) line: 58	
	DeploymentStateChecker.prepare(DeploymentContext) line: 154	
	AppContainerInvoker.prepare(DeploymentContext) line: 60	
	RedeployOperation.createAndPrepareContainer() line: 98	
	RedeployOperation.doPrepare() line: 122	
	RedeployOperation(AbstractOperation).prepare() line: 217	
	DeploymentManager.handleDeploymentPrepare(Deployment, DeploymentManager$DeploymentRequestInfo) line: 747	
	DeploymentManager.prepareDeploymentList(ArrayList, DeploymentContext) line: 1216	
	DeploymentManager.handlePrepare(DeploymentContext) line: 250	
	DeploymentServiceDispatcher.prepare(DeploymentContext) line: 159	
	DeploymentReceiverCallbackDeliverer.doPrepareCallback(DeploymentContext) line: 171	
	DeploymentReceiverCallbackDeliverer.access$000(DeploymentReceiverCallbackDeliverer, DeploymentContext) line: 13	
	DeploymentReceiverCallbackDeliverer$1.run() line: 46	
	SelfTuningWorkManagerImpl$WorkAdapterImpl.run() line: 528	
	ExecuteThread.execute(Runnable) line: 201	
	ExecuteThread.run()
Comment 2 Michael OBrien CLA 2010-09-03 15:30:21 EDT
Created attachment 178192 [details]
Option 7 (in use): Do a getServerSession that does a deploy/login that calls initializeDescriptors only for early emf.getMetamodel() users - em.getMetamodel() users do not login
Comment 3 Michael OBrien CLA 2010-09-03 15:33:00 EDT
>See the fix for bug # 322585 in SVN rev# 8141 for 2.2 and 8142 for 2.1.2
https://fisheye2.atlassian.com/changelog/eclipselink/?cs=8141
We now do a preemptive DB login via getServerSession to force initializeDescriptors so that a MappedSuperclass javaClass is set on the descriptor when a client does an emf.getMetamodel() or emf.getCriteriaBuilder() before at least one EntityManager is created or logged in.
If a NullPointerException occurs on early post-predeploy but pre-deploy access to the Metamodel via an EntityManagerFactory.getMetamodel() or emf.getCriteriaBuilder() call before an initial login to the DB - then reopen this bug.
NPE in ManagedTypeImpl.getTypeClassFromAttributeOrMethodLevelAccessor
NPE in MetamodelImpl.initialize
Comment 4 Eclipse Webmaster CLA 2022-06-09 10:07:42 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink