/*
 * Copyright 2013 Samppa Saarela
 *
 * 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.javersion.reflect;

import java.lang.reflect.*;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;

import com.thoughtworks.paranamer.BytecodeReadingParanamer;
import com.thoughtworks.paranamer.CachingParanamer;
import com.thoughtworks.paranamer.Paranamer;
import org.javersion.util.Check;

import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;

import static java.util.Collections.synchronizedMap;

public final class TypeDescriptors {

    public static final Predicate<Member> NON_SYNTHETIC = member -> !member.isSynthetic();

    public static final TypeDescriptors DEFAULT = new TypeDescriptors();

    public static TypeDescriptor getTypeDescriptor(Class<?> clazz) {
        Check.notNull(clazz, "clazz");
        return DEFAULT.get(clazz);
    }

    private final Map<TypeToken<?>, TypeDescriptor> cache = synchronizedMap(new WeakHashMap<>());

    protected final Predicate<? super Field> fieldFilter;

    protected final Predicate<? super Method> methodFilter;

    protected final Predicate<? super Constructor> constructorFilter;

    protected final Paranamer paranamer = new CachingParanamer(new BytecodeReadingParanamer());


    public TypeDescriptors() {
        this(NON_SYNTHETIC);
    }

    public TypeDescriptors(Predicate<? super Member> memberFilter) {
        this(memberFilter, memberFilter, memberFilter);
    }

    public TypeDescriptors(Predicate<? super Field> fieldFilter,
                           Predicate<? super Method> methodFilter,
                           Predicate<? super Constructor> constructorFilter) {
        this.fieldFilter = Check.notNull(fieldFilter, "fieldFilter");
        this.methodFilter = Check.notNull(methodFilter, "methodFilter");
        this.constructorFilter = Check.notNull(constructorFilter, "constructorFilter");
    }


    public TypeDescriptor get(Class<?> clazz) {
        return get(TypeToken.of(clazz));
    }

    public TypeDescriptor get(Type type) {
        return get(TypeToken.of(type));
    }

    public TypeDescriptor get(TypeToken<?> typeToken) {
        TypeDescriptor descriptor = cache.get(typeToken);
        if (descriptor == null) {
            descriptor = new TypeDescriptor(this, typeToken);
            cache.put(typeToken, descriptor);
        }
        return descriptor;
    }

    Paranamer getParanamer() {
        return paranamer;
    }

}
@@ -731,16 +731,147 @@
 ashMap;%0A
+import java.util.concurrent.ExecutionException;%0A%0Aimport com.google.common.cache.Cache;%0Aimport com.google.common.cache.CacheBuilder;
 %0Aimport 
@@ -1605,19 +1605,21 @@
 e final 
-Map
+Cache
 %3CTypeTok
@@ -1653,43 +1653,79 @@
 e = 
-synchronizedMap(new WeakHashMap%3C%3E()
+CacheBuilder.newBuilder()%0A            .softValues()%0A            .build(
 );%0A%0A
@@ -2916,116 +2916,59 @@
     
-TypeDescriptor descriptor = cache.get(typeToken);%0A        if (descriptor == null) %7B%0A            descriptor =
+try %7B%0A            return cache.get(typeToken, () -%3E
  new
@@ -2999,16 +2999,17 @@
 peToken)
+)
 ;%0A      
@@ -3014,45 +3014,40 @@
     
-   
+%7D
  ca
+t
 ch
-e.put(typeToken, descriptor);
+ (ExecutionException e) %7B
 %0A   
@@ -3055,36 +3055,52 @@
     
-%7D%0A
     
-    return descriptor;
+throw new RuntimeException(e);%0A        %7D
 %0A   

Replace WeakHashMap with real Cache with soft values