package io.katharsis.repository.annotated; import io.katharsis.queryParams.QueryParams; import io.katharsis.repository.LinksRepository; import io.katharsis.repository.MetaRepository; import io.katharsis.repository.ParametersFactory; import io.katharsis.repository.annotations.JsonApiLinks; import io.katharsis.repository.annotations.JsonApiMeta; import io.katharsis.repository.exception.RepositoryAnnotationNotFoundException; import io.katharsis.response.LinksInformation; import io.katharsis.response.MetaInformation; import io.katharsis.utils.ClassUtils; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public abstract class AnnotatedRepositoryAdapter<T> implements LinksRepository<T>, MetaRepository<T> { final Object implementationObject; final Class<?> implementationClass; final ParametersFactory parametersFactory; private Method linksMethod; private Method metaMethod; public AnnotatedRepositoryAdapter(Object implementationObject, ParametersFactory parametersFactory) { this.implementationObject = implementationObject; this.implementationClass = implementationObject.getClass(); this.parametersFactory = parametersFactory; } public boolean linksRepositoryAvailable() { assignLinksMethod(); return linksMethod != null; } @Override public LinksInformation getLinksInformation(Iterable<T> resources, QueryParams queryParams) { Class<JsonApiLinks> annotationType = JsonApiLinks.class; assignLinksMethod(); checkIfNotNull(annotationType, linksMethod); Object[] methodParameters = parametersFactory .buildParameters(new Object[]{resources}, linksMethod, queryParams, annotationType); return invoke(linksMethod, methodParameters); } private void assignLinksMethod() { if (linksMethod == null) { linksMethod = ClassUtils.findMethodWith(implementationClass, JsonApiLinks.class); } } public boolean metaRepositoryAvailable() { assignMetaMethod(); return metaMethod != null; } @Override public MetaInformation getMetaInformation(Iterable<T> resources, QueryParams queryParams) { Class<JsonApiMeta> annotationType = JsonApiMeta.class; assignMetaMethod(); checkIfNotNull(annotationType, metaMethod); Object[] methodParameters = parametersFactory .buildParameters(new Object[]{resources}, metaMethod, queryParams, annotationType); return invoke(metaMethod, methodParameters); } private void assignMetaMethod() { if (metaMethod == null) { metaMethod = ClassUtils.findMethodWith(implementationClass, JsonApiMeta.class); } } protected void checkIfNotNull(Class<? extends Annotation> annotationClass, Method foundMethod) { if (foundMethod == null) { throw new RepositoryAnnotationNotFoundException( String.format("Annotation %s for class %s not found", annotationClass, implementationObject.getClass())); } } protected <TYPE> TYPE invokeOperation(Method foundMethod, Class<? extends Annotation> annotationType, Object[] firstParameters) { checkIfNotNull(annotationType, foundMethod); Object[] methodParameters = parametersFactory .buildParameters(firstParameters, foundMethod, annotationType); return invoke(foundMethod, methodParameters); } protected <TYPE> TYPE invokeOperation(Method foundMethod, Class<? extends Annotation> annotationType, Object[] firstParameters, QueryParams queryParams) { checkIfNotNull(annotationType, foundMethod); Object[] methodParameters = parametersFactory .buildParameters(firstParameters, foundMethod, queryParams, annotationType); return invoke(foundMethod, methodParameters); } private <TYPE> TYPE invoke(Method method, Object... args) { try { return (TYPE) method.invoke(implementationObject, args); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw (RuntimeException) e.getCause(); } } }