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

io.micronaut.validation.validator.DefaultConstraintDescriptor Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017-2020 original authors
 *
 * Licensed 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
 *
 * https://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 io.micronaut.validation.validator;

import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.util.CollectionUtils;
import jakarta.validation.ConstraintDeclarationException;
import jakarta.validation.ConstraintTarget;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.Payload;
import jakarta.validation.groups.Default;
import jakarta.validation.metadata.ConstraintDescriptor;
import jakarta.validation.metadata.ValidateUnwrappedValue;
import jakarta.validation.valueextraction.Unwrapping;

import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Default constraint descriptor implementation.
 *
 * @param  The constraint type
 * @author graemerocher
 * @since 1.2
 */
@Internal
class DefaultConstraintDescriptor implements ConstraintDescriptor {

    @NonNull
    private final Class type;
    @Nullable
    private final String message;
    @Nullable
    private final String defaultMessage;
    private final Set> groups;
    private final Set> payload;
    private final List>> validatedBy;

    private final ConstraintTarget validationAppliesTo;
    private final AnnotationValue annotationValue;
    private final AnnotationMetadata annotationMetadata;

    DefaultConstraintDescriptor(@NonNull Class constraintType,
                                @NonNull AnnotationValue annotationValue,
                                @NonNull AnnotationMetadata annotationMetadata) {
        this(constraintType,
            annotationValue.stringValue("message").orElse(null),
            annotationValue.getDefaultValues() == null ? null : (String) annotationValue.getDefaultValues().get("message"),
            Set.of(annotationValue.classValues("groups")),
            (Set) Set.of(annotationValue.classValues("payload")),
            (List) List.of(annotationValue.classValues(ValidationAnnotationUtil.CONSTRAINT_VALIDATED_BY)),
            annotationValue.enumValue("validationAppliesTo", ConstraintTarget.class).orElse(ConstraintTarget.IMPLICIT),
            annotationValue,
            annotationMetadata);
    }

    DefaultConstraintDescriptor(@NonNull Class type,
                                @Nullable String message,
                                @Nullable String defaultMessage,
                                @NonNull Set> groups,
                                @NonNull Set> payload,
                                @NonNull List>> validatedBy,
                                @NonNull ConstraintTarget validationAppliesTo,
                                @NonNull AnnotationValue annotationValue,
                                @NonNull AnnotationMetadata annotationMetadata) {
        this.type = type;
        this.message = message;
        this.defaultMessage = defaultMessage;
        this.groups = groups;
        this.payload = payload;
        this.validatedBy = validatedBy;
        this.validationAppliesTo = validationAppliesTo;
        this.annotationValue = annotationValue;
        this.annotationMetadata = annotationMetadata;
    }

    public AnnotationValue getAnnotationValue() {
        return annotationValue;
    }

    public AnnotationMetadata getAnnotationMetadata() {
        return annotationMetadata;
    }

    public Class getType() {
        return type;
    }

    @Override
    public T getAnnotation() {
        return annotationMetadata.synthesize(type);
    }

    @Override
    public String getMessageTemplate() {
        if (message != null) {
            return message;
        }
        if (defaultMessage != null) {
            return defaultMessage;
        }
        return "{" + type.getName() + ".message}";
    }

    @Override
    public Set> getGroups() {
        if (groups.isEmpty()) {
            return Set.of(Default.class);
        }
        return groups;
    }

    @Override
    public Set> getPayload() {
        return payload;
    }

    @Override
    public ConstraintTarget getValidationAppliesTo() {
        return validationAppliesTo;
    }

    @Override
    public List>> getConstraintValidatorClasses() {
        return validatedBy;
    }

    @Override
    public Map getAttributes() {
        final Map values = annotationValue.getValues();
        Map variables = CollectionUtils.newLinkedHashMap(values.size());
        for (Map.Entry entry : values.entrySet()) {
            variables.put(entry.getKey().toString(), entry.getValue());
        }
        if (annotationValue.getDefaultValues() != null) {
            final Map defaultValues = annotationValue.getDefaultValues();
            for (Map.Entry entry : defaultValues.entrySet()) {
                final String n = entry.getKey().toString();
                if (!variables.containsKey(n)) {
                    final Object v = entry.getValue();
                    if (v != null) {
                        variables.put(n, v);
                    }
                }
            }
        }
        return variables;
    }

    @Override
    public Set> getComposingConstraints() {
        return Collections.emptySet();
    }

    @Override
    public boolean isReportAsSingleViolation() {
        return false;
    }

    @Override
    public ValidateUnwrappedValue getValueUnwrapping() {
        boolean unwrap = payload.contains(Unwrapping.Unwrap.class);
        boolean skip = payload.contains(Unwrapping.Skip.class);
        if (unwrap && skip) {
            throw new ConstraintDeclarationException("Payload declared with both " + Unwrapping.Unwrap.class.getName() + " and " + Unwrapping.Skip.class);
        }
        if (unwrap) {
            return ValidateUnwrappedValue.UNWRAP;
        }
        if (skip) {
            return ValidateUnwrappedValue.SKIP;
        }
        return ValidateUnwrappedValue.DEFAULT;
    }

    @Override
    public  U unwrap(Class type) {
        throw new UnsupportedOperationException("Unwrapping unsupported");
    }
}