package org.restler.spring.data.util; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.reflect.TypeToken; import org.restler.client.CoreModule; import org.restler.client.RestlerException; import org.springframework.data.repository.Repository; import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import java.lang.reflect.Type; import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.function.Predicate; public class Repositories { private final List<Class<?>> repositoriesList; private final LoadingCache<Class<?>, Repository> cache; public Repositories(List<Class<?>> repositories, CoreModule coreModule) { this.repositoriesList = repositories; this.cache = CacheBuilder.newBuilder(). build(new CacheLoader<Class<?>, Repository>() { @Override public Repository load(Class<?> aClass) throws Exception { return (Repository) coreModule.produceClient(aClass); } }); } public Optional<Repository> getByResourceClass(Class<?> resourceClass) { return repositoriesList.stream(). filter(classRepository(resourceClass)). map(this::toRepository). findFirst(); } private Repository toRepository(Class<?> c) { try { return cache.get(c); } catch (ExecutionException e) { throw new RestlerException("Repository creation failed", e); } } private Predicate<Class<?>> classRepository(Class<?> resourceClass) { return (Class<?> clazz) -> { Type[] interfaces = clazz.getGenericInterfaces(); Type[] genericTypes = ((ParameterizedTypeImpl) interfaces[0]).getActualTypeArguments(); Class<?> genericId = TypeToken.of(genericTypes[0]).getRawType(); //Repository and resourceClass must be loaded by one class loader return genericId.equals(resourceClass); }; } }