⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractjpatests.java

📁 Spring API核心源代码 Spring API核心源代码 Spring API核心源代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright 2002-2006 the original author or authors.
 *
 * 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 org.springframework.test.jpa;

import java.lang.instrument.ClassFileTransformer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import junit.framework.TestCase;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.instrument.classloading.ResourceOverridingShadowingClassLoader;
import org.springframework.instrument.classloading.ShadowingClassLoader;
import org.springframework.orm.jpa.ExtendedEntityManagerCreator;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.SharedEntityManagerCreator;
import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
import org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests;
import org.springframework.util.StringUtils;

/**
 * Convenient support class for JPA-related tests. Offers the same contract as
 * AbstractTransactionalDataSourceSpringContextTests and equally good performance,
 * even when performing the instrumentation required by the JPA specification.
 *
 * <p>Exposes an EntityManagerFactory and a shared EntityManager.
 * Requires an EntityManagerFactory to be injected, plus the DataSource and
 * JpaTransactionManager through the superclass.
 * 
 * <p>When using Xerces, make sure a post 2.0.2 version is available on the classpath
 * to avoid a critical 
 * <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16014"/>bug</a> 
 * that leads to StackOverflow. Maven users are likely to encounter this problem since
 * 2.0.2 is used by default.
 * <p/>
 * A workaround is to explicitly specify the Xerces version inside the Maven pom: 
 * <pre>
 * &lt;dependency&gt;
 *   &lt;groupId&gt;xerces&lt;/groupId&gt;
 *     &lt;artifactId&gt;xercesImpl&lt;/artifactId&gt;
 *   &lt;version&gt;2.8.1&lt;/version&gt;
 * &lt;/dependency&gt;
 * </pre>
 *
 * @author Rod Johnson
 * @author Rob Harrop
 * @since 2.0
 */
public abstract class AbstractJpaTests extends AbstractAnnotationAwareTransactionalTests {

	private static final String DEFAULT_ORM_XML_LOCATION = "META-INF/orm.xml";
	
	/**
	 * Map from String defining unique combination of config locations, to ApplicationContext.
	 * Values are intentionally not strongly typed, to avoid potential class cast exceptions
	 * through use between different class loaders.
	 */
	private static Map<String, Object> contextCache = new HashMap<String, Object>();

	private static Map<String, ClassLoader> classLoaderCache = new HashMap<String, ClassLoader>();

	protected EntityManagerFactory entityManagerFactory;

	/**
	 * If this instance is in a shadow loader, this variable
	 * will contain the parent instance of the subclass.
	 * The class will not be the same as the class of the
	 * shadow instance, as it was loaded by a different class loader,
	 * but it can be invoked reflectively. The shadowParent
	 * and the shadow loader can communicate reflectively
	 * but not through direct invocation.
	 */
	private Object shadowParent;

	/**
	 * Subclasses can use this in test cases.
	 * It will participate in any current transaction.
	 */
	protected EntityManager sharedEntityManager;


	public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
		this.entityManagerFactory = entityManagerFactory;
		this.sharedEntityManager = SharedEntityManagerCreator.createSharedEntityManager(this.entityManagerFactory);
	}

	/**
	 * Create an EntityManager that will always automatically enlist itself in current
	 * transactions, in contrast to an EntityManager returned by
	 * <code>EntityManagerFactory.createEntityManager()</code>
	 * (which requires an explicit <code>joinTransaction()</code> call).
	 */
	protected EntityManager createContainerManagedEntityManager() {
		return ExtendedEntityManagerCreator.createContainerManagedEntityManager(this.entityManagerFactory);
	}
	
	/**
	 * Subclasses should override this method if they wish
	 * to disable shadow class loading. Do this only
	 * if instrumentation is not required in your
	 * JPA implementation. 
	 * @return whether to disable shadow loading functionality
	 */
	protected boolean shouldUseShadowLoader() {
		return true;
	}
	
	@Override
	public void setDirty() {
		super.setDirty();		
		contextCache.remove(cacheKeys());
		classLoaderCache.remove(cacheKeys());
		
		// If we are a shadow loader, we need to invoke
		// the shadow parent to set it dirty, as 
		// it is the shadow parent that maintains the cache state,
		// not the child
		if (this.shadowParent != null) {			
			try {
				Method m = shadowParent.getClass().getMethod("setDirty", (Class[]) null);
				m.invoke(shadowParent, (Object[]) null);
			}
			catch (Exception ex) {
				throw new RuntimeException(ex);
			}
		}
	}

	
	@Override
	public void runBare() throws Throwable {
		if (!shouldUseShadowLoader()) {
			super.runBare();
			return;
		}
		
		String combinationOfContextLocationsForThisTestClass = cacheKeys(); 			
		ClassLoader classLoaderForThisTestClass = getClass().getClassLoader();
		// save the TCCL
		ClassLoader initialClassLoader = Thread.currentThread().getContextClassLoader();
		
		if (this.shadowParent != null) {
			Thread.currentThread().setContextClassLoader(classLoaderForThisTestClass);
			super.runBare();
		}
		else {
			ShadowingClassLoader shadowingClassLoader = (ShadowingClassLoader) classLoaderCache.get(combinationOfContextLocationsForThisTestClass);

			if (shadowingClassLoader == null) {
				shadowingClassLoader = (ShadowingClassLoader) createShadowingClassLoader(classLoaderForThisTestClass);
				classLoaderCache.put(combinationOfContextLocationsForThisTestClass, shadowingClassLoader);
			}
			try {
				Thread.currentThread().setContextClassLoader(shadowingClassLoader);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -