📄 abstractjpatests.java
字号:
/*
* 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>
* <dependency>
* <groupId>xerces</groupId>
* <artifactId>xercesImpl</artifactId>
* <version>2.8.1</version>
* </dependency>
* </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 + -