/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.apache.bval.jsr.metadata;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.validation.ConstraintDeclarationException;
import javax.validation.ConstraintTarget;
import javax.validation.Payload;
import javax.validation.ValidationException;
import javax.validation.groups.Default;
import javax.xml.bind.JAXBElement;

import org.apache.bval.jsr.ApacheValidatorFactory;
import org.apache.bval.jsr.ConstraintAnnotationAttributes;
import org.apache.bval.jsr.groups.GroupConversion;
import org.apache.bval.jsr.util.AnnotationProxyBuilder;
import org.apache.bval.jsr.util.ToUnmodifiable;
import org.apache.bval.jsr.xml.AnnotationType;
import org.apache.bval.jsr.xml.BeanType;
import org.apache.bval.jsr.xml.ClassType;
import org.apache.bval.jsr.xml.ConstraintMappingsType;
import org.apache.bval.jsr.xml.ConstraintType;
import org.apache.bval.jsr.xml.ConstructorType;
import org.apache.bval.jsr.xml.ContainerElementTypeType;
import org.apache.bval.jsr.xml.CrossParameterType;
import org.apache.bval.jsr.xml.ElementType;
import org.apache.bval.jsr.xml.FieldType;
import org.apache.bval.jsr.xml.GetterType;
import org.apache.bval.jsr.xml.GroupConversionType;
import org.apache.bval.jsr.xml.GroupSequenceType;
import org.apache.bval.jsr.xml.GroupsType;
import org.apache.bval.jsr.xml.MappingValidator;
import org.apache.bval.jsr.xml.MethodType;
import org.apache.bval.jsr.xml.ParameterType;
import org.apache.bval.jsr.xml.PayloadType;
import org.apache.bval.jsr.xml.ReturnValueType;
import org.apache.bval.util.Exceptions;
import org.apache.bval.util.Lazy;
import org.apache.bval.util.ObjectUtils;
import org.apache.bval.util.StringUtils;
import org.apache.bval.util.Validate;
import org.apache.bval.util.reflection.Reflection;
import org.apache.commons.weaver.privilizer.Privilizing;
import org.apache.commons.weaver.privilizer.Privilizing.CallTo;

@Privilizing(@CallTo(Reflection.class))
public class XmlBuilder {
    //@formatter:off
    public enum Version {
        v10("1.0"), v11("1.1"), v20("2.0"), v30("3.0");
        //@formatter:on

        static Version of(ConstraintMappingsType constraintMappings) {
            Validate.notNull(constraintMappings);
            String version = constraintMappings.getVersion();
            if (StringUtils.isBlank(version)) {
                return v10;
            }
            version = version.trim();
            for (Version candidate : values()) {
                if (candidate.id.equals(version)) {
                    return candidate;
                }
            }
            throw new ValidationException("Unknown schema version: " + version);
        }

        private final String id;

        private Version(String number) {
            this.id = number;
        }

        public String getId() {
            return id;
        }
    }

    private class ForBean<T> implements MetadataBuilder.ForBean<T> {

        private final BeanType descriptor;

        ForBean(BeanType descriptor) {
            super();
            this.descriptor = Validate.notNull(descriptor, "descriptor");
        }

        Class<?> getBeanClass() {
            return resolveClass(descriptor.getClazz());
        }

        @Override
        public MetadataBuilder.ForClass<T> getClass(Meta<Class<T>> meta) {
            final ClassType classType = descriptor.getClassType();
            return classType == null ? EmptyBuilder.instance().<T> forBean().getClass(meta)
                : new XmlBuilder.ForClass<T>(classType);
        }

        @Override
        public Map<String, MetadataBuilder.ForContainer<Field>> getFields(Meta<Class<T>> meta) {
            return descriptor.getField().stream()
                .collect(ToUnmodifiable.map(FieldType::getName, XmlBuilder.ForField::new));
        }

        @Override
        public Map<String, MetadataBuilder.ForContainer<Method>> getGetters(Meta<Class<T>> meta) {
            return descriptor.getGetter().stream()
                .collect(ToUnmodifiable.map(GetterType::getName, XmlBuilder.ForGetter::new));
        }

        @Override
        public Map<Signature, MetadataBuilder.ForExecutable<Constructor<? extends T>>> getConstructors(Meta<Class<T>> meta) {
            if (!atLeast(Version.v11)) {
                return Collections.emptyMap();
            }
            final Function<ConstructorType, Class<?>[]> params = ct -> ct.getParameter().stream()
                .map(ParameterType::getType).map(XmlBuilder.this::resolveClass).toArray(Class[]::new);

            final Function<ConstructorType, Signature> signature =
                ct -> new Signature(meta.getHost().getName(), params.apply(ct));

            return descriptor.getConstructor().stream()
                .collect(Collectors.toMap(signature, XmlBuilder.ForConstructor::new));
        }

        @Override
        public Map<Signature, MetadataBuilder.ForExecutable<Method>> getMethods(Meta<Class<T>> meta) {
            if (!atLeast(Version.v11)) {
                return Collections.emptyMap();
            }
            final Function<MethodType, Class<?>[]> params = mt -> mt.getParameter().stream().map(ParameterType::getType)
                .map(XmlBuilder.this::resolveClass).toArray(Class[]::new);

            final Function<MethodType, Signature> signature = mt -> new Signature(mt.getName(), params.apply(mt));

            return descriptor.getMethod().stream().collect(Collectors.toMap(signature, XmlBuilder.ForMethod::new));
        }

        @Override
        public final AnnotationBehavior getAnnotationBehavior() {
            return descriptor.getIgnoreAnnotations() ? AnnotationBehavior.EXCLUDE : AnnotationBehavior.INCLUDE;
        }
    }

    private class NonRootLevel<SELF extends NonRootLevel<SELF, D>, D> implements HasAnnotationBehavior {
        protected final D descriptor;
        private Lazy<Boolean> getIgnoreAnnotations;

        public NonRootLevel(D descriptor) {
            super();
            this.descriptor = Validate.notNull(descriptor, "descriptor");
        }

        @Override
        public final AnnotationBehavior getAnnotationBehavior() {
            return Optional.ofNullable(getIgnoreAnnotations).map(Lazy::get)
                .map(b -> b.booleanValue() ? AnnotationBehavior.EXCLUDE : AnnotationBehavior.INCLUDE)
                .orElse(AnnotationBehavior.ABSTAIN);
        }

        @SuppressWarnings("unchecked")
        final SELF withGetIgnoreAnnotations(Function<D, Boolean> getIgnoreAnnotations) {
            Validate.notNull(getIgnoreAnnotations);
            this.getIgnoreAnnotations = new Lazy<>(() -> getIgnoreAnnotations.apply(descriptor));
            return (SELF) this;
        }
    }

    private class ForElement<SELF extends XmlBuilder.ForElement<SELF, E, D>, E extends AnnotatedElement, D>
        extends NonRootLevel<SELF, D> implements MetadataBuilder.ForElement<E> {

        private Lazy<Annotation[]> getDeclaredConstraints;

        ForElement(D descriptor) {
            super(descriptor);
        }

        @Override
        public final Annotation[] getDeclaredConstraints(Meta<E> meta) {
            return lazy(getDeclaredConstraints, "getDeclaredConstraints");
        }

        final SELF withGetConstraintTypes(Function<D, List<ConstraintType>> getConstraintTypes) {
            return withGetDeclaredConstraints(getConstraintTypes
                .andThen(l -> l.stream().map(XmlBuilder.this::createConstraint).toArray(Annotation[]::new)));
        }

        @SuppressWarnings("unchecked")
        final SELF withGetDeclaredConstraints(Function<D, Annotation[]> getDeclaredConstraints) {
            this.getDeclaredConstraints = new Lazy<>(() -> getDeclaredConstraints.apply(descriptor));
            return (SELF) this;
        }
    }

    private class ForClass<T> extends ForElement<ForClass<T>, Class<T>, ClassType> implements MetadataBuilder.ForClass<T> {

        ForClass(ClassType descriptor) {
            super(descriptor);
            this.withGetConstraintTypes(ClassType::getConstraint)
                .withGetIgnoreAnnotations(ClassType::getIgnoreAnnotations);
        }

        @Override
        public List<Class<?>> getGroupSequence(Meta<Class<T>> meta) {
            final GroupSequenceType groupSequence = descriptor.getGroupSequence();
            return groupSequence == null ? null
                : groupSequence.getValue().stream().map(XmlBuilder.this::resolveClass).collect(ToUnmodifiable.list());
        }
    }

    private class ForContainer<SELF extends XmlBuilder.ForContainer<SELF, E, D>, E extends AnnotatedElement, D>
        extends XmlBuilder.ForElement<SELF, E, D> implements MetadataBuilder.ForContainer<E> {

        private Lazy<Boolean> isCascade;
        private Lazy<Set<GroupConversion>> getGroupConversions;
        private Lazy<List<ContainerElementTypeType>> getContainerElementTypes;

        ForContainer(D descriptor) {
            super(descriptor);
        }

        @Override
        public boolean isCascade(Meta<E> meta) {
            return Boolean.TRUE.equals(lazy(isCascade, "isCascade"));
        }

        @Override
        public Set<GroupConversion> getGroupConversions(Meta<E> meta) {
            return lazy(getGroupConversions, "getGroupConversions");
        }

        @Override
        public Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> getContainerElementTypes(
            Meta<E> meta) {
            if (!atLeast(Version.v20)) {
                return Collections.emptyMap();
            }
            final List<ContainerElementTypeType> elements = lazy(getContainerElementTypes, "getContainerElementTypes");
            final AnnotatedType annotatedType = meta.getAnnotatedType();
            final E host = meta.getHost();

            if (annotatedType instanceof AnnotatedParameterizedType) {
                final AnnotatedType[] actualTypeArguments =
                    ((AnnotatedParameterizedType) annotatedType).getAnnotatedActualTypeArguments();

                return elements.stream().collect(ToUnmodifiable.map(cet -> {
                    Integer typeArgumentIndex = cet.getTypeArgumentIndex();
                    if (typeArgumentIndex == null) {
                        Exceptions.raiseIf(actualTypeArguments.length > 1, ValidationException::new,
                            "Missing required type argument index for %s", host);
                        typeArgumentIndex = Integer.valueOf(0);
                    }
                    return new ContainerElementKey(annotatedType, typeArgumentIndex);
                }, XmlBuilder.ForContainerElementType::new));
            }
            if (!elements.isEmpty()) {
                Exceptions.raise(ValidationException::new, "Illegally specified %d container element type(s) for %s",
                    elements.size(), host);
            }
            return Collections.emptyMap();
        }

        @SuppressWarnings("unchecked")
        SELF withGetValid(Function<D, String> getValid) {
            Validate.notNull(getValid);
            this.isCascade = new Lazy<>(() -> getValid.apply(descriptor) != null);
            return (SELF) this;
        }

        @SuppressWarnings("unchecked")
        SELF withGetGroupConversions(Function<D, List<GroupConversionType>> getGroupConversions) {
            Validate.notNull(getGroupConversions);

            this.getGroupConversions = new Lazy<>(() -> {
                return getGroupConversions.apply(descriptor).stream().map(gc -> {
                    final String from = gc.getFrom();
                    final Class<?> source = from == null ? Default.class : resolveClass(from);
                    final Class<?> target = resolveClass(gc.getTo());
                    return GroupConversion.from(source).to(target);
                }).collect(ToUnmodifiable.set());
            });
            return (SELF) this;
        }

        @SuppressWarnings("unchecked")
        SELF withGetContainerElementTypes(Function<D, List<ContainerElementTypeType>> getContainerElementTypes) {
            Validate.notNull(getContainerElementTypes);
            this.getContainerElementTypes = new Lazy<>(() -> getContainerElementTypes.apply(descriptor));
            return (SELF) this;
        }
    }

    private class ForContainerElementType
        extends ForContainer<ForContainerElementType, AnnotatedType, ContainerElementTypeType> {

        ForContainerElementType(ContainerElementTypeType descriptor) {
            super(descriptor);
            this.withGetConstraintTypes(ContainerElementTypeType::getConstraint)
                .withGetValid(ContainerElementTypeType::getValid)
                .withGetGroupConversions(ContainerElementTypeType::getConvertGroup)
                .withGetContainerElementTypes(ContainerElementTypeType::getContainerElementType);
        }
    }

    private class ForField extends XmlBuilder.ForContainer<ForField, Field, FieldType> {

        ForField(FieldType descriptor) {
            super(descriptor);
            this.withGetIgnoreAnnotations(FieldType::getIgnoreAnnotations)
                .withGetConstraintTypes(FieldType::getConstraint).withGetValid(FieldType::getValid)
                .withGetGroupConversions(FieldType::getConvertGroup)
                .withGetContainerElementTypes(FieldType::getContainerElementType);
        }
    }

    private class ForGetter extends XmlBuilder.ForContainer<ForGetter, Method, GetterType> {

        ForGetter(GetterType descriptor) {
            super(descriptor);
            this.withGetIgnoreAnnotations(GetterType::getIgnoreAnnotations)
                .withGetConstraintTypes(GetterType::getConstraint).withGetValid(GetterType::getValid)
                .withGetGroupConversions(GetterType::getConvertGroup)
                .withGetContainerElementTypes(GetterType::getContainerElementType);
        }
    }

    private abstract class ForExecutable<SELF extends ForExecutable<SELF, E, D>, E extends Executable, D>
        extends NonRootLevel<SELF, D> implements MetadataBuilder.ForExecutable<E> {

        Lazy<ReturnValueType> getReturnValue;
        Lazy<CrossParameterType> getCrossParameter;
        Lazy<List<ParameterType>> getParameters;

        ForExecutable(D descriptor) {
            super(descriptor);
        }

        @Override
        public MetadataBuilder.ForElement<E> getCrossParameter(Meta<E> meta) {
            final CrossParameterType cp = lazy(getCrossParameter, "getCrossParameter");
            if (cp == null) {
                return EmptyBuilder.instance().<E> forExecutable().getCrossParameter(meta);
            }
            return new XmlBuilder.ForCrossParameter<>(cp);
        }

        @Override
        public MetadataBuilder.ForContainer<E> getReturnValue(Meta<E> meta) {
            final ReturnValueType rv = lazy(getReturnValue, "getReturnValue");
            if (rv == null) {
                return EmptyBuilder.instance().<E> forExecutable().getReturnValue(meta);
            }
            return new XmlBuilder.ForReturnValue<>(rv);
        }

        @Override
        public List<MetadataBuilder.ForContainer<Parameter>> getParameters(Meta<E> meta) {
            return lazy(getParameters, "getParameters").stream().map(XmlBuilder.ForParameter::new)
                .collect(Collectors.toList());
        }

        @SuppressWarnings("unchecked")
        SELF withGetReturnValue(Function<D, ReturnValueType> getReturnValue) {
            Validate.notNull(getReturnValue);
            this.getReturnValue = new Lazy<>(() -> getReturnValue.apply(descriptor));
            return (SELF) this;
        }

        @SuppressWarnings("unchecked")
        SELF withGetCrossParameter(Function<D, CrossParameterType> getCrossParameter) {
            Validate.notNull(getCrossParameter);
            this.getCrossParameter = new Lazy<>(() -> getCrossParameter.apply(descriptor));
            return (SELF) this;
        }

        @SuppressWarnings("unchecked")
        SELF withGetParameters(Function<D, List<ParameterType>> getParameters) {
            Validate.notNull(getParameters);
            this.getParameters = new Lazy<>(() -> getParameters.apply(descriptor));
            return (SELF) this;
        }
    }

    private class ForConstructor<T> extends ForExecutable<ForConstructor<T>, Constructor<? extends T>, ConstructorType> {

        ForConstructor(ConstructorType descriptor) {
            super(descriptor);
            this.withGetIgnoreAnnotations(ConstructorType::getIgnoreAnnotations)
                .withGetReturnValue(ConstructorType::getReturnValue)
                .withGetCrossParameter(ConstructorType::getCrossParameter)
                .withGetParameters(ConstructorType::getParameter);
        }
    }

    private class ForMethod extends ForExecutable<ForMethod, Method, MethodType> {

        ForMethod(MethodType descriptor) {
            super(descriptor);
            this.withGetIgnoreAnnotations(MethodType::getIgnoreAnnotations)
                .withGetReturnValue(MethodType::getReturnValue).withGetCrossParameter(MethodType::getCrossParameter)
                .withGetParameters(MethodType::getParameter);
        }
    }

    private class ForParameter extends ForContainer<ForParameter, Parameter, ParameterType> {

        ForParameter(ParameterType descriptor) {
            super(descriptor);
            this.withGetIgnoreAnnotations(ParameterType::getIgnoreAnnotations)
                .withGetConstraintTypes(ParameterType::getConstraint).withGetValid(ParameterType::getValid)
                .withGetGroupConversions(ParameterType::getConvertGroup)
                .withGetContainerElementTypes(ParameterType::getContainerElementType);
        }
    }

    private class ForCrossParameter<E extends Executable>
        extends ForElement<ForCrossParameter<E>, E, CrossParameterType> {

        ForCrossParameter(CrossParameterType descriptor) {
            super(descriptor);
            this.withGetIgnoreAnnotations(CrossParameterType::getIgnoreAnnotations)
                .withGetDeclaredConstraints(d -> d.getConstraint().stream()
                    .map(ct -> createConstraint(ct, ConstraintTarget.PARAMETERS)).toArray(Annotation[]::new));
        }
    }

    private class ForReturnValue<E extends Executable> extends ForContainer<ForReturnValue<E>, E, ReturnValueType> {

        ForReturnValue(ReturnValueType descriptor) {
            super(descriptor);
            this.withGetDeclaredConstraints(d -> d.getConstraint().stream()
                .map(ct -> createConstraint(ct, ConstraintTarget.RETURN_VALUE)).toArray(Annotation[]::new))
                .withGetIgnoreAnnotations(ReturnValueType::getIgnoreAnnotations).withGetValid(ReturnValueType::getValid)
                .withGetGroupConversions(ReturnValueType::getConvertGroup)
                .withGetContainerElementTypes(ReturnValueType::getContainerElementType);
        }
    }

    private static final <T> T lazy(Lazy<T> lazy, String name) {
        Validate.validState(lazy != null, "%s not set", name);
        return lazy.get();
    }

    private final ApacheValidatorFactory validatorFactory;
    private final ConstraintMappingsType constraintMappings;
    private final Version version;

    public XmlBuilder(ApacheValidatorFactory validatorFactory, ConstraintMappingsType constraintMappings) {
        super();
        this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory");
        this.constraintMappings = Validate.notNull(constraintMappings, "constraintMappings");
        this.version = Version.of(constraintMappings);
        new MappingValidator(constraintMappings, this::resolveClass).validateMappings();
    }

    public Map<Class<?>, MetadataBuilder.ForBean<?>> forBeans() {
        return constraintMappings.getBean().stream().map(XmlBuilder.ForBean::new)
            .collect(ToUnmodifiable.map(XmlBuilder.ForBean::getBeanClass, Function.identity()));
    }

    public String getDefaultPackage() {
        return constraintMappings.getDefaultPackage();
    }

    boolean atLeast(Version v) {
        return version.compareTo(v) >= 0;
    }

    <T> Class<T> resolveClass(String className) {
        return loadClass(toQualifiedClassName(className));
    }

    private String toQualifiedClassName(String className) {
        if (isQualifiedClass(className)) {
            return className;
        }
        if (className.startsWith("[L") && className.endsWith(";")) {
            return "[L" + getDefaultPackage() + "." + className.substring(2);
        }
        return getDefaultPackage() + "." + className;
    }

    private boolean isQualifiedClass(String clazz) {
        return clazz.indexOf('.') >= 0;
    }

    @SuppressWarnings("unchecked")
    private <T> Class<T> loadClass(final String fqn) {
        ClassLoader loader = Reflection.loaderFromThreadOrClass(XmlBuilder.class);
        if (loader == null) {
            loader = getClass().getClassLoader();
        }
        try {
            return (Class<T>) Class.forName(fqn, true, loader);
        } catch (ClassNotFoundException ex) {
            throw Exceptions.create(ValidationException::new, ex, "Unable to load class: %d", fqn);
        }
    }

    private Class<?>[] loadClasses(Supplier<Stream<String>> classNames) {
        return streamClasses(classNames).toArray(Class[]::new);
    }

    private Stream<Class<?>> streamClasses(Supplier<Stream<String>> classNames) {
        return classNames.get().map(this::loadClass);
    }

    private <A extends Annotation, T> A createConstraint(final ConstraintType constraint) {
        return createConstraint(constraint, ConstraintTarget.IMPLICIT);
    }

    private <A extends Annotation, T> A createConstraint(final ConstraintType constraint, ConstraintTarget target) {
        final Class<A> annotationClass = this.<A> loadClass(toQualifiedClassName(constraint.getAnnotation()));
        final AnnotationProxyBuilder<A> annoBuilder =
            validatorFactory.getAnnotationsManager().buildProxyFor(annotationClass);

        if (constraint.getMessage() != null) {
            annoBuilder.setMessage(constraint.getMessage());
        }
        annoBuilder.setGroups(getGroups(constraint.getGroups()));
        annoBuilder.setPayload(getPayload(constraint.getPayload()));

        if (ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO.analyze(annotationClass).isValid()) {
            annoBuilder.setValidationAppliesTo(target);
        }
        for (final ElementType elementType : constraint.getElement()) {
            final String name = elementType.getName();
            final Class<?> returnType = getAnnotationParameterType(annotationClass, name);
            final Object elementValue = getElementValue(elementType, returnType);
            annoBuilder.setValue(name, elementValue);
        }
        return annoBuilder.createAnnotation();
    }

    private <A extends Annotation> Class<?> getAnnotationParameterType(final Class<A> annotationClass,
        final String name) {
        final Method m = Reflection.getPublicMethod(annotationClass, name);
        Exceptions.raiseIf(m == null, ValidationException::new,
            "Annotation of type %s does not contain a parameter %s.", annotationClass.getName(), name);
        return m.getReturnType();
    }

    private Object getElementValue(ElementType elementType, Class<?> returnType) {
        removeEmptyContentElements(elementType);

        final List<Serializable> content = elementType.getContent();
        final int sz = content.size();
        if (returnType.isArray()) {
            final Object result = Array.newInstance(returnType.getComponentType(), sz);
            for (int i = 0; i < sz; i++) {
                Array.set(result, i, getSingleValue(content.get(i), returnType.getComponentType()));
            }
            return result;
        }
        Exceptions.raiseIf(sz != 1, ValidationException::new,
            "Attempt to specify an array where single value is expected.");

        return getSingleValue(content.get(0), returnType);
    }

    private void removeEmptyContentElements(ElementType elementType) {
        for (Iterator<Serializable> iter = elementType.getContent().iterator(); iter.hasNext();) {
            final Serializable content = iter.next();
            if (content instanceof String && ((String) content).matches("[\\n ].*")) {
                iter.remove();
            }
        }
    }

    @SuppressWarnings("unchecked")
    private Object getSingleValue(Serializable serializable, Class<?> returnType) {
        if (serializable instanceof String) {
            return convertToResultType(returnType, (String) serializable);
        }
        if (serializable instanceof JAXBElement<?>) {
            final JAXBElement<?> elem = (JAXBElement<?>) serializable;
            if (String.class.equals(elem.getDeclaredType())) {
                return convertToResultType(returnType, (String) elem.getValue());
            }
            if (AnnotationType.class.equals(elem.getDeclaredType())) {
                AnnotationType annotationType = (AnnotationType) elem.getValue();
                try {
                    return createAnnotation(annotationType, (Class<? extends Annotation>) returnType);
                } catch (ClassCastException e) {
                    throw new ValidationException("Unexpected parameter value");
                }
            }
        }
        throw new ValidationException("Unexpected parameter value");
    }

    private Object convertToResultType(Class<?> returnType, String value) {
        /**
         * Class is represented by the fully qualified class name of the class. spec: Note that if the raw string is
         * unqualified, default package is taken into account.
         */
        if (String.class.equals(returnType)) {
            return value;
        }
        if (Class.class.equals(returnType)) {
            return resolveClass(value);
        }
        if (returnType.isEnum()) {
            try {
                @SuppressWarnings({ "rawtypes", "unchecked" })
                final Enum e = Enum.valueOf(returnType.asSubclass(Enum.class), value);
                return e;
            } catch (IllegalArgumentException e) {
                throw new ConstraintDeclarationException(e);
            }
        }
        try {
            if (Byte.class.equals(returnType) || byte.class.equals(returnType)) {
                // spec mandates it:
                return Byte.parseByte(value);
            }
            if (Short.class.equals(returnType) || short.class.equals(returnType)) {
                return Short.parseShort(value);
            }
            if (Integer.class.equals(returnType) || int.class.equals(returnType)) {
                return Integer.parseInt(value);
            }
            if (Long.class.equals(returnType) || long.class.equals(returnType)) {
                return Long.parseLong(value);
            }
            if (Float.class.equals(returnType) || float.class.equals(returnType)) {
                return Float.parseFloat(value);
            }
            if (Double.class.equals(returnType) || double.class.equals(returnType)) {
                return Double.parseDouble(value);
            }
            if (Boolean.class.equals(returnType) || boolean.class.equals(returnType)) {
                return Boolean.parseBoolean(value);
            }
        } catch (Exception e) {
            Exceptions.raise(ValidationException::new, e, "Unable to coerce value '%s' to %s", value, returnType);
        }
        if (Character.class.equals(returnType) || char.class.equals(returnType)) {
            Exceptions.raiseIf(value.length() > 1, ConstraintDeclarationException::new,
                "a char must have a length of 1");
            return value.charAt(0);
        }
        return Exceptions.raise(ValidationException::new, "Unknown annotation value type %s", returnType.getName());
    }

    private <A extends Annotation> Annotation createAnnotation(AnnotationType annotationType, Class<A> returnType) {
        final AnnotationProxyBuilder<A> metaAnnotation =
            validatorFactory.getAnnotationsManager().buildProxyFor(returnType);
        for (ElementType elementType : annotationType.getElement()) {
            final String name = elementType.getName();
            metaAnnotation.setValue(name, getElementValue(elementType, getAnnotationParameterType(returnType, name)));
        }
        return metaAnnotation.createAnnotation();
    }

    private Class<?>[] getGroups(GroupsType groupsType) {
        if (groupsType == null) {
            return ObjectUtils.EMPTY_CLASS_ARRAY;
        }
        return loadClasses(groupsType.getValue()::stream);
    }

    @SuppressWarnings("unchecked")
    private Class<? extends Payload>[] getPayload(PayloadType payloadType) {
        if (payloadType == null) {
            return (Class<? extends Payload>[]) ObjectUtils.EMPTY_CLASS_ARRAY;
        }
        return streamClasses(payloadType.getValue()::stream).peek(pc -> {
            Exceptions.raiseUnless(Payload.class.isAssignableFrom(pc), ConstraintDeclarationException::new,
                "Specified payload class %s does not implement %s", pc.getName(), Payload.class.getName());
        }).<Class<? extends Payload>> map(pc -> pc.asSubclass(Payload.class)).toArray(Class[]::new);
    }
}
