org.jboss.forge.roaster.model.impl.AnnotationImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.forge.roaster.model.impl.AnnotationImpl.java

Source

/*
 * Copyright 2012-2014 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Eclipse Public License version 1.0, available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.jboss.forge.roaster.model.impl;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.TypeLiteral;
import org.jboss.forge.roaster.Roaster;
import org.eclipse.jdt.core.dom.Annotation;
import org.jboss.forge.roaster.model.JavaClass;
import org.jboss.forge.roaster.model.Type;
import org.jboss.forge.roaster.model.ValuePair;
import org.jboss.forge.roaster.model.source.AnnotationSource;
import org.jboss.forge.roaster.model.source.AnnotationTargetSource;
import org.jboss.forge.roaster.model.source.Import;
import org.jboss.forge.roaster.model.source.JavaSource;
import org.jboss.forge.roaster.model.util.Types;

import static java.util.Objects.requireNonNull;
import static java.util.function.Predicate.isEqual;

/**
 * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
 */
public class AnnotationImpl<O extends JavaSource<O>, T> implements AnnotationSource<O> {
    private static final String MISSING = "MISSING";
    private static final String DEFAULT_VALUE = "value";

    private AST ast;
    private Annotation annotation;
    private AnnotationTargetSource<O, T> parent;

    private class Nested extends AnnotationImpl<O, T> {
        Nested(AnnotationImpl<O, T> owner) {
            super(owner.parent);
        }

        Nested(AnnotationImpl<O, T> owner, Object internal) {
            super(owner.parent, internal);
        }

        @Override
        protected void replace(Annotation oldNode, Annotation newNode) {
            if (oldNode.getParent() instanceof SingleMemberAnnotation) {
                ((SingleMemberAnnotation) oldNode.getParent()).setValue(newNode);
            } else if (oldNode.getParent() instanceof MemberValuePair) {
                ((MemberValuePair) oldNode.getParent()).setValue(newNode);
            } else if (oldNode.getParent() instanceof ArrayInitializer) {
                @SuppressWarnings("unchecked")
                final List<Annotation> expressions = ((ArrayInitializer) oldNode.getParent()).expressions();
                expressions.set(expressions.indexOf(oldNode), newNode);
            }
        }
    }

    private static enum AnnotationType {
        MARKER, SINGLE, NORMAL
    }

    public AnnotationImpl(final AnnotationTargetSource<O, T> parent) {
        this(parent, AnnotationType.MARKER);
    }

    public AnnotationImpl(final AnnotationTargetSource<O, T> parent, final Object internal) {
        this.parent = parent;
        this.ast = ((ASTNode) parent.getInternal()).getAST();
        this.annotation = (Annotation) requireNonNull(internal);
    }

    public AnnotationImpl(final AnnotationTargetSource<O, T> parent, final AnnotationType type) {
        this(parent, createAnnotation(parent, type));
    }

    private static Annotation createAnnotation(final AnnotationTargetSource<?, ?> parent,
            final AnnotationType type) {
        AST ast = ((ASTNode) parent.getInternal()).getAST();
        switch (type) {
        case MARKER:
            return ast.newMarkerAnnotation();
        case SINGLE:
            return ast.newSingleMemberAnnotation();
        case NORMAL:
            return ast.newNormalAnnotation();
        default:
            throw new IllegalArgumentException("Unknown annotation type: " + type);
        }
    }

    @Override
    public String getName() {
        Name name = annotation.getTypeName();
        if (name.getFullyQualifiedName().equals(MISSING)) {
            return MISSING;
        }
        if (name.isSimpleName()) {
            return name.getFullyQualifiedName();
        }
        return Types.toSimpleName(name.getFullyQualifiedName());
    }

    @Override
    public String getQualifiedName() {
        Name name = annotation.getTypeName();
        if (name.getFullyQualifiedName().equals(MISSING)) {
            return MISSING;
        }
        if (name.isSimpleName()) {
            return parent.getOrigin().resolveType(name.getFullyQualifiedName());
        }
        return name.getFullyQualifiedName();
    }

    @Override
    public String getLiteralValue() {
        if (isSingleValue()) {
            Expression value = ((SingleMemberAnnotation) annotation).getValue();
            if (value instanceof TypeLiteral) {
                return resolveTypeLiteralName((TypeLiteral) value);
            }
            return value.toString();
        }
        if (isNormal()) {
            for (ValuePair pair : getValues()) {
                if (DEFAULT_VALUE.equals(pair.getName())) {
                    return pair.getLiteralValue();
                }
            }
        }
        return null;
    }

    @Override
    public String getLiteralValue(final String name) {
        if (DEFAULT_VALUE.equals(name) && isSingleValue()) {
            return getLiteralValue();
        }
        if (isNormal()) {
            for (Object v : ((NormalAnnotation) annotation).values()) {
                if (v instanceof MemberValuePair) {
                    MemberValuePair pair = (MemberValuePair) v;
                    if (pair.getName().getFullyQualifiedName().equals(name)) {
                        Expression value = pair.getValue();
                        if (value instanceof TypeLiteral) {
                            return resolveTypeLiteralName((TypeLiteral) value);
                        }
                        return value.toString();
                    }
                }
            }
        }
        return null;
    }

    @Override
    public List<ValuePair> getValues() {
        List<ValuePair> result = new ArrayList<>();
        if (isNormal()) {
            for (Object v : ((NormalAnnotation) annotation).values()) {
                if (v instanceof MemberValuePair) {
                    MemberValuePair pair = (MemberValuePair) v;
                    ValuePair temp = new ValuePairImpl(pair.getName().getFullyQualifiedName(),
                            pair.getValue().toString());
                    result.add(temp);
                }
            }
        } else if (isSingleValue()) {
            result.add(new ValuePairImpl(DEFAULT_VALUE, getLiteralValue()));
        }
        return Collections.unmodifiableList(result);
    }

    @Override
    public String getStringValue() throws IllegalStateException {
        return Strings.unquote(getLiteralValue());
    }

    @Override
    public String getStringValue(final String name) {
        return Strings.unquote(getLiteralValue(name));
    }

    @Override
    public boolean isMarker() {
        return annotation.isMarkerAnnotation();
    }

    @Override
    public boolean isNormal() {
        return annotation.isNormalAnnotation();
    }

    @Override
    public boolean isSingleValue() {
        return annotation.isSingleMemberAnnotation();
    }

    @Override
    public AnnotationSource<O> removeAllValues() {
        convertTo(AnnotationType.MARKER);
        return this;
    }

    @Override
    @SuppressWarnings("unchecked")
    public AnnotationSource<O> removeValue(final String name) {
        if (annotation.isNormalAnnotation()) {
            NormalAnnotation normalAnnotation = (NormalAnnotation) annotation;

            List<MemberValuePair> toRemove = new ArrayList<>();
            for (Object annotationValue : normalAnnotation.values()) {
                if (annotationValue instanceof MemberValuePair) {
                    MemberValuePair pair = (MemberValuePair) annotationValue;
                    if (pair.getName().toString().equals(name)) {
                        toRemove.add(pair);
                    }
                }
            }
            normalAnnotation.values().removeAll(toRemove);

            if ((getLiteralValue() != null) && (getValues().size() == 1)) {
                convertTo(AnnotationType.SINGLE);
            } else if (getValues().size() == 0) {
                convertTo(AnnotationType.MARKER);
            }
        } else if (annotation.isSingleMemberAnnotation()) {
            removeAllValues();
        }
        return this;
    }

    @Override
    public AnnotationSource<O> setName(final String className) {
        annotation.setTypeName(ast.newName(className));
        return this;
    }

    @SuppressWarnings("unchecked")
    @Override
    public AnnotationSource<O> setLiteralValue(final String value) {
        requireNonNull(value);

        if (isMarker()) {
            convertTo(AnnotationType.SINGLE);
        }

        if (isSingleValue()) {
            String stub = "@" + getName() + "(" + value + ") public class Stub { }";
            JavaClass<?> temp = Roaster.parse(JavaClass.class, stub);

            Object internal = temp.getAnnotations().get(0).getInternal();
            if (internal instanceof SingleMemberAnnotation) {
                SingleMemberAnnotation singleMemberAnnotation = (SingleMemberAnnotation) annotation;
                Expression expression = ((SingleMemberAnnotation) internal).getValue();
                singleMemberAnnotation.setValue((Expression) ASTNode.copySubtree(ast, expression));
            } else if (internal instanceof NormalAnnotation) {
                NormalAnnotation internalNormalAnnotation = (NormalAnnotation) internal;
                convertTo(AnnotationType.NORMAL);
                NormalAnnotation normalAnnotation = (NormalAnnotation) annotation;

                for (MemberValuePair pair : (List<MemberValuePair>) internalNormalAnnotation.values()) {
                    normalAnnotation.values().add(ASTNode.copySubtree(annotation.getAST(), pair));
                }
            } else {
                throw new IllegalArgumentException(
                        "Type " + internal.getClass().getName() + " cannot be handled in this method");
            }
        } else {
            setLiteralValue(DEFAULT_VALUE, value);
        }

        return this;
    }

    @Override
    @SuppressWarnings("unchecked")
    public AnnotationSource<O> setLiteralValue(final String name, final String value) {
        requireNonNull(value);

        if (!isNormal() && !DEFAULT_VALUE.equals(name)) {
            convertTo(AnnotationType.NORMAL);
        } else if (!isSingleValue() && !isNormal() && DEFAULT_VALUE.equals(name)) {
            convertTo(AnnotationType.SINGLE);
        }
        if (isSingleValue() && DEFAULT_VALUE.equals(name)) {
            return setLiteralValue(value);
        }

        NormalAnnotation normalAnnotation = (NormalAnnotation) annotation;

        String stub = "@" + getName() + "(" + name + "=" + value + " ) public class Stub { }";
        JavaClass<?> temp = Roaster.parse(JavaClass.class, stub);

        NormalAnnotation anno = (NormalAnnotation) temp.getAnnotations().get(0).getInternal();
        MemberValuePair pair = (MemberValuePair) anno.values().get(0);

        List<MemberValuePair> values = normalAnnotation.values();
        ListIterator<MemberValuePair> iter = values.listIterator();
        while (iter.hasNext()) {
            if (iter.next().getName().getIdentifier().equals(name)) {
                iter.remove();
                break;
            }
        }
        iter.add((MemberValuePair) ASTNode.copySubtree(annotation.getAST(), pair));

        return this;
    }

    @Override
    public AnnotationSource<O> setStringValue(final String value) {
        return setLiteralValue(Strings.enquote(value));
    }

    @Override
    public AnnotationSource<O> setStringValue(final String name, final String value) {
        return setLiteralValue(name, Strings.enquote(value));
    }

    @Override
    public <E extends Enum<E>> E getEnumValue(final Class<E> type) {
        String literalValue = getLiteralValue();
        return convertLiteralToEnum(type, literalValue);
    }

    @Override
    public <E extends Enum<E>> E getEnumValue(final Class<E> type, final String name) {
        String literalValue = getLiteralValue(name);
        return convertLiteralToEnum(type, literalValue);
    }

    private <E extends Enum<E>> E convertLiteralToEnum(final Class<E> type, String literalValue) {
        E[] constants = type.getEnumConstants();

        for (E inst : constants) {
            String[] tokens = literalValue.split("\\.");
            if (tokens.length > 1) {
                literalValue = tokens[tokens.length - 1];
            }

            if (inst.name().equals(literalValue)) {
                return inst;
            }
        }
        return null;
    }

    @Override
    public AnnotationSource<O> setEnumValue(final String name, final Enum<?> value) {
        return setEnumArrayValue(name, value);
    }

    @Override
    public AnnotationSource<O> setEnumValue(final Enum<?>... values) {
        return setEnumArrayValue(values);
    }

    @Override
    public AnnotationSource<O> setEnumArrayValue(Enum<?>... values) {
        return setEnumArrayValue(DEFAULT_VALUE, values);
    }

    @Override
    public AnnotationSource<O> setEnumArrayValue(String name, final Enum<?>... values) {
        final List<String> literals = new ArrayList<>();

        for (Enum<?> value : requireNonNull(values)) {
            Import imprt = getOrigin().addImport(requireNonNull(value).getDeclaringClass());
            if (imprt == null) {
                literals.add(value.getDeclaringClass().getCanonicalName() + "." + value.name());
            } else {
                literals.add(value.getDeclaringClass().getSimpleName() + "." + value.name());
            }
        }
        return setArrayLiteralValue(name, literals);
    }

    /*
     * Shared interface methods.
     */
    @Override
    public O getOrigin() {
        return parent.getOrigin();
    }

    @Override
    public Object getInternal() {
        return annotation;
    }

    @Override
    public String toString() {
        return annotation.toString();
    }

    @SuppressWarnings("unchecked")
    protected void replace(Annotation oldNode, Annotation newNode) {
        List<IExtendedModifier> modifiers;
        ASTNode parentNode = oldNode.getParent();
        if (parentNode instanceof BodyDeclaration) {
            modifiers = ((BodyDeclaration) parentNode).modifiers();
        } else if (parentNode instanceof SingleVariableDeclaration) {
            modifiers = ((SingleVariableDeclaration) parentNode).modifiers();
        } else {
            throw new IllegalStateException("Cannot handle annotations attached to " + parentNode);
        }

        int annotationIndex = modifiers.indexOf(annotation);
        if (annotationIndex >= 0) {
            modifiers.set(annotationIndex, newNode);
        }
    }

    private void convertTo(final AnnotationType type) {
        if (isMarker() && type != AnnotationType.MARKER || isSingleValue() && type != AnnotationType.SINGLE
                || isNormal() && type != AnnotationType.NORMAL) {
            String value = this.getLiteralValue();
            AnnotationImpl<O, T> newAnnotation = new AnnotationImpl<>(parent, type);
            if (getOrigin().getImport(getQualifiedName()) != null) {
                newAnnotation.setName(getName());
            } else {
                newAnnotation.setName(getQualifiedName());
            }
            replace(annotation, newAnnotation.annotation);
            annotation = newAnnotation.annotation;

            if (AnnotationType.MARKER != type && (value != null)) {
                setLiteralValue(value);
            }
        }
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(annotation);
    }

    @Override
    public boolean equals(final Object obj) {
        if (!(obj instanceof AnnotationImpl<?, ?>)) {
            return false;
        }

        AnnotationImpl<?, ?> other = (AnnotationImpl<?, ?>) obj;
        return annotation.equals(other.annotation);
    }

    @Override
    public AnnotationSource<O> setAnnotationValue() {
        if (isMarker()) {
            convertTo(AnnotationType.SINGLE);
        }

        if (isSingleValue()) {
            final AnnotationSource<O> result = new Nested(this);
            ((SingleMemberAnnotation) annotation).setValue((Expression) result.getInternal());
            return result;
        }
        return setAnnotationValue(DEFAULT_VALUE);
    }

    @Override
    public AnnotationSource<O> setAnnotationValue(String name) {
        if (!isNormal() && DEFAULT_VALUE.equals(name)) {
            return setAnnotationValue();
        }
        if (!isNormal()) {
            convertTo(AnnotationType.NORMAL);
        }
        AnnotationSource<O> result = new Nested(this);

        String stub = "@" + getName() + "(" + name + "= 0 ) public class Stub { }";
        JavaClass<?> temp = Roaster.parse(JavaClass.class, stub);

        NormalAnnotation anno = (NormalAnnotation) temp.getAnnotations().get(0).getInternal();
        MemberValuePair pair = (MemberValuePair) anno.values().get(0);

        @SuppressWarnings("unchecked")
        List<MemberValuePair> values = ((NormalAnnotation) annotation).values();
        ListIterator<MemberValuePair> iter = values.listIterator();
        while (iter.hasNext()) {
            if (iter.next().getName().getIdentifier().equals(name)) {
                iter.remove();
                break;
            }
        }
        MemberValuePair mvpCopy = (MemberValuePair) ASTNode.copySubtree(annotation.getAST(), pair);
        mvpCopy.setValue((Expression) result.getInternal());
        iter.add(mvpCopy);

        return result;
    }

    @Override
    public AnnotationSource<O> addAnnotationValue() {
        if (isNormal()) {
            return addAnnotationValue(DEFAULT_VALUE);
        }
        if (isMarker()) {
            convertTo(AnnotationType.SINGLE);
        }
        Expression expr = ((SingleMemberAnnotation) annotation).getValue();
        if (expr instanceof Annotation) {
            // wrap a single annotation value:
            ArrayInitializer arrayInit = ast.newArrayInitializer();
            {
                @SuppressWarnings({ "unused", "unchecked" })
                boolean junk = arrayInit.expressions().add(ASTNode.copySubtree(ast, expr));
            }
            ((SingleMemberAnnotation) annotation).setValue(arrayInit);
            expr = arrayInit;
        }
        if (expr instanceof ArrayInitializer) {
            // append to an annotation array:
            final Annotation arrayElement = createAnnotation(parent, AnnotationType.MARKER);
            if (((ArrayInitializer) expr).expressions().isEmpty()) {
                ((SingleMemberAnnotation) annotation).setValue(arrayElement);
            } else {
                @SuppressWarnings({ "unchecked", "unused" })
                boolean junk = ((ArrayInitializer) expr).expressions().add(arrayElement);
            }
            return new Nested(this, arrayElement);
        }
        // overwrite with a single annotation value:
        return setAnnotationValue();
    }

    @Override
    public AnnotationSource<O> addAnnotationValue(String name) {
        if (!isNormal()) {
            if (DEFAULT_VALUE.equals(name)) {
                return addAnnotationValue();
            }
            convertTo(AnnotationType.NORMAL);
        }
        MemberValuePair memberValuePair = null;

        for (Object value : ((NormalAnnotation) annotation).values()) {
            if (value instanceof MemberValuePair
                    && Objects.equals(name, ((MemberValuePair) value).getName().getIdentifier())) {
                memberValuePair = (MemberValuePair) value;
                break;
            }
        }
        if (memberValuePair != null) {
            Expression expr = memberValuePair.getValue();
            if (expr instanceof Annotation) {
                // wrap a single annotation value:
                ArrayInitializer arrayInit = ast.newArrayInitializer();
                {
                    @SuppressWarnings({ "unchecked", "unused" })
                    boolean junk = arrayInit.expressions().add(ASTNode.copySubtree(ast, expr));
                }
                memberValuePair.setValue(arrayInit);
                expr = arrayInit;
            }
            if (expr instanceof ArrayInitializer) {
                // append to an annotation array:
                final Annotation arrayElement = createAnnotation(parent, AnnotationType.MARKER);
                if (((ArrayInitializer) expr).expressions().isEmpty()) {
                    memberValuePair.setValue(arrayElement);
                } else {
                    @SuppressWarnings({ "unchecked", "unused" })
                    boolean junk = ((ArrayInitializer) expr).expressions().add(arrayElement);
                }
                return new Nested(this, arrayElement);
            }
        }
        // overwrite with a single annotation value:
        return setAnnotationValue(name);
    }

    @Override
    public AnnotationSource<O> addAnnotationValue(Class<? extends java.lang.annotation.Annotation> type) {
        String typeToUse = getOrigin().addImport(type) != null ? type.getCanonicalName() : type.getSimpleName();
        return addAnnotationValue().setName(typeToUse);
    }

    @Override
    public AnnotationSource<O> addAnnotationValue(String name,
            Class<? extends java.lang.annotation.Annotation> type) {
        String typeToUse = getOrigin().addImport(type) != null ? type.getCanonicalName() : type.getSimpleName();
        return addAnnotationValue(name).setName(typeToUse);
    }

    @Override
    public AnnotationSource<O> removeAnnotationValue(org.jboss.forge.roaster.model.Annotation<O> element) {
        requireNonNull(element, "Cannot remove null element");

        if (isSingleValue()) {
            if (element.getInternal().equals(((SingleMemberAnnotation) annotation).getValue())) {
                convertTo(AnnotationType.MARKER);
            } else if (((SingleMemberAnnotation) annotation).getValue() instanceof ArrayInitializer) {
                final ArrayInitializer arrayInit = (ArrayInitializer) ((SingleMemberAnnotation) annotation)
                        .getValue();
                if (arrayInit.expressions().remove(element.getInternal())) {
                    if (arrayInit.expressions().isEmpty()) {
                        convertTo(AnnotationType.MARKER);
                    } else if (arrayInit.expressions().size() == 1) {
                        ((SingleMemberAnnotation) annotation).setValue(
                                (Expression) ASTNode.copySubtree(ast, (ASTNode) arrayInit.expressions().get(0)));
                    }
                }
            }
            return this;
        }
        return removeAnnotationValue(DEFAULT_VALUE, element);
    }

    @Override
    public AnnotationSource<O> removeAnnotationValue(String name,
            org.jboss.forge.roaster.model.Annotation<O> element) {
        requireNonNull(element, "Cannot remove null element");

        if (isSingleValue() && Objects.equals(name, DEFAULT_VALUE)) {
            return removeAnnotationValue(element);
        }
        if (isNormal()) {
            final Set<String> identifiers = new HashSet<>();
            for (@SuppressWarnings("unchecked")
            Iterator<Object> values = ((NormalAnnotation) annotation).values().iterator(); values.hasNext();) {
                final Object value = values.next();
                if (value instanceof MemberValuePair) {
                    final String identifier = ((MemberValuePair) value).getName().getIdentifier();
                    identifiers.add(identifier);
                    if (Objects.equals(name, identifier)) {
                        Expression expr = ((MemberValuePair) value).getValue();
                        if (element.getInternal().equals(expr)) {
                            // remove entire annotation element for inlined single-element array:
                            values.remove();
                            identifiers.remove(identifier);
                            continue;
                        }
                        if (expr instanceof ArrayInitializer) {
                            final ArrayInitializer arrayInit = (ArrayInitializer) expr;

                            // remove element:
                            arrayInit.expressions().remove(element.getInternal());

                            if (arrayInit.expressions().isEmpty()) {
                                // remove empty array:
                                values.remove();
                                identifiers.remove(identifier);
                            } else if (arrayInit.expressions().size() == 1) {
                                // promote single-element array:
                                ((MemberValuePair) value).setValue((Expression) ASTNode.copySubtree(ast,
                                        (ASTNode) arrayInit.expressions().get(0)));
                            }
                        }
                    }
                }
            }
            // finally, reduce to simplest equivalent annotation type:
            if (identifiers.isEmpty()) {
                convertTo(AnnotationType.MARKER);
            } else if (identifiers.equals(Collections.singleton(DEFAULT_VALUE))) {
                convertTo(AnnotationType.SINGLE);
            }
        }
        return this;
    }

    @Override
    public AnnotationSource<O> getAnnotationValue() {
        if (isSingleValue()) {
            SingleMemberAnnotation single = (SingleMemberAnnotation) annotation;
            Expression value = single.getValue();
            if (value instanceof Annotation) {
                return new Nested(this, value);
            }
            if (value instanceof ArrayInitializer && ((ArrayInitializer) value).expressions().size() == 1) {
                value = (Expression) ((ArrayInitializer) value).expressions().get(0);
                if (value instanceof Annotation) {
                    return new Nested(this, value);
                }
            }
        }
        if (isNormal()) {
            return getAnnotationValue(DEFAULT_VALUE);
        }
        return null;
    }

    @Override
    public AnnotationSource<O> getAnnotationValue(String name) {
        if (isNormal()) {
            NormalAnnotation normal = (NormalAnnotation) annotation;
            @SuppressWarnings("unchecked")
            List<MemberValuePair> values = normal.values();
            for (MemberValuePair memberValuePair : values) {
                if (Objects.equals(name, memberValuePair.getName().getIdentifier())) {
                    Expression value = memberValuePair.getValue();
                    if (value instanceof Annotation) {
                        return new Nested(this, value);
                    }
                    if (value instanceof ArrayInitializer && ((ArrayInitializer) value).expressions().size() == 1) {
                        value = (Expression) ((ArrayInitializer) value).expressions().get(0);
                        if (value instanceof Annotation) {
                            return new Nested(this, value);
                        }
                    }
                }
            }
        }
        if (isSingleValue() && DEFAULT_VALUE.equals(name)) {
            return getAnnotationValue();
        }
        return null;
    }

    @Override
    public AnnotationSource<O>[] getAnnotationArrayValue() {
        return getAnnotationArrayValue(DEFAULT_VALUE);
    }

    @Override
    @SuppressWarnings("unchecked")
    public AnnotationSource<O>[] getAnnotationArrayValue(String name) {
        final Expression expr = getElementValueExpression(name);
        if (expr instanceof ArrayInitializer) {
            final List<AnnotationSource<O>> results = new ArrayList<>();
            final List<Expression> arrayElements = ((ArrayInitializer) expr).expressions();
            for (Expression arrayElement : arrayElements) {
                results.add(new Nested(this, arrayElement));
            }
            return results.toArray(new AnnotationSource[results.size()]);
        }
        final AnnotationSource<O> annotationValue = getAnnotationValue(name);
        if (annotationValue != null) {
            return new AnnotationSource[] { annotationValue };
        }
        return null;
    }

    @Override
    public <E extends Enum<E>> E[] getEnumArrayValue(Class<E> type) {
        return getEnumArrayValue(type, DEFAULT_VALUE);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E extends Enum<E>> E[] getEnumArrayValue(Class<E> type, String name) {
        final Expression expr = getElementValueExpression(name);
        if (expr instanceof ArrayInitializer) {
            final List<E> results = new ArrayList<>();
            final List<Expression> arrayElements = ((ArrayInitializer) expr).expressions();
            for (Expression arrayElement : arrayElements) {
                results.add(convertLiteralToEnum(type, arrayElement.toString()));
            }
            return results.toArray((E[]) Array.newInstance(type, results.size()));
        } else if (expr != null) {
            final E instance = convertLiteralToEnum(type, expr.toString());
            if (type.isInstance(instance)) {
                final E[] result = (E[]) Array.newInstance(type, 1);
                result[0] = instance;
                return result;
            }
        }
        return null;
    }

    @Override
    public Class<?> getClassValue() {
        return getClassValue(DEFAULT_VALUE);
    }

    @Override
    public Class<?> getClassValue(String name) {
        final TypeLiteral typeLiteral = getElementValueExpression(name);
        return resolveTypeLiteral(typeLiteral);
    }

    @Override
    public Class<?>[] getClassArrayValue() {
        return getClassArrayValue(DEFAULT_VALUE);
    }

    @Override
    public Class<?>[] getClassArrayValue(String name) {
        final Expression expr = getElementValueExpression(name);
        if (expr instanceof ArrayInitializer) {
            final List<Class<?>> result = new ArrayList<>();
            @SuppressWarnings("unchecked")
            final List<Expression> arrayElements = ((ArrayInitializer) expr).expressions();
            for (Expression expression : arrayElements) {
                final Class<?> type = resolveTypeLiteral((TypeLiteral) expression);
                result.add(type);
            }
            return result.toArray(new Class[result.size()]);
        } else if (expr instanceof TypeLiteral) {
            return new Class[] { resolveTypeLiteral((TypeLiteral) expr) };
        }
        return null;
    }

    @Override
    public String[] getStringArrayValue() {
        return getStringArrayValue(DEFAULT_VALUE);
    }

    @Override
    public String[] getStringArrayValue(String name) {
        final List<String> result = new ArrayList<>();
        String literalValue = getLiteralValue(name);

        if (literalValue.startsWith("{") && literalValue.endsWith("}")) {
            literalValue = literalValue.substring(1, literalValue.length() - 1);
        }
        if (!StringUtils.isEmpty(literalValue)) {
            for (String value : literalValue.split(",")) {
                result.add(Strings.unquote(value));
            }
        }
        return result.toArray(new String[result.size()]);
    }

    @Override
    public AnnotationSource<O> setClassValue(String name, Class<?> value) {
        getOrigin().addImport(value);
        return setLiteralValue(name, Types.toResolvedType(value.getCanonicalName(), getOrigin()) + ".class");
    }

    @Override
    public AnnotationSource<O> setClassValue(Class<?> value) {
        return setClassValue(DEFAULT_VALUE, value);
    }

    @Override
    public AnnotationSource<O> setClassArrayValue(Class<?>... values) {
        return setClassArrayValue(DEFAULT_VALUE, values);
    }

    @Override
    public AnnotationSource<O> setStringArrayValue(String[] values) {
        return setStringArrayValue(DEFAULT_VALUE, values);
    }

    @Override
    public AnnotationSource<O> setStringArrayValue(String name, String[] values) {
        final List<String> literals = new ArrayList<>();

        for (String value : requireNonNull(values)) {
            literals.add(Strings.enquote(requireNonNull(value)));
        }
        return setArrayLiteralValue(name, literals);
    }

    @Override
    public AnnotationSource<O> setClassArrayValue(String name, Class<?>... values) {
        final List<String> literals = new ArrayList<>();

        for (Class<?> value : requireNonNull(values)) {
            getOrigin().addImport(value);
            literals.add(Types.toResolvedType(value.getCanonicalName(), getOrigin()) + ".class");
        }
        return setArrayLiteralValue(name, literals);
    }

    private AnnotationSource<O> setArrayLiteralValue(String name, final List<String> literals) {
        String value = literals.size() == 1 ? literals.get(0) : String.format("{%s}", String.join(",", literals));
        return setLiteralValue(name, value);
    }

    @SuppressWarnings("unchecked")
    private <E extends Expression> E getElementValueExpression(String name) {
        if (isSingleValue() && DEFAULT_VALUE.equals(name)) {
            return (E) ((SingleMemberAnnotation) annotation).getValue();
        }
        if (isNormal()) {
            for (Object annotationValue : ((NormalAnnotation) annotation).values()) {
                if (annotationValue instanceof MemberValuePair) {
                    MemberValuePair pair = (MemberValuePair) annotationValue;
                    if (pair.getName().getFullyQualifiedName().equals(name)) {
                        return (E) pair.getValue();
                    }
                }
            }
        }
        return null;
    }

    private String resolveTypeLiteralName(TypeLiteral typeLiteral) {
        final Type<O> type = new TypeImpl<>(getOrigin(), typeLiteral.getType());
        if (Types.isPrimitive(type.getName())) {
            return type.getName();
        }
        return type.getQualifiedName();
    }

    private Class<?> resolveTypeLiteral(TypeLiteral typeLiteral) {
        final Type<O> type = new TypeImpl<>(getOrigin(), typeLiteral.getType());
        if (Types.isPrimitive(type.getName())) {
            return Types.toPrimitive(type.getName());
        }

        try {
            return Class.forName(type.getQualifiedName());
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    @Override
    public boolean isTypeElementDefined(String name) {
        return getValues().stream().map(ValuePair::getName).anyMatch(isEqual(name));
    }
}