// Path: jackdaw-apt/src/main/java/com/github/vbauer/jackdaw/util/model/MethodInfo.java
// public class MethodInfo {
// 
//     private final String name;
//     private final TypeMirror returnType;
//     private final List<TypeMirror> parameterTypes;
//     private final ExecutableElement element;
// 
// 
//     public MethodInfo(
//         final String name, final TypeMirror returnType, final List<TypeMirror> parameterTypes,
//         final ExecutableElement element
//     ) {
//         this.name = name;
//         this.returnType = returnType;
//         this.parameterTypes = parameterTypes;
//         this.element = element;
//     }
// 
// 
//     public static MethodInfo create(final ExecutableElement element) {
//         return new MethodInfo(
//             TypeUtils.getName(element),
//             element.getReturnType(),
//             TypeUtils.asTypes(element.getParameters()),
//             element
//         );
//     }
// 
//     public static Set<ExecutableElement> convert(final Collection<MethodInfo> info) {
//         final Set<ExecutableElement> methods = Sets.newHashSet();
//         for (final MethodInfo method : info) {
//             methods.add(method.getElement());
//         }
//         return methods;
//     }
// 
//     public static MethodInfo find(
//         final Collection<MethodInfo> info, final String name, final Collection<TypeMirror> types
//     ) {
//         for (final MethodInfo method : info) {
//             final String methodName = method.getName();
//             if (StringUtils.equals(methodName, name)
//                 && Objects.equal(method.getParameterTypes(), types)) {
//                 return method;
//             }
//         }
//         return null;
//     }
// 
// 
//     public final String getName() {
//         return name;
//     }
// 
//     public final TypeMirror getReturnType() {
//         return returnType;
//     }
// 
//     public final List<TypeMirror> getParameterTypes() {
//         return parameterTypes;
//     }
// 
//     public final ExecutableElement getElement() {
//         return element;
//     }
// 
// 
//     @Override
//     public final int hashCode() {
//         return Objects.hashCode(
//             getName(),
//             getParameterTypes(),
//             getReturnType()
//         );
//     }
// 
//     @Override
//     public final boolean equals(final Object obj) {
//         if (obj instanceof  MethodInfo) {
//             final MethodInfo other = (MethodInfo) obj;
//             return Objects.equal(other.getName(), getName())
//                 && Objects.equal(other.getParameterTypes(), getParameterTypes())
//                 && Objects.equal(other.getReturnType(), getReturnType());
//         }
//         return false;
//     }
// 
// }


import com.github.vbauer.jackdaw.util.callback.AnnotatedElementCallback;
import com.github.vbauer.jackdaw.util.model.MethodInfo;
import com.google.common.base.CaseFormat;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import org.apache.commons.lang3.StringUtils;
import javax.lang.model.element.AnnotationMirror;
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.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementFilter;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
            .build();
    }

    public static MethodSpec createSetter(final VariableElement field) {
        final TypeName type = TypeUtils.getTypeName(field);
        final String fieldName = TypeUtils.getName(field);
        final String setterName = TypeUtils.setterName(fieldName);

        return MethodSpec.methodBuilder(setterName)
            .addModifiers(Modifier.PUBLIC)
            .returns(TypeName.VOID)
            .addParameter(type, fieldName, Modifier.FINAL)
            .addStatement("this.$L = $L", fieldName, fieldName)
            .build();
    }

    public static <T extends Annotation> void processSimpleMethodsAndVariables(
        final TypeSpec.Builder builder, final TypeElement typeElement,
        final Class<T> annotationClass, final AnnotatedElementCallback<T> callback
    ) throws Exception {
        final List<? extends Element> elements = typeElement.getEnclosedElements();
        final List<VariableElement> fields = ElementFilter.fieldsIn(elements);
        final List<ExecutableElement> methods = ElementFilter.methodsIn(elements);

        TypeUtils.filterWithAnnotation(typeElement, fields, annotationClass,
            new AnnotatedElementCallback<T>() {
                @Override
                public void process(final Element element, final T annotation) throws Exception {
                    if (!TypeUtils.hasAnyModifier(element, Modifier.STATIC)) {
                        final String name = TypeUtils.getterName(element);
// Path: jackdaw-apt/src/main/java/com/github/vbauer/jackdaw/util/model/MethodInfo.java
// public class MethodInfo {
// 
//     private final String name;
//     private final TypeMirror returnType;
//     private final List<TypeMirror> parameterTypes;
//     private final ExecutableElement element;
// 
// 
//     public MethodInfo(
//         final String name, final TypeMirror returnType, final List<TypeMirror> parameterTypes,
//         final ExecutableElement element
//     ) {
//         this.name = name;
//         this.returnType = returnType;
//         this.parameterTypes = parameterTypes;
//         this.element = element;
//     }
// 
// 
//     public static MethodInfo create(final ExecutableElement element) {
//         return new MethodInfo(
//             TypeUtils.getName(element),
//             element.getReturnType(),
//             TypeUtils.asTypes(element.getParameters()),
//             element
//         );
//     }
// 
//     public static Set<ExecutableElement> convert(final Collection<MethodInfo> info) {
//         final Set<ExecutableElement> methods = Sets.newHashSet();
//         for (final MethodInfo method : info) {
//             methods.add(method.getElement());
//         }
//         return methods;
//     }
// 
//     public static MethodInfo find(
//         final Collection<MethodInfo> info, final String name, final Collection<TypeMirror> types
//     ) {
//         for (final MethodInfo method : info) {
//             final String methodName = method.getName();
//             if (StringUtils.equals(methodName, name)
//                 && Objects.equal(method.getParameterTypes(), types)) {
//                 return method;
//             }
//         }
//         return null;
//     }
// 
// 
//     public final String getName() {
//         return name;
//     }
// 
//     public final TypeMirror getReturnType() {
//         return returnType;
//     }
// 
//     public final List<TypeMirror> getParameterTypes() {
//         return parameterTypes;
//     }
// 
//     public final ExecutableElement getElement() {
//         return element;
//     }
// 
// 
//     @Override
//     public final int hashCode() {
//         return Objects.hashCode(
//             getName(),
//             getParameterTypes(),
//             getReturnType()
//         );
//     }
// 
//     @Override
//     public final boolean equals(final Object obj) {
//         if (obj instanceof  MethodInfo) {
//             final MethodInfo other = (MethodInfo) obj;
//             return Objects.equal(other.getName(), getName())
//                 && Objects.equal(other.getParameterTypes(), getParameterTypes())
//                 && Objects.equal(other.getReturnType(), getReturnType());
//         }
//         return false;
//     }
// 
// }


// Path: jackdaw-apt/src/main/java/com/github/vbauer/jackdaw/util/SourceCodeUtils.java
import com.github.vbauer.jackdaw.util.callback.AnnotatedElementCallback;
import com.github.vbauer.jackdaw.util.model.MethodInfo;
import com.google.common.base.CaseFormat;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import org.apache.commons.lang3.StringUtils;
import javax.lang.model.element.AnnotationMirror;
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.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementFilter;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

            .build();
    }

    public static MethodSpec createSetter(final VariableElement field) {
        final TypeName type = TypeUtils.getTypeName(field);
        final String fieldName = TypeUtils.getName(field);
        final String setterName = TypeUtils.setterName(fieldName);

        return MethodSpec.methodBuilder(setterName)
            .addModifiers(Modifier.PUBLIC)
            .returns(TypeName.VOID)
            .addParameter(type, fieldName, Modifier.FINAL)
            .addStatement("this.$L = $L", fieldName, fieldName)
            .build();
    }

    public static <T extends Annotation> void processSimpleMethodsAndVariables(
        final TypeSpec.Builder builder, final TypeElement typeElement,
        final Class<T> annotationClass, final AnnotatedElementCallback<T> callback
    ) throws Exception {
        final List<? extends Element> elements = typeElement.getEnclosedElements();
        final List<VariableElement> fields = ElementFilter.fieldsIn(elements);
        final List<ExecutableElement> methods = ElementFilter.methodsIn(elements);

        TypeUtils.filterWithAnnotation(typeElement, fields, annotationClass,
            new AnnotatedElementCallback<T>() {
                @Override
                public void process(final Element element, final T annotation) throws Exception {
                    if (!TypeUtils.hasAnyModifier(element, Modifier.STATIC)) {
                        final String name = TypeUtils.getterName(element);
                        final Collection<MethodInfo> methods = ModelUtils.findImplementedMethods(typeElement);