英文:
How to perform an @Entity query inside a ConstraintValidator
问题
以下是您要翻译的内容:
情景是在持久化 `Log` 实体类之前,应该检查其属性 `String description` 是否包含至少一个在 `IllegalWord` 实体类中找到的单词。以下是这两个实体类的映射:
// Log.java
@Entity
public class Log {
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Id
private Long id;
@NotContainingIllegalWords
private String description;
}
// IllegalWord.java
@Entity
public class IllegalWord {
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Id
private Long id;
private String word;
}
由于我将执行对 `IllegalWord` 实体类的 `select *` 操作,我为它创建了一个存储库类:
// IllegalWordRepository.java
@Repository
public interface IllegalWordRepository extends CrudRepository<IllegalWord, Long> {}
然后创建了 `ConstraintValidator` 验证器类,该类将被 `NotContainingIllegalWords` 注解使用,而该注解将用于注解 `Log` 实体类的 `String description` 字段:
// NotContainingIllegalWordsValidator.java
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
private static final Logger log = LoggerFactory.getLogger(NotContainingIllegalWordsValidator.class);
@Autowired
private IllegalWordRepository illegalWordRepository;
public void initialize(NotContainingIllegalWords constraintAnnotation) {}
public boolean isValid(String value, ConstraintValidatorContext cxt) {
log.debug("illegalWordRepository is null? " + (illegalWordRepository == null));
// 返回 "illegalWordRepository is null? true"
// 即使使用了 @Autowired 注解,它仍然未被注入。
boolean valid = true;
Collection<IllegalWord> illegalWords = illegalWordRepository.findAll();
// 在这里遇到了 NullPointerException。
// valid = ...遍历 illegalWords 集合并使用正则表达式(或其他最佳方法)与 @param value 匹配,以检查它是否包含非法单词。
return valid;
}
}
我以为会像这样简单明了。但是语句 `illegalWordRepository.findAll()` 引发错误,因为 `illegalWordRepository` 变量为 null。请注意,我尝试在前面的语句中检查它是否为 `null`。
我认为我在存储库类中编写了错误的代码,因此我尝试在 `@Service` 注释的类中使用 `@Autowired private IllegalWordRepository illegalWordRepository`,令人惊讶的是,它在那里被正确注入了(即不为 `null`):
// IllegalWordService.java
@Service
public class IllegalWordService {
private static final Logger log = LoggerFactory.getLogger(IllegalWordService.class);
@Autowired
private IllegalWordRepository illegalWordRepository;
public IllegalWord generate(String word) {
log.debug("illegalWordRepository is null? " + (illegalWordRepository == null));
// 返回 "illegalWordRepository is null? false"
IllegalWord illegalWord = new IllegalWord();
illegalWord.setWord(word);
illegalWordRepository.save(illegalWord);
// 在这里没有遇到 NullPointerException。
return illegalWord;
}
}
因此,我猜测 `IllegalWordRepository` 存储库类没有问题。只是它没有像我打算的那样在 `NotContainingIllegalWordsValidator` 验证器类中被注入,即使我使用 `@Autowired` 注解(如果这就是 `@Autowired` 注解的预期功能的话,我很抱歉,我是 Spring Framework 的新手)。
如果有一种在 `ConstraintValidator` 实例中执行 @Entity 查询的正确方法,请告诉我。
相关未回答的 SO 问题:[在 Spring 4 和消息插值配置中在 ConstraintValidator 中注入 Repository][1]
**失败的尝试:**
我尝试使用 `@Configurable` 注解对 `NotContainingIllegalWordsValidator` 类进行注解,如下所示:
@Configurable(autowire=Autowire.BY_NAME, preConstruction=true)
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
但 `illegalWordRepository` 属性仍然为 `null`。
[1]: https://stackoverflow.com/q/46594706/4043409
英文:
The scenario is that before persisting a Log
entity class, its property, String description
should be checked if it contains at least a word found in the IllegalWord
entity class. Here is the mapping of the two entity classes:
// Log.java
@Entity
public class Log {
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Id
private Long id;
@NotContainingIllegalWords
private String description;
}
// IllegalWord.java
@Entity
public class IllegalWord {
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Id
private Long id;
private String word;
}
Since I will be performing a select *
to the IllegalWord
entity class, I created a repository class for it:
// IllegalWordRepository.java
@Repository
public interface IllegalWordRepository extends CrudRepository<IllegalWord, Long> {}
And then created the ConstraintValidator
validator class that will be used by NotContainingIllegalWords
annotation, that in turn, will be use to annotate the String description
field of Log
entity class:
// NotContainingIllegalWordsValidator.java
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
private static final Logger log = LoggerFactory.getLogger(NotContainingIllegalWordsValidator.class);
@Autowired
private IllegalWordRepository illegalWordRepository;
public void initialize(NotContainingIllegalWords constraintAnnotation) {}
public boolean isValid(String value, ConstraintValidatorContext cxt) {
log.debug("illegalWordRepository is null? " + (illegalWordRepository == null));
// Returns "illegalWordRepository is null? true"
// It is not injected even with the @Autowired annotation.
boolean valid = true;
Collection<IllegalWord> illegalWords = illegalWordRepository.findAll();
// Encounters a NullPointerException here.
// valid = ...loop through illegalWords collection and match regex (or whatever optimal approach)
// with @param value to check if it contains the illegal word.
return valid;
}
I thought it will be as straight-forward like that. But the statement illegalWordRepository.findAll()
throws an error because the illegalWordRepository
variable is null. Notice that I tried to check if it is null
in the preceding statement.
I assumed that I have something wrong coded within the repository class so I attempted to used @Autowired private IllegalWordRepository illegalWordRepository
inside a @Service
annotated class and suprisingly it is injected there properly (e.i. not null
):
// IllegalWordService.java
@Service
public class IllegalWordService {
private static final Logger log = LoggerFactory.getLogger(IllegalWordService.class);
@Autowired
private IllegalWordRepository illegalWordRepository;
public IllegalWord generate(String word) {
log.debug("illegalWordRepository is null? " + (illegalWordRepository == null));
// Returns "illegalWordRepository is null? false"
IllegalWord illegalWord = new IllegalWord();
illegalWord.setWord(word);
illegalWordRepository.save(illegalWord);
// Didn't encounter a NullPointerException here.
return illegalWord;
}
}
Therefore, I guess nothing is wrong with the IllegalWordRepository
repository class. It's just that it is not injected in NotContainingIllegalWordsValidator
validator class as I intended it to be with the @Autowired
annotation (if that is how @Autowired
annotation was intended to function even, I am sorry I am new in Spring Framework.).
If there is a proper approach on how to perform a @Entity query inside a ConstraintValidator
instance, please tell me.
Related unanswered SO question: Inject Repository inside ConstraintValidator with Spring 4 and message interpolation configuration
<hr/>
Failed Attempt:
I tried to annotate the NotContainingIllegalWordsValidator
class with @Configurable
annotation, like so:
@Configurable(autowire=Autowire.BY_NAME, preConstruction=true)
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
but the illegalWordRepository
property remains null
.
答案1
得分: 1
Since Your validator is not initialized by Spring, you can't inject anything into it. You'd have to access the ApplicationContext
through a static variable.
在您的验证器没有由Spring初始化时,您无法将任何内容注入其中。您必须通过静态变量访问ApplicationContext
。
@SpringBootApplication
public class MyApplication {
private static ApplicationContext applicationContext;
public static void main(final String[] args) {
applicationContext = SpringApplication.run(MyApplication.class, args);
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
And in your ConstraintValidator
:
在您的ConstraintValidator
中:
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
public boolean isValid(String value, ConstraintValidatorContext cxt) {
ApplicationContext applicationContext = MyApplication.getApplicationContext();
IllegalWordRepository illegalWordRepository = applicationContext.getBean(IllegalWordRepository.class);
...
}
}
英文:
Since Your validator is not initialized by Spring, you can't inject anything into it. You'd have to access the ApplicationContext
through a static variable.
@SpringBootApplication
public class MyApplication {
private static ApplicationContext applicationContext;
public static void main(final String[] args) {
applicationContext = SpringApplication.run(MyApplication.class, args);
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
And in your ConstraintValidator
:
public class NotContainingIllegalWordsValidator implements ConstraintValidator<NotContainingIllegalWords, Object> {
public boolean isValid(String value, ConstraintValidatorContext cxt) {
ApplicationContext applicationContext = MyApplication.getApplicationContext();
IllegalWordRepository illegalWordRepository = applicationContext.getBean(IllegalWordRepository.class);
...
}
}
答案2
得分: 0
以下是要翻译的内容:
来自我对类似问题的回答:
使@Autowired在ConstraintValidator实现中正常工作的最小设置是在Spring @Configuration中拥有此bean:
@Bean
public Validator defaultValidator() {
return new LocalValidatorFactoryBean();
}
这是演示项目。
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论