private IAnnotationModel processAnnotation(CtAnnotation<? extends Annotation> annotation) {

    String simpleName = annotation.getActualAnnotation().annotationType().getSimpleName();

    AnnotationModel annotationModel = new AnnotationModel();
    annotationModel.setName(simpleName);

    Map<String, Object> elementValues = annotation.getElementValues();

    for (Map.Entry<String, Object> entry : elementValues.entrySet()) {

      String key = entry.getKey();
      if (key == null) {
        continue;
      }

      Object value = entry.getValue();
      ArrayList<CtAnnotation<?>> annotationList = toCtAnnotationList(value);
      if (annotationList != null) {
        int size = annotationList.size();
        IAnnotationModel[] annotationModels = new IAnnotationModel[size];
        for (int i = 0; i < size; i++) {
          CtAnnotation<?> subAnnotation = annotationList.get(i);
          IAnnotationModel subAnnotationModel = processAnnotation(subAnnotation);
          annotationModels[i] = subAnnotationModel;
        }
        annotationModel.addValue(key, annotationModels);
      } else if (value instanceof String[]) {
        annotationModel.addValue(key, value);
      } else {
        if (value instanceof CtNewArray<?>) {
          List<?> elements = ((CtNewArray<?>) value).getElements();
          int size = elements.size();
          Object[] arr = new Object[size];
          for (int i = 0; i < size; i++) {
            Object elem = elements.get(i);
            if (elem instanceof CtCodeElement) {
              PartialEvaluator eval = factory.Eval().createPartialEvaluator();
              arr[i] = eval.evaluate(null, (CtCodeElement) elem);
            } else {
              arr[i] = elem;
            }
          }
          value = arr;
        }
        if (value instanceof CtCodeElement) {
          PartialEvaluator eval = factory.Eval().createPartialEvaluator();
          value = eval.evaluate(null, (CtCodeElement) value);
        }

        if (value instanceof CtLiteral<?>) {
          value = ((CtLiteral<?>) value).getValue().toString();
        } else if (value instanceof CtFieldReference<?>) {
          Member member = ((CtFieldReference<?>) value).getActualField();

          // if field references a static final String, use string's value
          if (member instanceof Field) {
            Field field = (Field) member;

            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) && Modifier.isFinal(mod)) {
              field.setAccessible(true);
              try {
                value = field.get(null).toString();
              } catch (Throwable t) {
                value = member.getName();
                // NOOP tolerate any exception/error, and fall back to using name of field below
              }
            }
            // fall back to using name of field reference
            else {
              value = member.getName();
            }
          }

        } else if (value.getClass().isArray()) {
          int length = Array.getLength(value);
          String[] arr = new String[length];
          for (int i = 0; i < length; i++) {

            Object elem = Array.get(value, i);
            String sVal = elem.toString();
            if (elem instanceof CtLiteral<?>) {
              sVal = ((CtLiteral<?>) elem).getValue().toString();
            } else if (elem instanceof CtFieldReference<?>) {
              sVal = ((CtFieldReference<?>) elem).getActualField().getName();
            }
            arr[i] = sVal;
          }
          value = arr;
        } else {
          value = value.toString();
        }
        if (value == null) {
          value = "null";
        }
        annotationModel.addValue(key, value);
      }
    }
    return annotationModel;
  }