com.gwtplatform.dispatch.annotation.helper.ReflectionHelper Maven / Gradle / Ivy
/**
* Copyright 2011 ArcBees Inc.
*
* 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 com.gwtplatform.dispatch.annotation.helper;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import com.gwtplatform.dispatch.annotation.In;
import com.gwtplatform.dispatch.annotation.Optional;
import com.gwtplatform.dispatch.annotation.Order;
import com.gwtplatform.dispatch.annotation.Out;
/**
* {@link ReflectionHelper} is an internal class that provides common routines
* only used by the annotation processors.
*
* @author Brendan Doherty
* @author Florian Sauter
* @author Stephen Haberman (concept)
*/
@SuppressWarnings("unchecked")
public class ReflectionHelper {
private TypeElement classRepresenter;
private ProcessingEnvironment environment;
public ReflectionHelper(ProcessingEnvironment environment, TypeElement classRepresenter) {
this.classRepresenter = classRepresenter;
this.environment = environment;
}
public Collection filterConstantFields(Collection fieldElements) {
return filterFields(fieldElements, Modifier.STATIC, Modifier.FINAL);
}
/**
* Returns only fields which are not annotated with one of the passed annotation.
*/
public Collection filterFields(Collection fieldElements,
Class extends Annotation>... annotations) {
Collection filteredFields = new ArrayList();
filteredFields.addAll(fieldElements);
for (VariableElement fieldElement : fieldElements) {
for (Class extends Annotation> passedAnnotation : annotations) {
Annotation fieldAnnotation = fieldElement.getAnnotation(passedAnnotation);
if (fieldAnnotation != null) {
filteredFields.remove(fieldElement);
break;
}
}
}
return filteredFields;
}
/**
* Returns only fields which do not contain one of the passed modifiers.
*/
public Collection filterFields(Collection fieldElements, Modifier... modifiers) {
Collection filteredFields = new ArrayList();
filteredFields.addAll(fieldElements);
for (VariableElement fieldElement : fieldElements) {
for (Modifier modifier : modifiers) {
if (fieldElement.getModifiers().contains(modifier)) {
filteredFields.remove(fieldElement);
break;
}
}
}
return filteredFields;
}
/**
* Returns only fields which simple names do not equal the passed field names.
*/
public Collection filterFields(Collection fieldElements,
String... simpleFieldNames) {
Collection filteredFields = new ArrayList();
filteredFields.addAll(fieldElements);
for (VariableElement fieldElement : fieldElements) {
for (String simpleFieldName : simpleFieldNames) {
if (fieldElement.getSimpleName().toString().equals(simpleFieldName)) {
filteredFields.remove(fieldElement);
break;
}
}
}
return filteredFields;
}
/**
* Returns all fields annotated with the passed annotation classes.
*/
public Collection getAnnotatedFields(Class extends Annotation>... annotations) {
Collection fieldsCopy = getFields();
for (Class extends Annotation> annotation : annotations) {
Collection nonAnnotatedFields = filterFields(getFields(), annotation);
fieldsCopy.removeAll(nonAnnotatedFields);
}
return fieldsCopy;
}
/**
* Returns the class name.
*
* For example:
* {@code com.gwtplatform.dispatch.annotation.Foo}
*
*
* @return the class name.
*/
public String getClassName() {
return getPackageName() + '.' + getSimpleClassName();
}
public TypeElement getClassRepresenter() {
return classRepresenter;
}
/**
* Returns all fields ordered that are {@link Modifier.FINAL} or {@link Modifier.STATIC}.
*/
public Collection getConstantFields() {
return getModifierFields(Modifier.FINAL, Modifier.STATIC);
}
/**
* Returns all fields.
*
* Important: Fields are not sorted according to @{@link Order}!
*
* To get these sorted use {@link ReflectionHelper#getOrderedFields()}.
*/
public Collection getFields() {
List extends Element> members = getElementUtils().getAllMembers(classRepresenter);
return ElementFilter.fieldsIn(members);
}
/**
* Returns all fields which contains {@link Modifier.FINAL}.
*/
public Collection getFinalFields() {
return filterFields(getOrderedFields(), Modifier.FINAL);
}
/**
* Returns all fields annotated with @{@link In}. Sorted based on the @
* {@link In} annotation.
*/
public Collection getInFields() {
return sortFields(In.class, getAnnotatedFields(In.class));
}
/**
* Returns all fields with the passed modifier.
*/
public Collection getModifierFields(Modifier... modifiers) {
Collection modifierFields = new ArrayList();
modifierFields.addAll(getFields());
for (Modifier modifier : modifiers) {
Collection nonModifierFields = filterFields(getFields(), modifier);
modifierFields.removeAll(nonModifierFields);
}
return modifierFields;
}
/**
* Returns all fields that are not {@link Modifier.FINAL} or
* {@link Modifier.STATIC}. Sorted based on the @ {@link Order} annotation.
*/
public Collection getNonConstantFields() {
return filterFields(getOrderedFields(), Modifier.FINAL, Modifier.STATIC);
}
/**
* Returns all non constant fields annotated with @{@link Optional}. Sorted
* based on the @ {@link Order} annotation.
*/
public Collection getOptionalFields() {
return sortFields(Order.class, filterConstantFields(getAnnotatedFields(Optional.class)));
}
/**
* Returns all non constant fields annotated with passed annotation.
*
* Important: Fields are not sorted!
*
*/
public Collection getOptionalFields(Class extends Annotation> annotation) {
return filterConstantFields(getAnnotatedFields(Optional.class, annotation));
}
/**
* Returns all fields ordered. Sorted based on the @ {@link Order} annotation.
*/
public Collection getOrderedFields() {
return sortFields(Order.class, getFields());
}
/**
* Returns all fields annotated with @{@link Out}. Sorted based on the @
* {@link Out} annotation.
*/
public Collection getOutFields() {
return sortFields(Out.class, getAnnotatedFields(Out.class));
}
public String getPackageName() {
return getElementUtils().getPackageOf(classRepresenter).getQualifiedName().toString();
}
public ProcessingEnvironment getProcessingEnvironment() {
return environment;
}
/**
* Returns all non {@link Optional}|{@link Modifier#STATIC}|
* {@link Modifier#FINAL} fields ordered. Sorted based on the @
* {@link Order} annotation.
*
* Required are all:
*
* - Declared fields matching rules below
* - Non annotated {@link Optional} fields
* - Non {@link Modifier#STATIC} fields
* - Non {@link Modifier#FINAL} fields
*
*
*/
public Collection getRequiredFields() {
Collection fields = getFields();
fields.removeAll(getOptionalFields());
fields = filterFields(fields, Modifier.FINAL, Modifier.STATIC);
return sortFields(Order.class, fields);
}
public String getSimpleClassName() {
return classRepresenter.getSimpleName().toString();
}
/**
* Returns all fields which contains {@link Modifier.STATIC}.
*/
public Collection getStaticFields() {
return filterFields(getOrderedFields(), Modifier.STATIC);
}
/**
* Sorts the passed fields based on the passed annotation sort logic.
*/
public Collection sortFields(Class extends Annotation> annotation,
Collection fields) {
SortedMap sortedFields = new TreeMap();
if (In.class.equals(annotation)) {
sortInFields(sortedFields, fields);
} else if (Out.class.equals(annotation)) {
sortOutFields(sortedFields, fields);
} else if (Order.class.equals(annotation)) {
sortOrderFields(sortedFields, fields);
} else {
return fields;
}
return sortedFields.values();
}
public boolean hasOptionalFields() {
return getOptionalFields().size() > 0;
}
public boolean hasRequiredFields() {
return getRequiredFields().size() > 0;
}
/**
* Utility method.
*/
protected Elements getElementUtils() {
return environment.getElementUtils();
}
protected void sortInFields(SortedMap sortedFields, Collection fields) {
for (VariableElement fieldElement : fields) {
In inFieldAnnotation = fieldElement.getAnnotation(In.class);
if (inFieldAnnotation != null) {
sortedFields.put(inFieldAnnotation.value(), fieldElement);
}
}
}
protected void sortOrderFields(SortedMap sortedFields,
Collection fields) {
int maxOrderNum = -1;
for (VariableElement fieldElement : fields) {
Order order = fieldElement.getAnnotation(Order.class);
if (order != null) {
maxOrderNum = Math.max(maxOrderNum, order.value());
}
}
for (VariableElement fieldDecl : fields) {
Order order = fieldDecl.getAnnotation(Order.class);
if (order != null) {
maxOrderNum = Math.max(maxOrderNum, order.value());
sortedFields.put(order.value(), fieldDecl);
} else {
sortedFields.put(++maxOrderNum, fieldDecl);
}
}
}
protected void sortOutFields(SortedMap sortedFields, Collection fields) {
for (VariableElement fieldElement : fields) {
Out outFieldAnnotation = fieldElement.getAnnotation(Out.class);
if (outFieldAnnotation != null) {
sortedFields.put(outFieldAnnotation.value(), fieldElement);
}
}
}
}