Как сохранить объект, имеющий поле с пользовательским валидатором, используя пружинные сапоги? - PullRequest
0 голосов
/ 11 июля 2019

Может кто-нибудь помочь мне, почему я не могу сохранить объект, имеющий поле с настраиваемым валидатором, в весенних сапогах?

Сценарий: сначала я должен проверить поле с помощью настраиваемого валидатора (который работает нормально), затемсохранить сущность в базу данных (которая ломается).Я использую Spring Boot Framework на IntelliJ IDE.Код есть на github.https://github.com/mhussainshah1/customvalidation

У меня есть сущность Customer

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @ContactInfo //Custom Validator
    @NotNull
    private String contactInfo;

    // standard constructor, getters, setters
}

У меня есть сущность ContactInfoExpression

@Entity
public class ContactInfoExpression {

    @Id
    @Column(name="expression_type")
    private String type;

    private String pattern;

    //standard constructor, getters, setters
}

У меня есть ContactInfoExpressionRepository и CustomerRepository, которая расширяется CrudRepository<T, Id>

Я использую базу данных H2 в памяти со следующей конфигурацией в файле application.properties.Свойству contactInfoType может быть присвоено одно из значений: электронная почта, телефон или веб-сайт

spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.show-sql=true

contactInfoType=email
#contactInfoType=phone
#contactInfoType=website

Пользовательский валидатор

@Component
public class ContactInfoValidator implements ConstraintValidator<ContactInfo, String> {

    private static final Logger LOG = LogManager.getLogger(ContactInfoValidator.class);

    @Value("${contactInfoType}")
    private String expressionType;

    private String pattern;

    @Autowired
    private ContactInfoExpressionRepository contactInfoExpressionRepository;

    @Override
    public void initialize(ContactInfo contactInfo) {
        if (StringUtils.isEmptyOrWhitespace(expressionType)) {
            LOG.error("Contact info type missing!");
        } else {
            pattern = contactInfoExpressionRepository.findById(expressionType)
                    .map(ContactInfoExpression::getPattern).get();
        }
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (!StringUtils.isEmptyOrWhitespace(pattern)) {
            return Pattern.matches(pattern, value);
        }
        LOG.error("Contact info pattern missing!");
        return false;
    }
}

Пользовательская аннотация ограничения

@Constraint(validatedBy = { ContactInfoValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface ContactInfo {
    String message() default "Invalid value";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

Я использую класс DataLoader для загрузки данных

@Component
public class DataLoader implements CommandLineRunner {

    @Autowired
    ContactInfoExpressionRepository contactInfoExpressionRepository;

    @Autowired
    CustomerRepository customerRepository;

    @Override
    public void run(String... args) throws Exception {
        String pattern = "[a-z0-9!#$%&*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";
        ContactInfoExpression email = new ContactInfoExpression("email", pattern);
        contactInfoExpressionRepository.save(email);

        pattern = "^([0-9]( |-)?)?(\\(?[0-9]{3}\\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})$";
        ContactInfoExpression phone = new ContactInfoExpression("phone", pattern);
        contactInfoExpressionRepository.save(phone);

        pattern = "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$";
        ContactInfoExpression website = new ContactInfoExpression("website", pattern);
        contactInfoExpressionRepository.save(website);

        Customer customer1 = new Customer("mhussainshah79@gmail.com");
        customerRepository.save(customer1);// Error: can`t save
    }
}

Я не могу сохранить объект клиента, имеющий поле с пользовательским валидатором.Я получаю следующую ошибку во время выполнения

java.lang.IllegalStateException: Failed to execute CommandLineRunner

Caused by: org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction

Caused by: javax.persistence.RollbackException: Error while committing the transaction

Caused by: javax.validation.ValidationException: HV000032: Unable to initialize com.example.customvalidation.ContactInfoValidator.

Caused by: java.lang.NullPointerException: null
    at com.example.customvalidation.ContactInfoValidator.initialize(ContactInfoValidator.java:41) ~[classes/:na]
    at com.example.customvalidation.ContactInfoValidator.initialize(ContactInfoValidator.java:18) ~[classes/:na]

1 Ответ

1 голос
/ 13 июля 2019

Решение проблемы заключается в добавлении следующего в файл application.properties.

properties spring.jpa.properties.javax.persistence.validation.mode:none

Ссылка: Как избежать двойной проверки в приложениях Spring Boot, Санджай Патель, 15 мая 2018 г. https://www.naturalprogrammer.com/blog/16386/switch-off-jpa-validation-spring-boot

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...