
moxy.compiler.PresenterInjectorRules Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of moxy-compiler Show documentation
Show all versions of moxy-compiler Show documentation
Moxy Compiler library for Android
package moxy.compiler;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.tools.Diagnostic;
import moxy.MvpPresenter;
import moxy.MvpView;
import moxy.presenter.InjectPresenter;
import static moxy.compiler.Util.fillGenerics;
public class PresenterInjectorRules extends AnnotationRule {
public PresenterInjectorRules(ElementKind validKind, Modifier... validModifiers) {
super(validKind, validModifiers);
}
@SuppressWarnings("StringConcatenationInsideStringBufferAppend")
@Override
public void checkAnnotation(Element annotatedField) {
checkEnvironment(annotatedField);
if (annotatedField.getKind() != mValidKind) {
mErrorBuilder
.append("Field " + annotatedField + " of " + annotatedField.getEnclosingElement().getSimpleName()
+ " should be " + mValidKind.name() + ", or not mark it as @" + InjectPresenter.class
.getSimpleName()).append("\n");
}
for (Modifier modifier : annotatedField.getModifiers()) {
if (!mValidModifiers.contains(modifier)) {
mErrorBuilder.append("Field " + annotatedField + " of " + annotatedField.getEnclosingElement()
.getSimpleName() + " can't be a " + modifier).append(". Use ").append(validModifiersToString())
.append("\n");
}
}
Element enclosingElement = annotatedField.getEnclosingElement();
while (enclosingElement.getKind() == ElementKind.CLASS) {
if (!enclosingElement.getModifiers().contains(Modifier.PUBLIC)) {
mErrorBuilder.append(enclosingElement.getSimpleName() + " should be PUBLIC ");
break;
}
enclosingElement = enclosingElement.getEnclosingElement();
}
}
private void checkEnvironment(final Element annotatedField) {
if (!(annotatedField.asType() instanceof DeclaredType)) {
return;
}
TypeElement typeElement = (TypeElement) ((DeclaredType) annotatedField.asType()).asElement();
String viewClassFromGeneric = getViewClassFromGeneric(typeElement, (DeclaredType) annotatedField.asType());
Collection viewsType = getViewsType(
(TypeElement) ((DeclaredType) annotatedField.getEnclosingElement().asType()).asElement());
boolean result = false;
for (TypeMirror typeMirror : viewsType) {
if (Util.getFullClassName(typeMirror).equals(viewClassFromGeneric) || Util
.fillGenerics(Collections.emptyMap(), typeMirror).equals(viewClassFromGeneric)) {
result = true;
break;
}
}
if (!result) {
MvpCompiler.getMessager().printMessage(Diagnostic.Kind.ERROR,
"You can not use @InjectPresenter in classes that are not View, which is typified target Presenter",
annotatedField);
}
}
private String getViewClassFromGeneric(TypeElement typeElement, DeclaredType declaredType) {
TypeMirror superclass = declaredType;
Map mTypedMap = Collections.emptyMap();
if (!typeElement.getTypeParameters().isEmpty()) {
mTypedMap = getChildInstanceOfClassFromGeneric(typeElement, MvpView.class);
}
Map parentTypes = Collections.emptyMap();
List extends TypeMirror> totalTypeArguments = new ArrayList<>(((DeclaredType) superclass).getTypeArguments());
while (superclass.getKind() != TypeKind.NONE) {
TypeElement superclassElement = (TypeElement) ((DeclaredType) superclass).asElement();
List extends TypeMirror> typeArguments = ((DeclaredType) superclass).getTypeArguments();
totalTypeArguments.retainAll(typeArguments);
final List extends TypeParameterElement> typeParameters = superclassElement.getTypeParameters();
Map types = new HashMap<>();
for (int i = 0; i < typeArguments.size(); i++) {
types.put(typeParameters.get(i).toString(), fillGenerics(parentTypes, typeArguments.get(i)));
}
if (superclassElement.toString().equals(MvpPresenter.class.getCanonicalName())) {
if (!typeArguments.isEmpty()) {
TypeMirror typeMirror = typeArguments.get(0);
if (typeMirror instanceof TypeVariable) {
Element key = ((TypeVariable) typeMirror).asElement();
for (Map.Entry entry : mTypedMap.entrySet()) {
if (entry.getKey().toString().equals(key.toString())) {
return Util.getFullClassName(entry.getValue());
}
}
}
}
if (typeArguments.isEmpty() && typeParameters.isEmpty()) {
return ((DeclaredType) superclass).asElement().getSimpleName().toString();
}
// MvpPresenter is typed only on View class
return fillGenerics(parentTypes, typeArguments);
}
parentTypes = types;
superclass = superclassElement.getSuperclass();
}
return "";
}
private Map getChildInstanceOfClassFromGeneric(final TypeElement typeElement,
final Class> aClass) {
Map result = new HashMap<>();
for (TypeParameterElement element : typeElement.getTypeParameters()) {
List extends TypeMirror> bounds = element.getBounds();
for (TypeMirror bound : bounds) {
if (bound instanceof DeclaredType && ((DeclaredType) bound).asElement() instanceof TypeElement) {
Collection viewsType = getViewsType((TypeElement) ((DeclaredType) bound).asElement());
boolean isViewType = false;
for (TypeMirror viewType : viewsType) {
if (((DeclaredType) viewType).asElement().toString().equals(aClass.getCanonicalName())) {
isViewType = true;
}
}
if (isViewType) {
result.put(element, bound);
break;
}
}
}
}
return result;
}
private Collection getViewsType(TypeElement typeElement) {
TypeMirror superclass = typeElement.asType();
List result = new ArrayList<>();
while (superclass.getKind() != TypeKind.NONE) {
TypeElement superclassElement = (TypeElement) ((DeclaredType) superclass).asElement();
Collection extends TypeMirror> interfaces = new HashSet<>(superclassElement.getInterfaces());
for (TypeMirror typeMirror : interfaces) {
if (typeMirror instanceof DeclaredType) {
result.addAll(getViewsType((TypeElement) ((DeclaredType) typeMirror).asElement()));
}
}
result.addAll(interfaces);
result.add(superclass);
superclass = superclassElement.getSuperclass();
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy