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

com.github.wglanzer.annosave.processor.AnnoSaveConverterImpl Maven / Gradle / Ivy

There is a newer version: 1.2.4
Show newest version
package com.github.wglanzer.annosave.processor;

import com.github.wglanzer.annosave.api.*;
import com.github.wglanzer.annosave.api.containers.IMethodContainer;
import com.github.wglanzer.annosave.impl.util.TypeFactory;
import com.google.auto.common.AnnotationMirrors;
import com.google.common.base.Predicates;
import com.google.common.primitives.Primitives;
import org.jetbrains.annotations.*;

import javax.lang.model.element.*;
import javax.lang.model.type.TypeMirror;
import java.util.*;
import java.util.stream.*;

/**
 * @author W.Glanzer, 15.09.2017
 */
class AnnoSaveConverterImpl implements IAnnoSaveConverter
{
  @Override
  public List createContainer(Element pElement)
  {
    if (_getChildren(pElement).length == 0 && _getAnnotations(pElement).length == 0)
      return null;

    ArrayList result = new ArrayList<>();
    if (ElementUtil.isMethod(pElement))
      result.add(new _MethodContainer((ExecutableElement) pElement));
    else
      result.add(new _AnnotationContainer(pElement));

    // Child-Classes
    if(ElementUtil.isType(pElement))
      result.addAll(_getSubClasses(pElement));
    return result;
  }

  @NotNull
  private IAnnotation[] _getAnnotations(Element pElement)
  {
    ArrayList annos = new ArrayList<>();
    for (AnnotationMirror annotationMirror : pElement.getAnnotationMirrors())
    {
      IAnnotation anno = _toAnno(annotationMirror);
      if (anno != null)
        annos.add(anno);
    }
    return annos.toArray(new IAnnotation[annos.size()]);
  }

  @NotNull
  private IAnnotationContainer[] _getChildren(Element pElement)
  {
    return pElement.getEnclosedElements().stream()
        .filter(Predicates.not(ElementUtil::isConstructor).and(Predicates.not(ElementUtil::isType)))
        .flatMap(pEle -> {
          List containers = createContainer(pEle);
          if(containers == null)
            return Stream.empty();
          return containers.stream();
        })
        .filter(Objects::nonNull)
        .toArray(IAnnotationContainer[]::new);
  }

  @NotNull
  private List _getSubClasses(Element pElement)
  {
    return pElement.getEnclosedElements().stream()
        .filter(ElementUtil::isType)
        .flatMap(pEle -> {
          List containers = createContainer(pEle);
          if(containers == null)
            return Stream.empty();
          return containers.stream();
        })
        .filter(Objects::nonNull)
        .collect(Collectors.toList());
  }

  @Nullable
  private IAnnotation _toAnno(AnnotationMirror pMirror)
  {
    if (!new PersistenceFilter().test(pMirror))
      return null;

    return new _Annotation(pMirror);
  }

  @NotNull
  private IAnnotationParameter _toParameter(ExecutableElement pElement, AnnotationValue pValue)
  {
    return new _AnnotationParameter(pElement, pValue);
  }

  /**
   * IAnnotation-Impl
   */
  private class _Annotation implements IAnnotation
  {
    private final AnnotationMirror mirror;

    _Annotation(AnnotationMirror pMirror)
    {
      mirror = pMirror;
    }

    @NotNull
    @Override
    public String getName()
    {
      return mirror.getAnnotationType().toString();
    }

    @NotNull
    @Override
    public IType getType()
    {
      return TypeFactory.create(mirror.getAnnotationType().toString());
    }

    @NotNull
    @Override
    public IAnnotationParameter[] getParameters()
    {
      ArrayList params = new ArrayList<>();
      AnnotationMirrors.getAnnotationValuesWithDefaults(mirror).forEach((pName, pValue) -> params.add(_toParameter(pName, pValue)));
      return params.toArray(new IAnnotationParameter[params.size()]);
    }
  }

  /**
   * IAnnotationParameter-Impl
   */
  private class _AnnotationParameter implements IAnnotationParameter
  {
    private final ExecutableElement element;
    private final AnnotationValue value;

    _AnnotationParameter(ExecutableElement pElement, AnnotationValue pValue)
    {
      element = pElement;
      value = pValue;
    }

    @Override
    public String getName()
    {
      return element.getSimpleName().toString();
    }

    @NotNull
    @Override
    public IType getType()
    {
      return TypeFactory.create(ElementUtil.getClassName(element.getReturnType()));
    }

    @Override
    public Object getValue()
    {
      return _extractValueFromAnnotationValue(value);
    }

    private Object _extractValueFromAnnotationValue(AnnotationValue pValue)
    {
      Object value = pValue.getValue();
      if (value instanceof List)
      {
        if (((List) value).get(0) instanceof AnnotationMirror)
        {
          return ((List) value).stream()
              .map(pMirror -> _toAnno(pMirror))
              .toArray(IAnnotation[]::new);
        }
        else if (((List) value).get(0) instanceof AnnotationValue)
        {
          return ((List) value).stream()
              .map(this::_extractValueFromAnnotationValue)
              .toArray(Object[]::new);
        }
      }

      // Maybe it is a Class-Type? (int.class, String.class, ...)
      if (value instanceof TypeMirror)
        return ElementUtil.getClassName((TypeMirror) value);

      // Already a correct value?
      if (value instanceof String ||
          value.getClass().isPrimitive() ||
          Primitives.isWrapperType(value.getClass()))
        return value;

      return value.toString();
    }
  }

  /**
   * IAnnotationContainer-Impl
   */
  private class _AnnotationContainer implements IAnnotationContainer
  {
    private final Element element;

    _AnnotationContainer(Element pElement)
    {
      element = pElement;
    }

    @NotNull
    @Override
    public String getName()
    {
      if(ElementUtil.isMethod(element))
        return element.getSimpleName().toString();
      else if(ElementUtil.isType(element))
        return ElementUtil.getClassName(element.asType());
      return element.toString();
    }

    @NotNull
    @Override
    public IType getType()
    {
      String className;
      if (ElementUtil.isField(element))
        className = ElementUtil.getClassName(element.asType());
      else if (ElementUtil.isMethod(element))
        className = ElementUtil.getClassName(((ExecutableElement) element).getReturnType());
      else
        className = ElementUtil.flatName(element, element.toString());
      return TypeFactory.create(className);
    }

    @NotNull
    @Override
    public IAnnotation[] getAnnotations()
    {
      return _getAnnotations(element);
    }

    @NotNull
    @Override
    public IAnnotationContainer[] getChildren()
    {
      return _getChildren(element);
    }
  }

  /**
   * IMethodContainer-Impl
   */
  private class _MethodContainer extends _AnnotationContainer implements IMethodContainer
  {
    private final ExecutableElement element;

    _MethodContainer(ExecutableElement pElement)
    {
      super(pElement);
      element = pElement;
    }

    @NotNull
    @Override
    public IType[] getMethodParameters()
    {
      return element.getParameters().stream()
          .map(Element::asType)
          .map(pEle -> TypeFactory.create(ElementUtil.getClassName(pEle)))
          .toArray(IType[]::new);
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy