full support for JPA 2.0 PersistenceUnitInfo SPI (for compatibility with Hibernate 3.5 beta 3; SPR-6408)

This commit is contained in:
Juergen Hoeller 2010-01-12 12:39:56 +00:00
parent 5c41e2c6e1
commit 0ba8375546
6 changed files with 165 additions and 24 deletions

View File

@ -29,9 +29,9 @@ import org.springframework.core.io.ResourceLoader;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.jdbc.datasource.lookup.SingleDataSourceLookup;
import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo;
import org.springframework.util.ClassUtils;
/**
@ -195,8 +195,8 @@ public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManage
this.persistenceUnitInfo = determinePersistenceUnitInfo(managerToUse);
JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
if (jpaVendorAdapter != null && this.persistenceUnitInfo instanceof MutablePersistenceUnitInfo) {
((MutablePersistenceUnitInfo) this.persistenceUnitInfo).setPersistenceProviderPackageName(
if (jpaVendorAdapter != null && this.persistenceUnitInfo instanceof SmartPersistenceUnitInfo) {
((SmartPersistenceUnitInfo) this.persistenceUnitInfo).setPersistenceProviderPackageName(
jpaVendorAdapter.getPersistenceProviderRootPackage());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2010 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.
@ -17,12 +17,14 @@
package org.springframework.orm.jpa.persistenceunit;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.PersistenceException;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.sql.DataSource;
@ -40,6 +42,7 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.jdbc.datasource.lookup.MapDataSourceLookup;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/**
@ -78,7 +81,8 @@ public class DefaultPersistenceUnitManager
public final static String ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION = "classpath:";
/** Location of persistence.xml file(s) */
private static final boolean jpa2ApiPresent = ClassUtils.hasMethod(PersistenceUnitInfo.class, "getSharedCacheMode");
private String[] persistenceXmlLocations = new String[] {DEFAULT_PERSISTENCE_XML_LOCATION};
private String defaultPersistenceUnitRootLocation = ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION;
@ -95,8 +99,7 @@ public class DefaultPersistenceUnitManager
private final Set<String> persistenceUnitInfoNames = new HashSet<String>();
private final Map<String, MutablePersistenceUnitInfo> persistenceUnitInfos =
new HashMap<String, MutablePersistenceUnitInfo>();
private final Map<String, PersistenceUnitInfo> persistenceUnitInfos = new HashMap<String, PersistenceUnitInfo>();
/**
@ -273,8 +276,7 @@ public class DefaultPersistenceUnitManager
this.persistenceUnitInfoNames.clear();
this.persistenceUnitInfos.clear();
SpringPersistenceUnitInfo[] puis = readPersistenceUnitInfos();
for (int i = 0; i < puis.length; i++) {
SpringPersistenceUnitInfo pui = puis[i];
for (SpringPersistenceUnitInfo pui : puis) {
if (pui.getPersistenceUnitRootUrl() == null) {
pui.setPersistenceUnitRootUrl(determineDefaultPersistenceUnitRootUrl());
}
@ -290,7 +292,12 @@ public class DefaultPersistenceUnitManager
postProcessPersistenceUnitInfo(pui);
String name = pui.getPersistenceUnitName();
this.persistenceUnitInfoNames.add(name);
this.persistenceUnitInfos.put(name, pui);
PersistenceUnitInfo puiToStore = pui;
if (jpa2ApiPresent) {
puiToStore = (PersistenceUnitInfo) Proxy.newProxyInstance(SmartPersistenceUnitInfo.class.getClassLoader(),
new Class[] {SmartPersistenceUnitInfo.class}, new Jpa2PersistenceUnitInfoDecorator(pui));
}
this.persistenceUnitInfos.put(name, puiToStore);
}
}
@ -331,7 +338,7 @@ public class DefaultPersistenceUnitManager
* @param persistenceUnitName the name of the desired persistence unit
* @return the PersistenceUnitInfo in mutable form, or <code>null</code> if not available
*/
protected final MutablePersistenceUnitInfo getPersistenceUnitInfo(String persistenceUnitName) {
protected final PersistenceUnitInfo getPersistenceUnitInfo(String persistenceUnitName) {
return this.persistenceUnitInfos.get(persistenceUnitName);
}
@ -387,4 +394,45 @@ public class DefaultPersistenceUnitManager
return pui;
}
/**
* Decorator that exposes a JPA 2.0 compliant PersistenceUnitInfo interface for a
* JPA 1.0 based SpringPersistenceUnitInfo object, adapting the <code>getSharedCacheMode</code>
* and <code>getValidationMode</code> methods from String names to enum return values.
*/
private static class Jpa2PersistenceUnitInfoDecorator implements InvocationHandler {
private final SpringPersistenceUnitInfo target;
private final Class<? extends Enum> sharedCacheModeEnum;
private final Class<? extends Enum> validationModeEnum;
@SuppressWarnings("unchecked")
public Jpa2PersistenceUnitInfoDecorator(SpringPersistenceUnitInfo target) {
this.target = target;
try {
this.sharedCacheModeEnum = (Class<? extends Enum>)
ClassUtils.forName("javax.persistence.SharedCacheMode", PersistenceUnitInfo.class.getClassLoader());
this.validationModeEnum = (Class<? extends Enum>)
ClassUtils.forName("javax.persistence.ValidationMode", PersistenceUnitInfo.class.getClassLoader());
}
catch (Exception ex) {
throw new IllegalStateException("JPA 2.0 API enum types not present", ex);
}
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getSharedCacheMode")) {
return Enum.valueOf(this.sharedCacheModeEnum, this.target.getSharedCacheModeName());
}
else if (method.getName().equals("getValidationMode")) {
return Enum.valueOf(this.validationModeEnum, this.target.getValidationModeName());
}
else {
return method.invoke(this.target, args);
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2010 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.
@ -20,9 +20,7 @@ import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import javax.persistence.spi.ClassTransformer;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;
@ -41,7 +39,7 @@ import org.springframework.util.ClassUtils;
* @author Costin Leau
* @since 2.0
*/
public class MutablePersistenceUnitInfo implements PersistenceUnitInfo {
public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo {
private String persistenceUnitName;
@ -65,6 +63,8 @@ public class MutablePersistenceUnitInfo implements PersistenceUnitInfo {
private Properties properties = new Properties();
private String persistenceXMLSchemaVersion = "1.0";
private String persistenceProviderPackageName;
@ -169,6 +169,14 @@ public class MutablePersistenceUnitInfo implements PersistenceUnitInfo {
return this.properties;
}
public void setPersistenceXMLSchemaVersion(String persistenceXMLSchemaVersion) {
this.persistenceXMLSchemaVersion = persistenceXMLSchemaVersion;
}
public String getPersistenceXMLSchemaVersion() {
return this.persistenceXMLSchemaVersion;
}
public void setPersistenceProviderPackageName(String persistenceProviderPackageName) {
this.persistenceProviderPackageName = persistenceProviderPackageName;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 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.
@ -52,6 +52,10 @@ import org.springframework.util.xml.SimpleSaxErrorHandler;
*/
class PersistenceUnitReader {
private static final String PERSISTENCE_UNIT = "persistence-unit";
private static final String UNIT_NAME = "name";
private static final String MAPPING_FILE_NAME = "mapping-file";
private static final String JAR_FILE_URL = "jar-file";
@ -62,17 +66,17 @@ class PersistenceUnitReader {
private static final String PROVIDER = "provider";
private static final String EXCLUDE_UNLISTED_CLASSES = "exclude-unlisted-classes";
private static final String TRANSACTION_TYPE = "transaction-type";
private static final String NON_JTA_DATA_SOURCE = "non-jta-data-source";
private static final String SHARED_CACHE_MODE = "shared-cache-mode";
private static final String VALIDATION_MODE = "validation-mode";
private static final String JTA_DATA_SOURCE = "jta-data-source";
private static final String TRANSACTION_TYPE = "transaction-type";
private static final String NON_JTA_DATA_SOURCE = "non-jta-data-source";
private static final String PERSISTENCE_UNIT = "persistence-unit";
private static final String UNIT_NAME = "name";
private static final String EXCLUDE_UNLISTED_CLASSES = "exclude-unlisted-classes";
private static final String META_INF = "META-INF";
@ -274,6 +278,18 @@ class PersistenceUnitReader {
unitInfo.setTransactionType(PersistenceUnitTransactionType.valueOf(txType));
}
// set JPA 2.0 shared cache mode
String cacheMode = persistenceUnit.getAttribute(SHARED_CACHE_MODE).trim();
if (StringUtils.hasText(cacheMode)) {
unitInfo.setSharedCacheModeName(cacheMode);
}
// set JPA 2.0 validation mode
String validationMode = persistenceUnit.getAttribute(VALIDATION_MODE).trim();
if (StringUtils.hasText(validationMode)) {
unitInfo.setValidationModeName(validationMode);
}
// data-source
String jtaDataSource = DomUtils.getChildElementValueByTagName(persistenceUnit, JTA_DATA_SOURCE);
if (StringUtils.hasText(jtaDataSource)) {

View File

@ -0,0 +1,40 @@
/*
* Copyright 2002-2010 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.orm.jpa.persistenceunit;
import javax.persistence.spi.PersistenceUnitInfo;
/**
* Extension of the standard JPA PersistenceUnitInfo interface, for advanced collaboration
* between Spring's {@link org.springframework.orm.jpa.LocalEntityManagerFactoryBean} and
* {@link PersistenceUnitManager} implementations.
*
* @author Juergen Hoeller
* @since 3.0.1
* @see PersistenceUnitManager
* @see org.springframework.orm.jpa.LocalEntityManagerFactoryBean
*/
public interface SmartPersistenceUnitInfo extends PersistenceUnitInfo {
/**
* Set the persistence provider's own package name, for exclusion from class transformation.
* @see #addTransformer(javax.persistence.spi.ClassTransformer)
* @see #getNewTempClassLoader()
*/
void setPersistenceProviderPackageName(String persistenceProviderPackageName);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2010 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.
@ -22,6 +22,7 @@ import org.springframework.core.DecoratingClassLoader;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.instrument.classloading.SimpleThrowawayClassLoader;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Subclass of {@link MutablePersistenceUnitInfo} that adds instrumentation hooks based on
@ -37,11 +38,39 @@ import org.springframework.util.Assert;
*/
class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo {
private static final String DEFAULT_SHARED_CACHE_MODE_NAME = "UNSPECIFIED";
private static final String DEFAULT_VALIDATION_MODE_NAME = "AUTO";
private String sharedCacheModeName = DEFAULT_SHARED_CACHE_MODE_NAME;
private String validationModeName = DEFAULT_VALIDATION_MODE_NAME;
private LoadTimeWeaver loadTimeWeaver;
private ClassLoader classLoader;
public void setSharedCacheModeName(String sharedCacheModeName) {
this.sharedCacheModeName =
(StringUtils.hasLength(sharedCacheModeName) ? sharedCacheModeName : DEFAULT_SHARED_CACHE_MODE_NAME);
}
public String getSharedCacheModeName() {
return this.sharedCacheModeName;
}
public void setValidationModeName(String validationModeName) {
this.validationModeName =
(StringUtils.hasLength(validationModeName) ? validationModeName : DEFAULT_VALIDATION_MODE_NAME);
}
public String getValidationModeName() {
return this.validationModeName;
}
/**
* Initialize this PersistenceUnitInfo with the LoadTimeWeaver SPI interface
* used by Spring to add instrumentation to the current class loader.