All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.richfaces.cdk.apt.AptSourceUtils Maven / Gradle / Ivy

The newest version!
package org.richfaces.cdk.apt;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
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.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;

import org.richfaces.cdk.CdkException;
import org.richfaces.cdk.Logger;
import org.richfaces.cdk.model.ClassName;
import org.richfaces.cdk.model.FacesId;
import org.richfaces.cdk.util.PropertyUtils;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;

/**
 * 

* Implementation to use in annotation processor. *

* * @author [email protected] * */ public class AptSourceUtils implements SourceUtils { private static final String IS = "is"; private static final int IS_LENGTH = IS.length(); private static final String GET = "get"; private static final String SET = "set"; private static final int SET_LENGTH = SET.length(); private static final int GET_LENGTH = GET.length(); private static final ImmutableSet HIDDEN_PROPERTIES = ImmutableSet.of("eventNames", "defaultEventName", "clientBehaviors", "family", "class"); private final ProcessingEnvironment processingEnv; private Map> beanPropertyCache = Maps.newHashMap(); @Inject private Logger log; /** *

*

* * @param processingEnv */ public AptSourceUtils(ProcessingEnvironment processingEnv) { this.processingEnv = processingEnv; } /** *

* Get all fields and bean properties that are annotated with given annotation. *

* * @param annotation * @param type * @return */ public Set getBeanPropertiesAnnotatedWith(Class annotation, TypeElement type) { Set properties = new HashSet(); Map beanProperties = getBeanProperties(type); for (BeanProperty beanProperty : beanProperties.values()) { if (beanProperty.isAnnotationPresent(annotation)) { properties.add(beanProperty); } } return properties; } public Set getAbstractBeanProperties(TypeElement type) { Set properties = new HashSet(); Map beanProperties = getBeanProperties(type); for (BeanProperty beanProperty : beanProperties.values()) { if (!beanProperty.isExists()) { properties.add(beanProperty); } } return properties; } @Override public BeanProperty getBeanProperty(ClassName type, final String name) { return getBeanProperty(asTypeElement(type), name); } @Override public BeanProperty getBeanProperty(TypeElement type, final String name) { Map beanProperties = getBeanProperties(type); if (beanProperties.containsKey(name)) { return beanProperties.get(name); } else { return new DummyPropertyImpl(name); } } /** *

* Utility method to get all bean properties, similar to Introspector *

* * @param type * @return */ Map getBeanProperties(TypeElement type) { if (null == type) { return Collections.emptyMap(); } Name qName = type.getQualifiedName(); Map result = beanPropertyCache.get(qName); if (result != null) { return result; } result = Maps.newHashMap(); List members = this.processingEnv.getElementUtils().getAllMembers(type); // extract all getters/setters. for (Element element : members) { if (ElementKind.METHOD.equals(element.getKind())) { ExecutableElement method = (ExecutableElement) element; processMethod(type, result, method); } } beanPropertyCache.put(qName, result); return result; } private void processMethod(TypeElement type, Map result, ExecutableElement method) { if (isPublicNonStatic(method)) { if (isGetter(method)) { processBeanPropertyAccessor(type, result, method, false); } else if (isSetter(method)) { processBeanPropertyAccessor(type, result, method, true); } } } private void processBeanPropertyAccessor(TypeElement type, Map result, ExecutableElement method, boolean setter) { String propertyName = getPropertyName(method); if (!HIDDEN_PROPERTIES.contains(propertyName)) { ClassName propertyType = asClassDescription(setter ? method.getParameters().get(0).asType() : method .getReturnType()); if (result.containsKey(propertyName)) { // Merge property with existed one. AptBeanProperty beanProperty = result.get(propertyName); checkPropertyType(type, propertyName, propertyType, beanProperty); if (null != (setter ? beanProperty.setter : beanProperty.getter)) { log.debug("Two " + (setter ? "setter" : "getter") + " methods for the same bean property " + propertyName + " in the class " + type.getQualifiedName()); if (!method.getModifiers().contains(Modifier.ABSTRACT)) { beanProperty.setAccessMethod(method, setter); } } else { beanProperty.setAccessMethod(method, setter); } } else { AptBeanProperty beanProperty = new AptBeanProperty(propertyName); beanProperty.setAccessMethod(method, setter); beanProperty.type = propertyType; result.put(propertyName, beanProperty); } } } private String getPropertyName(ExecutableElement method) { return PropertyUtils.methodToName(method.getSimpleName().toString()); } private void checkPropertyType(TypeElement type, String propertyName, ClassName propertyType, AptBeanProperty beanProperty) { if (!propertyType.equals(beanProperty.type)) { log.warn("Unambiguious type for bean property " + propertyName + " in the class " + type.getQualifiedName()); } } private boolean isAbstract(ExecutableElement method) { return method.getModifiers().contains(Modifier.ABSTRACT); } private boolean isPublicNonStatic(ExecutableElement method) { Set modifiers = method.getModifiers(); return modifiers.contains(Modifier.PUBLIC) && !modifiers.contains(Modifier.STATIC); } private boolean isGetter(ExecutableElement e) { String methodName = e.getSimpleName().toString(); return (isGetterName(methodName) || isBooleanGetterName(methodName)) && 0 == e.getParameters().size(); } private boolean isGetterName(String methodName) { return methodName.startsWith(GET) && methodName.length() > GET_LENGTH && Character.isUpperCase(methodName.charAt(GET_LENGTH)); } private boolean isBooleanGetterName(String methodName) { return methodName.startsWith(IS) && methodName.length() > IS_LENGTH && Character.isUpperCase(methodName.charAt(IS_LENGTH)); } private boolean isSetter(ExecutableElement e) { String methodName = e.getSimpleName().toString(); return isSetterName(methodName) && 1 == e.getParameters().size() && !e.isVarArgs() && TypeKind.VOID.equals(e.getReturnType().getKind()); } private boolean isSetterName(String methodName) { return methodName.startsWith(SET) && methodName.length() > SET_LENGTH && Character.isUpperCase(methodName.charAt(SET_LENGTH)); } private ClassName asClassDescription(TypeMirror type) { return new ClassName(type.toString()); } public String getDocComment(Element componentElement) { return this.processingEnv.getElementUtils().getDocComment(componentElement); } @Override public AnnotationMirror getAnnotationMirror(Element element, Class annotationType) { List annotationMirrors = processingEnv.getElementUtils().getAllAnnotationMirrors(element); TypeMirror annotationTypeMirror = processingEnv.getElementUtils().getTypeElement(annotationType.getName()).asType(); for (AnnotationMirror annotationMirror : annotationMirrors) { if (processingEnv.getTypeUtils().isSameType(annotationTypeMirror, annotationMirror.getAnnotationType())) { return annotationMirror; } } return null; } @Override public boolean isAnnotationPresent(Element element, Class annotationType) { return null != element.getAnnotation(annotationType); } @Override public boolean isAnnotationPropertyPresent(AnnotationMirror annotation, final String propertyName) { return Iterables.any(getAnnotationValuesMap(annotation).entrySet(), new AnnotationAttributePredicate(propertyName)); } @Override public boolean isDefaultValue(AnnotationMirror annotation, String propertyName) { Map.Entry attributeEntry = findAnnotationProperty(annotation, propertyName); return !annotation.getElementValues().containsKey(attributeEntry.getKey()); } @Override public T getAnnotationValue(AnnotationMirror annotation, String propertyName, Class expectedType) { Map.Entry attributeEntry = findAnnotationProperty(annotation, propertyName); AnnotationValue annotationValue = attributeEntry.getValue(); return convertAnnotationValue(expectedType, annotationValue); } @SuppressWarnings("unchecked") private T convertAnnotationValue(Class expectedType, AnnotationValue annotationValue) { if (Enum.class.isAssignableFrom(expectedType)) { VariableElement variable = (VariableElement) annotationValue.getValue(); return (T) Enum.valueOf((Class) expectedType, variable.getSimpleName().toString()); } else if (ClassName.class.equals(expectedType)) { Object value = annotationValue.getValue(); return (T) ClassName.get(value.toString()); } else if (FacesId.class.equals(expectedType)) { String value = (String) annotationValue.getValue(); return (T) FacesId.parseId(value); } else if (AnnotationMirror.class.isAssignableFrom(expectedType)) { AnnotationMirror value = (AnnotationMirror) annotationValue.getValue(); return (T) value; } else { return (T) annotationValue.getValue(); } } @SuppressWarnings("unchecked") @Override public Iterable getAnnotationValues(AnnotationMirror annotation, String propertyName, Class expectedType) { Map.Entry attributeEntry = findAnnotationProperty(annotation, propertyName); List annotationValues = (List) attributeEntry.getValue() .getValue(); List values = Lists.newArrayList(); for (AnnotationValue annotationValue : annotationValues) { values.add(convertAnnotationValue(expectedType, annotationValue)); } return values; } private Entry findAnnotationProperty(AnnotationMirror annotation, final String propertyName) { try { return Iterables .find(getAnnotationValuesMap(annotation).entrySet(), new AnnotationAttributePredicate(propertyName)); } catch (NoSuchElementException e) { throw new CdkException("Attribute " + propertyName + " not found for annotation " + annotation.getAnnotationType().toString()); } } private Map getAnnotationValuesMap(AnnotationMirror annotation) { return processingEnv.getElementUtils().getElementValuesWithDefaults(annotation); } /** *

* Set model property to the corresponding annotation attribute, if annotation attribute set to non-default value. *

* * @param model Model object. * @param annotation annotation to copy property from. * @param modelProperty bean attribute name in the model and annotation. */ @Override public void setModelProperty(Object model, AnnotationMirror annotation, String modelProperty) { setModelProperty(model, annotation, modelProperty, modelProperty); } /** *

* Set model property to the corresponding annotation attribute, if annotation attribute set to non-default value. *

* * @param model Model object. * @param annotation annotation to copy property from. * @param modelProperty bean attribute name in model. * @param annotationAttribute annotation attribute name. */ @Override public void setModelProperty(Object model, AnnotationMirror annotation, String modelProperty, String annotationAttribute) { if (!isDefaultValue(annotation, annotationAttribute)) { PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(model, modelProperty); PropertyUtils.setPropertyValue(model, modelProperty, getAnnotationValue(annotation, annotationAttribute, propertyDescriptor.getPropertyType())); } } public Object getConstant(TypeElement componentElement, String name) { List fieldsIn = ElementFilter.fieldsIn(this.processingEnv.getElementUtils().getAllMembers( componentElement)); Object value = null; for (VariableElement field : fieldsIn) { Set modifiers = field.getModifiers(); if (modifiers.contains(Modifier.FINAL) && modifiers.contains(Modifier.STATIC) && field.getSimpleName().toString().equals(name)) { value = field.getConstantValue(); } } return value; } public void visitSupertypes(TypeElement type, SuperTypeVisitor visitor) { visitSupertypes(type.asType(), visitor); } private void visitSupertypes(TypeMirror type, SuperTypeVisitor visitor) { List supertypes = this.processingEnv.getTypeUtils().directSupertypes(type); for (TypeMirror typeMirror : supertypes) { visitSupertypes(typeMirror, visitor); } visitor.visit(type); } private TypeElement asTypeElement(ClassName type) { return processingEnv.getElementUtils().getTypeElement(type.toString()); } public boolean isClassExists(ClassName type) { return null != asTypeElement(type); } @Override public TypeElement asTypeElement(TypeMirror mirror) { if (TypeKind.DECLARED.equals(mirror.getKind())) { return (TypeElement) processingEnv.getTypeUtils().asElement(mirror); } else { return null; } } /** *

*

* * @author [email protected] * */ private static final class AnnotationAttributePredicate implements Predicate> { private final String propertyName; private AnnotationAttributePredicate(String propertyName) { this.propertyName = propertyName; } @Override public boolean apply(Entry input) { return this.propertyName.equals(input.getKey().getSimpleName().toString()); } } /** *

*

* * @author [email protected] * */ protected final class AptBeanProperty implements BeanProperty { private ExecutableElement getter; private ExecutableElement setter; private final String name; private ClassName type; /** *

*

* * @param name */ public AptBeanProperty(String name) { this.name = name; } void setAccessMethod(ExecutableElement method, boolean setter) { if (setter) { this.setter = method; } else { this.getter = method; } } /** *

*

* * @return the name */ public String getName() { return name; } /** *

* Get JavaDoc comment of appropriate bean property element. *

* * @return */ public String getDocComment() { String comment = getMethodComment(getter); if (null == comment) { comment = getMethodComment(setter); } return comment; } private String getMethodComment(ExecutableElement method) { if (null != method) { return processingEnv.getElementUtils().getDocComment(method); } else { return null; } } public ClassName getType() { return type; } /** *

*

* * @return the exists */ public boolean isExists() { return !(isAbstract(getter) || isAbstract(setter)); } private boolean isAbstract(ExecutableElement method) { return null != method && method.getModifiers().contains(Modifier.ABSTRACT); } public AnnotationMirror getAnnotationMirror(Class annotationType) { if (isAnnotationPresent(getter, annotationType)) { return AptSourceUtils.this.getAnnotationMirror(getter, annotationType); } else if (isAnnotationPresent(setter, annotationType)) { return AptSourceUtils.this.getAnnotationMirror(setter, annotationType); } return null; } @Override public boolean isAnnotationPresent(Class annotationType) { return isAnnotationPresent(getter, annotationType) || isAnnotationPresent(setter, annotationType); } @Override public T getAnnotation(Class annotationType) { if (isAnnotationPresent(getter, annotationType)) { return getter.getAnnotation(annotationType); } else if (isAnnotationPresent(setter, annotationType)) { return setter.getAnnotation(annotationType); } return null; } private boolean isAnnotationPresent(ExecutableElement method, Class annotationType) { return null != method && null != method.getAnnotation(annotationType); } @Override public ACCESS_TYPE getAccessType() { if (null != getter && null != setter) { return ACCESS_TYPE.readWrite; } else if (null == setter) { return ACCESS_TYPE.readOnly; } return ACCESS_TYPE.writeOnly; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } AptBeanProperty other = (AptBeanProperty) obj; if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } @Override public String toString() { return name + "[" + getType() + "]"; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy