org.androidannotations.internal.process.ModelProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of androidannotations Show documentation
Show all versions of androidannotations Show documentation
The Annotation Processor jar that generates code
/**
* Copyright (C) 2010-2016 eBusiness Information, Excilys Group
*
* 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.androidannotations.internal.process;
import java.util.Set;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.TypeElement;
import org.androidannotations.handler.AnnotationHandler;
import org.androidannotations.handler.GeneratingAnnotationHandler;
import org.androidannotations.holder.GeneratedClassHolder;
import org.androidannotations.internal.InternalAndroidAnnotationsEnvironment;
import org.androidannotations.internal.exception.ProcessingException;
import org.androidannotations.internal.model.AnnotationElements;
import org.androidannotations.internal.model.AnnotationElements.AnnotatedAndRootElements;
import org.androidannotations.logger.Logger;
import org.androidannotations.logger.LoggerFactory;
import com.helger.jcodemodel.JCodeModel;
public class ModelProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(ModelProcessor.class);
public static class ProcessResult {
public final JCodeModel codeModel;
public final OriginatingElements originatingElements;
public ProcessResult(JCodeModel codeModel, OriginatingElements originatingElements) {
this.codeModel = codeModel;
this.originatingElements = originatingElements;
}
}
private final InternalAndroidAnnotationsEnvironment environment;
public ModelProcessor(InternalAndroidAnnotationsEnvironment environment) {
this.environment = environment;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public ProcessResult process(AnnotationElements validatedModel) throws Exception {
ProcessHolder processHolder = new ProcessHolder(environment.getProcessingEnvironment());
environment.setProcessHolder(processHolder);
LOGGER.info("Processing root elements");
/*
* We generate top classes then inner classes, then inner classes of
* inner classes, etc... until there is no more classes to generate.
*/
while (generateElements(validatedModel, processHolder)) {
// CHECKSTYLE:OFF
;
// CHECKSTYLE:ON
}
LOGGER.info("Processing enclosed elements");
for (AnnotationHandler annotationHandler : environment.getDecoratingHandlers()) {
if (!annotationHandler.isEnabled()) {
continue;
}
String annotationName = annotationHandler.getTarget();
/*
* For ancestors, the annotationHandler manipulates the annotated
* elements, but uses the holder for the root element
*/
Set ancestorAnnotatedElements = validatedModel.getAncestorAnnotatedElements(annotationName);
if (!ancestorAnnotatedElements.isEmpty()) {
LOGGER.debug("Processing enclosed elements with {}: {}", annotationHandler.getClass().getSimpleName(), ancestorAnnotatedElements);
}
for (AnnotatedAndRootElements elements : ancestorAnnotatedElements) {
GeneratedClassHolder holder = processHolder.getGeneratedClassHolder(elements.rootTypeElement);
/*
* Annotations coming from ancestors may be applied to root
* elements that are not validated, and therefore not available.
*/
if (holder != null) {
processThrowing(annotationHandler, elements.annotatedElement, holder);
}
}
Set extends Element> rootAnnotatedElements = validatedModel.getRootAnnotatedElements(annotationName);
for (Element annotatedElement : rootAnnotatedElements) {
Element enclosingElement;
if (annotatedElement instanceof TypeElement) {
enclosingElement = annotatedElement;
} else {
enclosingElement = annotatedElement.getEnclosingElement();
/*
* we are processing a method parameter
*/
if (enclosingElement instanceof ExecutableElement) {
enclosingElement = enclosingElement.getEnclosingElement();
}
}
/*
* We do not generate code for elements belonging to abstract
* classes, because the generated classes are final anyway
*/
if (!isAbstractClass(enclosingElement)) {
GeneratedClassHolder holder = processHolder.getGeneratedClassHolder(enclosingElement);
/*
* The holder can be null if the annotated holder class is
* already invalidated.
*/
if (holder != null) {
processThrowing(annotationHandler, annotatedElement, holder);
}
} else {
LOGGER.trace("Skip element {} because enclosing element {} is abstract", annotatedElement, enclosingElement);
}
}
}
return new ProcessResult(//
processHolder.codeModel(), //
processHolder.getOriginatingElements());
}
private void processThrowing(AnnotationHandler handler, Element element, T generatedClassHolder) throws ProcessingException {
try {
handler.process(element, generatedClassHolder);
} catch (Exception e) {
throw new ProcessingException(e, element);
}
}
private boolean isAbstractClass(Element annotatedElement) {
if (annotatedElement instanceof TypeElement) {
TypeElement typeElement = (TypeElement) annotatedElement;
return typeElement.getKind() == ElementKind.CLASS && typeElement.getModifiers().contains(Modifier.ABSTRACT);
} else {
return false;
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private boolean generateElements(AnnotationElements validatedModel, ProcessHolder processHolder) throws Exception {
boolean isElementRemaining = false;
for (GeneratingAnnotationHandler generatingAnnotationHandler : environment.getGeneratingHandlers()) {
if (!generatingAnnotationHandler.isEnabled()) {
continue;
}
String annotationName = generatingAnnotationHandler.getTarget();
Set extends Element> annotatedElements = validatedModel.getRootAnnotatedElements(annotationName);
if (!annotatedElements.isEmpty()) {
LOGGER.debug("Processing root elements {}: {}", generatingAnnotationHandler.getClass().getSimpleName(), annotatedElements);
}
for (Element annotatedElement : annotatedElements) {
/*
* We do not generate code for abstract classes, because the
* generated classes are final anyway (we do not want anyone to
* extend them).
*/
if (!isAbstractClass(annotatedElement)) {
if (processHolder.getGeneratedClassHolder(annotatedElement) == null) {
TypeElement typeElement = (TypeElement) annotatedElement;
Element enclosingElement = annotatedElement.getEnclosingElement();
if (typeElement.getNestingKind() == NestingKind.MEMBER && processHolder.getGeneratedClassHolder(enclosingElement) == null) {
isElementRemaining = true;
} else {
GeneratedClassHolder generatedClassHolder = generatingAnnotationHandler.createGeneratedClassHolder(environment, typeElement);
processHolder.put(annotatedElement, generatedClassHolder);
generatingAnnotationHandler.process(annotatedElement, generatedClassHolder);
}
}
} else {
LOGGER.trace("Skip element {} because it's abstract", annotatedElement);
}
}
/*
* We currently do not take into account class annotations from
* ancestors. We should careful design the priority rules first.
*/
}
return isElementRemaining;
}
}