From f9452ae9e955f0e0a1c6046dd30a6eb2ed6ed1d5 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 19 Sep 2014 00:11:44 +0200 Subject: [PATCH] LocalSessionFactoryBean supports JPA 2.1 auto-apply @Converter on Hibernate 4.3 Issue: SPR-12234 --- .../LocalSessionFactoryBuilder.java | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBuilder.java b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBuilder.java index 60cc8cccecd..944ea4a80a8 100644 --- a/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBuilder.java +++ b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBuilder.java @@ -19,10 +19,10 @@ package org.springframework.orm.hibernate4; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.LinkedHashSet; import java.util.Properties; import java.util.Set; import java.util.TreeSet; +import javax.persistence.AttributeConverter; import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.MappedSuperclass; @@ -83,19 +83,20 @@ public class LocalSessionFactoryBuilder extends Configuration { private static final String PACKAGE_INFO_SUFFIX = ".package-info"; + private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] { + new AnnotationTypeFilter(Entity.class, false), + new AnnotationTypeFilter(Embeddable.class, false), + new AnnotationTypeFilter(MappedSuperclass.class, false)}; - private static final Set defaultTypeFilters; + + private static TypeFilter converterTypeFilter; static { - defaultTypeFilters = new LinkedHashSet(4); - defaultTypeFilters.add(new AnnotationTypeFilter(Entity.class, false)); - defaultTypeFilters.add(new AnnotationTypeFilter(Embeddable.class, false)); - defaultTypeFilters.add(new AnnotationTypeFilter(MappedSuperclass.class, false)); try { @SuppressWarnings("unchecked") Class converterAnnotation = (Class) ClassUtils.forName("javax.persistence.Converter", LocalSessionFactoryBuilder.class.getClassLoader()); - defaultTypeFilters.add(new AnnotationTypeFilter(converterAnnotation, false)); + converterTypeFilter = new AnnotationTypeFilter(converterAnnotation, false); } catch (ClassNotFoundException ex) { // JPA 2.1 API not available - Hibernate <4.3 @@ -103,12 +104,12 @@ public class LocalSessionFactoryBuilder extends Configuration { } - private TypeFilter[] entityTypeFilters = defaultTypeFilters.toArray(new TypeFilter[defaultTypeFilters.size()]); - private final ResourcePatternResolver resourcePatternResolver; private RegionFactory cacheRegionFactory; + private TypeFilter[] entityTypeFilters = DEFAULT_ENTITY_TYPE_FILTERS; + /** * Create a new LocalSessionFactoryBuilder for the given DataSource. @@ -272,7 +273,8 @@ public class LocalSessionFactoryBuilder extends Configuration { * @throws HibernateException if scanning fails for any reason */ public LocalSessionFactoryBuilder scanPackages(String... packagesToScan) throws HibernateException { - Set classNames = new TreeSet(); + Set entityClassNames = new TreeSet(); + Set converterClassNames = new TreeSet(); Set packageNames = new TreeSet(); try { for (String pkg : packagesToScan) { @@ -285,7 +287,10 @@ public class LocalSessionFactoryBuilder extends Configuration { MetadataReader reader = readerFactory.getMetadataReader(resource); String className = reader.getClassMetadata().getClassName(); if (matchesEntityTypeFilter(reader, readerFactory)) { - classNames.add(className); + entityClassNames.add(className); + } + else if (converterTypeFilter != null && converterTypeFilter.match(reader, readerFactory)) { + converterClassNames.add(className); } else if (className.endsWith(PACKAGE_INFO_SUFFIX)) { packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length())); @@ -298,8 +303,12 @@ public class LocalSessionFactoryBuilder extends Configuration { throw new MappingException("Failed to scan classpath for unlisted classes", ex); } try { - for (String className : classNames) { - addAnnotatedClass(this.resourcePatternResolver.getClassLoader().loadClass(className)); + ClassLoader cl = this.resourcePatternResolver.getClassLoader(); + for (String className : entityClassNames) { + addAnnotatedClass(cl.loadClass(className)); + } + for (String className : converterClassNames) { + ConverterRegistrationDelegate.registerConverter(this, cl.loadClass(className)); } for (String packageName : packageNames) { addPackage(packageName); @@ -369,4 +378,16 @@ public class LocalSessionFactoryBuilder extends Configuration { } } + + /** + * Inner class to avoid hard dependency on JPA 2.1 / Hibernate 4.3. + */ + private static class ConverterRegistrationDelegate { + + @SuppressWarnings("unchecked") + public static void registerConverter(Configuration config, Class converterClass) { + config.addAttributeConverter((Class>) converterClass); + } + } + }