package io.rx_cache2; import com.google.auto.common.SuperficialValidation; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeName; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Type; import io.reactivex.Observable; import java.util.ArrayList; import java.util.List; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; final class GetProvidersClass { ProvidersClass from(Element element) throws ValidationException { if (!SuperficialValidation.validateElement(element)) return null; if (element.getKind() != ElementKind.INTERFACE) return null; ClassName className = ClassName.get((TypeElement) element); List<ProvidersClass.Method> methods = getMethods(element); return new ProvidersClass(className, element, methods); } private List<ProvidersClass.Method> getMethods(Element classElement) throws ValidationException { List<? extends Element> enclosedElements = classElement.getEnclosedElements(); List<ProvidersClass.Method> methods = new ArrayList<>(); for (Element methodElement : enclosedElements) { if (!isAnnotatedWithActionable(methodElement)) continue; if (methodElement.getKind() != ElementKind.METHOD) continue; Symbol.MethodSymbol methodSymbol = (Symbol.MethodSymbol) methodElement; String nameMethod = methodSymbol.getSimpleName().toString(); Type returnType = methodSymbol.getReturnType(); if (!returnType.tsym.toString() .equals(TypeName.get(Observable.class).toString())) { throw new ValidationException(methodSymbol, "Error parsing %s provider. Only Observable<List> type is supported as observable loader", nameMethod); } Type enclosingTypeObservable = returnType.getTypeArguments().get(0); if (!enclosingTypeObservable.tsym.toString() .equals(TypeName.get(List.class).toString())) { throw new ValidationException(methodSymbol, "Error parsing %s provider. Only Observable<List> type is supported as observable loader", nameMethod); } List<Symbol.VarSymbol> params = methodSymbol.getParameters(); boolean hasEvictProvider = hasEvictProvider(params); boolean hasEvictDynamicKey = hasEvictDynamicKey(params); boolean hasEvictDynamicKeyGroup = hasEvictDynamicKeyGroup(params); if (!hasEvictProvider && !hasEvictDynamicKey && !hasEvictDynamicKeyGroup) { throw new ValidationException(methodElement, "Error parsing %s provider. The provider requires one evicting argument: EvictProvider, EvictDynamicKey or EvictDynamicKeyGroup", nameMethod); } if (hasEvictProvider && hasEvictDynamicKey) { throw new ValidationException(methodElement, "Error parsing %s provider. The provider requires one evicting argument: EvictProvider, EvictDynamicKey or EvictDynamicKeyGroup", nameMethod); } if (hasEvictProvider && hasEvictDynamicKeyGroup) { throw new ValidationException(methodElement, "Error parsing %s provider. The provider requires one evicting argument: EvictProvider, EvictDynamicKey or EvictDynamicKeyGroup", nameMethod); } if (hasEvictDynamicKey && hasEvictDynamicKeyGroup) { throw new ValidationException(methodElement, "Error parsing %s provider. The provider requires one evicting argument: EvictProvider, EvictDynamicKey or EvictDynamicKeyGroup", nameMethod); } boolean hasDynamicKey = hasDynamicKey(params); boolean hasDynamicKeyGroup = hasDynamicKeyGroup(params); methods.add(new ProvidersClass.Method(nameMethod, methodElement, enclosingTypeObservable, hasDynamicKey, hasDynamicKeyGroup)); } return methods; } private boolean isAnnotatedWithActionable(Element element) { Actionable actionable = element.getAnnotation(Actionable.class); return actionable != null; } private boolean hasDynamicKey(List<Symbol.VarSymbol> symbols) { return hasSymbol(symbols, DynamicKey.class); } private boolean hasDynamicKeyGroup(List<Symbol.VarSymbol> symbols) { return hasSymbol(symbols, DynamicKeyGroup.class); } private boolean hasEvictProvider(List<Symbol.VarSymbol> symbols) { return hasSymbol(symbols, EvictProvider.class); } private boolean hasEvictDynamicKey(List<Symbol.VarSymbol> symbols) { return hasSymbol(symbols, EvictDynamicKey.class); } private boolean hasEvictDynamicKeyGroup(List<Symbol.VarSymbol> symbols) { return hasSymbol(symbols, EvictDynamicKeyGroup.class); } private boolean hasSymbol(List<Symbol.VarSymbol> symbols, Class candidateClass) { for (Symbol.VarSymbol symbol: symbols) { String symbolClassName = symbol.type.toString(); String candidateClassName = candidateClass.getCanonicalName(); if (symbolClassName.equals(candidateClassName)) return true; } return false; } static class ValidationException extends Exception { private final Element element; public ValidationException(Element element, String msg, Object... args) { super(String.format(msg, args)); this.element = element; } public Element getElement() { return element; } } }