Skip to content

Commit b38cf9b

Browse files
committed
HHH-16545 PersistenceUtil.MetadataCache needs to be threadsafe
1 parent 8c01165 commit b38cf9b

File tree

1 file changed

+33
-14
lines changed

1 file changed

+33
-14
lines changed

hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUtilHelper.java

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
package org.hibernate.jpa.internal.util;
88

9+
import java.io.ObjectStreamException;
910
import java.io.Serializable;
1011
import java.lang.reflect.Field;
1112
import java.lang.reflect.InvocationTargetException;
@@ -16,7 +17,7 @@
1617
import java.util.HashMap;
1718
import java.util.List;
1819
import java.util.Map;
19-
import java.util.WeakHashMap;
20+
2021
import javax.persistence.spi.LoadState;
2122

2223
import org.hibernate.HibernateException;
@@ -411,24 +412,42 @@ private static Method getMethod(Class<?> clazz, String attributeName) {
411412
}
412413

413414
/**
414-
* Cache hierarchy and member resolution in a weak hash map
415+
* Cache hierarchy and member resolution, taking care to not leak
416+
* references to Class instances.
415417
*/
416-
//TODO not really thread-safe
417-
public static class MetadataCache implements Serializable {
418-
private transient Map<Class<?>, ClassMetadataCache> classCache = new WeakHashMap<Class<?>, ClassMetadataCache>();
418+
public static final class MetadataCache implements Serializable {
419419

420+
private final ClassValue<ClassMetadataCache> metadataCacheClassValue;
420421

421-
private void readObject(java.io.ObjectInputStream stream) {
422-
classCache = new WeakHashMap<Class<?>, ClassMetadataCache>();
422+
public MetadataCache() {
423+
this( new MetadataClassValue() );
423424
}
424425

425-
ClassMetadataCache getClassMetadata(Class<?> clazz) {
426-
ClassMetadataCache classMetadataCache = classCache.get( clazz );
427-
if ( classMetadataCache == null ) {
428-
classMetadataCache = new ClassMetadataCache( clazz );
429-
classCache.put( clazz, classMetadataCache );
430-
}
431-
return classMetadataCache;
426+
//To help with serialization: no need to serialize the actual metadataCacheClassValue field
427+
private MetadataCache(ClassValue<ClassMetadataCache> metadataCacheClassValue) {
428+
this.metadataCacheClassValue = metadataCacheClassValue;
429+
}
430+
431+
Object writeReplace() throws ObjectStreamException {
432+
//Writing a different instance which doesn't include the cache
433+
return new MetadataCache(null);
434+
}
435+
436+
private Object readResolve() throws ObjectStreamException {
437+
//Ensure we do instantiate a new cache instance on deserialization
438+
return new MetadataCache();
439+
}
440+
441+
ClassMetadataCache getClassMetadata(final Class<?> clazz) {
442+
return metadataCacheClassValue.get( clazz );
443+
}
444+
445+
}
446+
447+
private static final class MetadataClassValue extends ClassValue<ClassMetadataCache> {
448+
@Override
449+
protected ClassMetadataCache computeValue(final Class type) {
450+
return new ClassMetadataCache( type );
432451
}
433452
}
434453

0 commit comments

Comments
 (0)