|
6 | 6 | */ |
7 | 7 | package org.hibernate.jpa.internal.util; |
8 | 8 |
|
| 9 | +import java.io.ObjectStreamException; |
9 | 10 | import java.io.Serializable; |
10 | 11 | import java.lang.reflect.Field; |
11 | 12 | import java.lang.reflect.InvocationTargetException; |
|
16 | 17 | import java.util.HashMap; |
17 | 18 | import java.util.List; |
18 | 19 | import java.util.Map; |
19 | | -import java.util.WeakHashMap; |
| 20 | + |
20 | 21 | import javax.persistence.spi.LoadState; |
21 | 22 |
|
22 | 23 | import org.hibernate.HibernateException; |
@@ -411,24 +412,42 @@ private static Method getMethod(Class<?> clazz, String attributeName) { |
411 | 412 | } |
412 | 413 |
|
413 | 414 | /** |
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. |
415 | 417 | */ |
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 { |
419 | 419 |
|
| 420 | + private final ClassValue<ClassMetadataCache> metadataCacheClassValue; |
420 | 421 |
|
421 | | - private void readObject(java.io.ObjectInputStream stream) { |
422 | | - classCache = new WeakHashMap<Class<?>, ClassMetadataCache>(); |
| 422 | + public MetadataCache() { |
| 423 | + this( new MetadataClassValue() ); |
423 | 424 | } |
424 | 425 |
|
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 ); |
432 | 451 | } |
433 | 452 | } |
434 | 453 |
|
|
0 commit comments