java - 使用自定义 javax 验证器时为存储库获取 NullPointerException
问题描述
我正在 Spring Boot 应用程序中处理 javax 验证 API。我有一个用户 bean,我必须验证请求中给出的用户名是唯一的并且不存在于数据库中。
我为此要求创建了自定义注释 ( UniqueUser.java
) 和自定义验证器( )。UniqueUserValidator.java
public class User {
@NotNull
@UniqueUser
private String username;
@NotNull
private String password;
@NotNull
@Email
private String email;
@NotNull
private String phone;
}
唯一用户.java
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueUserValidator.class)
@Documented
public @interface NameMatch
{
String message() default "User id already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
UniqueUserValidator.java
public class UniqueUserValidator implements ConstraintValidator<NameMatch, Object>
{
@Autowired
UserRepository userRepository;
@Override
public boolean isValid(String userName, final ConstraintValidatorContext context)
{
boolean isUserExist = false;
if(userName!=null && !userName.isEmpty()) {
Optional<Product> product = userRepository.findByUserId(userName);
isUserExist = product.isPresent();
}
return isUserExist;
}
}
我正在使用 Spring Data JPA 编写存储库类并从数据库中获取用户名。
用户存储库.java:
import org.springframework.data.repository.CrudRepository;
@Repository
interface UserRepository extends CrudRepository<User, Long> {
Optional<User> findByUserId();
}
验证配置.java
@Bean
public Validator validator (final AutowireCapableBeanFactory autowireCapableBeanFactory) {
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure().constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
用户名验证测试.java
public class UserNameValidationTest
{
@Autowired
Validator validator;
@Test
public void whenExistingUser_thenFai()
{
User user = new User();
user.setUserName("testUSer"); //Existing user is set
user.setPhone("12345678");
user.setPassword("password123");
user.setEmail("test@gmail.com");
//Validate bean
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
//Show errors
if (constraintViolations.size() > 0) {
for (ConstraintViolation<User> violation : constraintViolations) {
System.out.println(violation.getMessage());
}
} else {
System.out.println("Valid Object");
}
assertsEquals(true, constraintViolations.size()>0);
}
}
在执行上述测试类时,我得到了NullPointerException
自定义验证器类中的内容。有人可以帮我解决这个问题。userRepository
null
解决方案
当我们需要注入一些验证所需的 bean 时,这是使用 Hibernate 验证器的经典问题。
首先,userRepository
内部为 null的原因UniqueUserValidator
是因为您的 UniqueUserValidator 没有使用任何 Spring Bean 注释进行注释,因此甚至不会发生自动装配和依赖注入。
现在,如果您考虑使用基于构造函数的in 注入,那么在您添加它的那一刻,您将在控制台中收到错误消息,抱怨找不到无参数的构造函数。userRepository
UniqueUserValidator
错误:
java.lang.NoSuchMethodException: com.example.package.UniqueUserValidator.<init>()
...
...
要解决这个问题,你需要别的东西。一个休眠属性定制器。并摆脱您的 ValidationConfig.java。:
@Component
public class ValidatorAddingCustomizer implements HibernatePropertiesCustomizer {
private final ObjectProvider<Validator> provider;
@Autowired
public ValidatorAddingCustomizer(ObjectProvider<Validator> provider) {
this.provider = provider;
}
@Override
public void customize(Map<String, Object> hibernateProperties) {
Validator validator = provider.getIfUnique();
if (validator != null) {
hibernateProperties.put("javax.persistence.validation.factory", validator);
}
}
}
最后,正如我所提到的,您需要修改UniqueUserValidator
并在其中使用基于构造函数的注入,如下所示:
public class UniqueUserValidator implements ConstraintValidator<NameMatch, String>
{
private final UserRepository userRepository;
public UniqueUserValidator(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public boolean isValid(String userName, final ConstraintValidatorContext context)
{
..... // whatever logic
}
}
我注意到的另一件事是,在您的测试类中,您错过了两个类级别的注释@RunWith(SpringRunner.class)
和
@SpringBootTest(classes = YourMainApplication.class)
我已经为此创建了一个要点。如果您需要整体图片,请查看。
推荐阅读
- javascript - 在 Angular 5 中将 Javascript 对象附加到另一个对象
- oracle - 如何在oracle中构造分层数据
- java - 如何使依赖项在 JVM 语言中使用它们自己的传递依赖项
- c# - C# 将 KeyValue 设置为一行中的变量
- javascript - 折线图显示在 chartjs 组合图中的条形下方
- android - 为什么 webview 标题键在 android 中转换为小写?
- python - 如何找到非卷积模型tensorflow python的概率
- javascript - MongoDB - 即时从 ID 获取数据
- sql-server - 重新安装 SQL Server 2008 的问题
- c++ - 如何交叉编译 linux 和 udev 的 arm 视频