Skip to content

Commit 591f795

Browse files
committed
Spring's default JPA persistence unit exposes package metadata as well (currently only supported with Hibernate)
Issue: SPR-10910
1 parent 9919a98 commit 591f795

File tree

6 files changed

+164
-31
lines changed

6 files changed

+164
-31
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2002-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.orm.jpa.vendor;
18+
19+
import java.util.Map;
20+
import javax.persistence.EntityManagerFactory;
21+
import javax.persistence.spi.PersistenceUnitInfo;
22+
23+
import org.hibernate.cfg.Configuration;
24+
import org.hibernate.jpa.HibernatePersistenceProvider;
25+
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
26+
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
27+
import org.hibernate.service.ServiceRegistry;
28+
29+
import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo;
30+
31+
/**
32+
* Spring-specific subclass of the standard {@link HibernatePersistenceProvider}
33+
* from the {@code org.hibernate.jpa} package, adding support for
34+
* {@link SmartPersistenceUnitInfo#getManagedPackages()}.
35+
*
36+
* <p>Compatible with Hibernate 4.3. {@link SpringHibernateEjbPersistenceProvider}
37+
* is an alternative for compatibility with earlier Hibernate versions (3.6-4.2).
38+
*
39+
* @author Juergen Hoeller
40+
* @since 4.1
41+
*/
42+
class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider {
43+
44+
@Override
45+
@SuppressWarnings("rawtypes")
46+
public EntityManagerFactory createContainerEntityManagerFactory(final PersistenceUnitInfo info, Map properties) {
47+
return new EntityManagerFactoryBuilderImpl(new PersistenceUnitInfoDescriptor(info), properties) {
48+
@Override
49+
public Configuration buildHibernateConfiguration(ServiceRegistry serviceRegistry) {
50+
Configuration configuration = super.buildHibernateConfiguration(serviceRegistry);
51+
if (info instanceof SmartPersistenceUnitInfo) {
52+
for (String managedPackage : ((SmartPersistenceUnitInfo) info).getManagedPackages()) {
53+
configuration.addPackage(managedPackage);
54+
}
55+
}
56+
return configuration;
57+
}
58+
}.build();
59+
}
60+
61+
}

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@
8686
public class DefaultPersistenceUnitManager
8787
implements PersistenceUnitManager, ResourceLoaderAware, LoadTimeWeaverAware, InitializingBean {
8888

89-
private static final String ENTITY_CLASS_RESOURCE_PATTERN = "/**/*.class";
89+
private static final String CLASS_RESOURCE_PATTERN = "/**/*.class";
90+
91+
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
9092

9193
private static final String DEFAULT_ORM_XML_RESOURCE = "META-INF/orm.xml";
9294

@@ -512,7 +514,7 @@ private SpringPersistenceUnitInfo buildDefaultPersistenceUnitInfo() {
512514
for (String pkg : this.packagesToScan) {
513515
try {
514516
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
515-
ClassUtils.convertClassNameToResourcePath(pkg) + ENTITY_CLASS_RESOURCE_PATTERN;
517+
ClassUtils.convertClassNameToResourcePath(pkg) + CLASS_RESOURCE_PATTERN;
516518
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
517519
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
518520
for (Resource resource : resources) {
@@ -528,6 +530,10 @@ private SpringPersistenceUnitInfo buildDefaultPersistenceUnitInfo() {
528530
}
529531
}
530532
}
533+
else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
534+
scannedUnit.addManagedPackage(
535+
className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
536+
}
531537
}
532538
}
533539
}

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -53,13 +53,15 @@ public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo {
5353

5454
private DataSource jtaDataSource;
5555

56-
private List<String> mappingFileNames = new LinkedList<String>();
56+
private final List<String> mappingFileNames = new LinkedList<String>();
5757

5858
private List<URL> jarFileUrls = new LinkedList<URL>();
5959

6060
private URL persistenceUnitRootUrl;
6161

62-
private List<String> managedClassNames = new LinkedList<String>();
62+
private final List<String> managedClassNames = new LinkedList<String>();
63+
64+
private final List<String> managedPackages = new LinkedList<String>();
6365

6466
private boolean excludeUnlistedClasses = false;
6567

@@ -161,6 +163,15 @@ public List<String> getManagedClassNames() {
161163
return this.managedClassNames;
162164
}
163165

166+
public void addManagedPackage(String packageName) {
167+
this.managedPackages.add(packageName);
168+
}
169+
170+
@Override
171+
public List<String> getManagedPackages() {
172+
return this.managedPackages;
173+
}
174+
164175
public void setExcludeUnlistedClasses(boolean excludeUnlistedClasses) {
165176
this.excludeUnlistedClasses = excludeUnlistedClasses;
166177
}
@@ -251,13 +262,7 @@ public ClassLoader getNewTempClassLoader() {
251262

252263
@Override
253264
public String toString() {
254-
StringBuilder builder = new StringBuilder();
255-
builder.append("PersistenceUnitInfo: name '");
256-
builder.append(this.persistenceUnitName);
257-
builder.append("', root URL [");
258-
builder.append(this.persistenceUnitRootUrl);
259-
builder.append("]");
260-
return builder.toString();
265+
return "PersistenceUnitInfo: name '" + this.persistenceUnitName + "', root URL [" + this.persistenceUnitRootUrl + "]";
261266
}
262267

263268
}

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.orm.jpa.persistenceunit;
1818

19+
import java.util.List;
1920
import javax.persistence.spi.PersistenceUnitInfo;
2021

2122
/**
@@ -30,6 +31,14 @@
3031
*/
3132
public interface SmartPersistenceUnitInfo extends PersistenceUnitInfo {
3233

34+
/**
35+
* Return a list of managed Java packages, to be introspected by the persistence provider.
36+
* Typically found through scanning but not exposable through {@link #getManagedClassNames()}.
37+
* @return a list of names of managed Java packages (potentially empty)
38+
* @since 4.1
39+
*/
40+
List<String> getManagedPackages();
41+
3342
/**
3443
* Set the persistence provider's own package name, for exclusion from class transformation.
3544
* @see #addTransformer(javax.persistence.spi.ClassTransformer)

spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,9 +32,6 @@
3232
import org.hibernate.dialect.Oracle9iDialect;
3333
import org.hibernate.dialect.PostgreSQLDialect;
3434
import org.hibernate.dialect.SQLServerDialect;
35-
import org.hibernate.ejb.HibernateEntityManager;
36-
import org.hibernate.ejb.HibernateEntityManagerFactory;
37-
import org.hibernate.ejb.HibernatePersistence;
3835

3936
import org.springframework.orm.jpa.JpaDialect;
4037

@@ -68,25 +65,28 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
6865

6966
@SuppressWarnings({"deprecation", "unchecked"})
7067
public HibernateJpaVendorAdapter() {
71-
PersistenceProvider providerToUse;
68+
ClassLoader cl = HibernateJpaVendorAdapter.class.getClassLoader();
7269
Class<? extends EntityManagerFactory> emfIfcToUse;
7370
Class<? extends EntityManager> emIfcToUse;
71+
Class<?> providerClass;
72+
PersistenceProvider providerToUse;
7473
try {
75-
// Try Hibernate 4.3's org.hibernate.jpa package in order to avoid deprecation warnings
76-
ClassLoader cl = HibernateJpaVendorAdapter.class.getClassLoader();
77-
Class<?> hibernatePersistenceProviderClass = cl.loadClass("org.hibernate.jpa.HibernatePersistenceProvider");
78-
providerToUse = (PersistenceProvider) hibernatePersistenceProviderClass.newInstance();
79-
emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.jpa.HibernateEntityManagerFactory");
80-
emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.jpa.HibernateEntityManager");
81-
}
82-
catch (ClassNotFoundException ex) {
83-
// Fall back to Hibernate 3.6-4.2 org.hibernate.ejb package
84-
providerToUse = new HibernatePersistence();
85-
emfIfcToUse = HibernateEntityManagerFactory.class;
86-
emIfcToUse = HibernateEntityManager.class;
74+
try {
75+
// Try Hibernate 4.3's org.hibernate.jpa package in order to avoid deprecation warnings
76+
emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.jpa.HibernateEntityManagerFactory");
77+
emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.jpa.HibernateEntityManager");
78+
providerClass = cl.loadClass("org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider");
79+
}
80+
catch (ClassNotFoundException ex) {
81+
// Fall back to Hibernate 3.6-4.2 org.hibernate.ejb package
82+
emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.ejb.HibernateEntityManagerFactory");
83+
emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.ejb.HibernateEntityManager");
84+
providerClass = cl.loadClass("org.springframework.orm.jpa.vendor.SpringHibernateEjbPersistenceProvider");
85+
}
86+
providerToUse = (PersistenceProvider) providerClass.newInstance();
8787
}
8888
catch (Exception ex) {
89-
throw new IllegalStateException("Found HibernatePersistenceProvider but could not instantiate it", ex);
89+
throw new IllegalStateException("Failed to determine Hibernate PersistenceProvider", ex);
9090
}
9191
this.persistenceProvider = providerToUse;
9292
this.entityManagerFactoryInterface = emfIfcToUse;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2002-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.orm.jpa.vendor;
18+
19+
import java.util.Map;
20+
import javax.persistence.EntityManagerFactory;
21+
import javax.persistence.spi.PersistenceUnitInfo;
22+
23+
import org.hibernate.ejb.Ejb3Configuration;
24+
import org.hibernate.ejb.HibernatePersistence;
25+
26+
import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo;
27+
28+
/**
29+
* Spring-specific subclass of the standard {@link HibernatePersistence}
30+
* provider from the {@code org.hibernate.ejb} package, adding support for
31+
* {@link SmartPersistenceUnitInfo#getManagedPackages()}.
32+
*
33+
* <p>Compatible with Hibernate 3.6 as well as 4.0-4.2.
34+
*
35+
* @author Juergen Hoeller
36+
* @since 4.1
37+
*/
38+
class SpringHibernateEjbPersistenceProvider extends HibernatePersistence {
39+
40+
@SuppressWarnings("rawtypes")
41+
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) {
42+
Ejb3Configuration cfg = new Ejb3Configuration();
43+
if (info instanceof SmartPersistenceUnitInfo) {
44+
for (String managedPackage : ((SmartPersistenceUnitInfo) info).getManagedPackages()) {
45+
cfg.addPackage(managedPackage);
46+
}
47+
}
48+
Ejb3Configuration configured = cfg.configure(info, properties);
49+
return (configured != null ? configured.buildEntityManagerFactory() : null);
50+
}
51+
52+
}

0 commit comments

Comments
 (0)