spring-bootautowiredhibernate-validator

@Autowired in ConstraintValidator inject Null


SpringBoot Version 2.7.13 Java 11

My Code


package com.chisw.contactservice.validation;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Component
public class PhoneNumbersValidAndUniqueValidator implements ConstraintValidator<PhoneNumbersValidAndUnique, String> {
    private static final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();

    @Autowired
    private ObjectMapper mapper;

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return false;
        }

        List<String> phoneNumbers;
        try {
            phoneNumbers = mapper.readValue(value, new TypeReference<ArrayList<String>>() {});
        } catch (JsonProcessingException e) {
            return false;
        }

        try {
            Optional<Phonenumber.PhoneNumber> invalidPhoneNumber = phoneNumbers.stream()
                    .map(phone -> {
                        try {
                            return phoneNumberUtil.parse(phone, null);
                        } catch (NumberParseException e) {
                            throw new RuntimeException(e);
                        }
                    })
                    .filter(phoneNumber -> !phoneNumberUtil.isValidNumber(phoneNumber))
                    .findFirst();

             if (invalidPhoneNumber.isPresent()) {
                 return false;
             }
        } catch (RuntimeException e) {
            return false;
        }

        if (phoneNumbers.stream()
                .map(phoneNumber -> phoneNumber.replaceAll("[\\s\\-()]", ""))
                .distinct()
                .count() != phoneNumbers.size()){
            return false;
        }

        return true;
    }
}

Problem is: @Autowired private ObjectMapper mapper; - inject NULL only in ConstraintValidator In all another components it works and return correct bean ObjectMapper.

I tried solutions from Autowired gives Null value in Custom Constraint validator

Nothing helps me !


Solution

  • Based on this Hibernate Validator in Spring Boot using different ConstraintValidatorManager

    I added Configuration

    package com.chisw.contactservice;
    
    import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Lazy;
    
    import javax.validation.Validator;
    import java.util.Map;
    
    @Configuration
    @Lazy
    class ValidatorConfig {
    
        @Bean
        @Lazy
        public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(final Validator validator) {
            return new HibernatePropertiesCustomizer() {
    
                @Override
                public void customize(Map<String, Object> hibernateProperties) {
                    hibernateProperties.put("javax.persistence.validation.factory", validator);
                }
            };
        }
    }