-
Notifications
You must be signed in to change notification settings - Fork 563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validator auto discovery not working for Spring Data Rest [DATAREST-524] #898
Comments
Fabian Trampusch commented Are there any news on this one? |
Andreas Kluth commented You could add this configuration to add the expected behavior.
|
Fabian Trampusch commented Thanks a lot, Andreas! I will try that approach. |
Sebastian Bathke commented Thanks Andreas for providing the configuration! Had the same problem that validation beans with this prefix didn't got catched up as the documentation suggests. However I encountered a problem that in some occasions (multiple repositories for the same entity) some tests failed to startup the context correctly with No qualifying bean of type [org.springframework.data.rest.core.event.ValidatingRepositoryEventListener] I could fix that by migrating your solution to RepositoryRestConfigurerAdapter: @Configuration
public class ValidatorRegistrar extends RepositoryRestConfigurerAdapter {
private static final List<String> EVENTS;
static {
List<String> events = new ArrayList<String>();
events.add("beforeCreate");
events.add("afterCreate");
events.add("beforeSave");
events.add("afterSave");
events.add("beforeLinkSave");
events.add("afterLinkSave");
events.add("beforeDelete");
events.add("afterDelete");
EVENTS = Collections.unmodifiableList(events);
}
@Autowired
ListableBeanFactory beanFactory;
@Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
super.configureValidatingRepositoryEventListener(validatingListener);
Map<String, Validator> validators = beanFactory.getBeansOfType(Validator.class);
for (Map.Entry<String, Validator> entry : validators.entrySet()) {
EVENTS.stream().filter(p -> entry.getKey().startsWith(p)).findFirst()
.ifPresent(p -> validatingListener.addValidator(p, entry.getValue()));
}
}
} |
jamlee commented it work for me . spring-data-rest 2.4 |
bitsofinfo commented Any progress on fixing doc or in the code? |
Casey Link commented After debugging and fighting with this for way to long, I land here on this bug report :( If the bug itself can't be fixed for whatever reasons, it would be nice at least to update the documentation The docs say:
That's exactly wrong! |
Farrukh Najmi commented I am using springboot 2.0.1.RELEASE with spring-data-rest and followed the workaround mentioned here and my Validator is still not being invoked. Here are the details:
@Component("beforeSaveBidValidator")
public class BeforeSaveBidValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Bid.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
Bid bid = (Bid)target;
if (!bid.getAddendaAcknowledged()) {
errors.rejectValue("addendaAcknowledged",
"addendaAcknowledged is not true");
}
}
}
@RestController
@RequestMapping(path = "/bids")
@Api(value = "/bids", description = "CRUD operations with Bids")
public class BidController {
private BidRepository bidRepository;
@Autowired
public BidController(
BidRepository bidRepository) {
this.bidRepository = bidRepository;
}
@PutMapping("{id}")
public Bid update(@RequestBody @Valid Bid bid) {
return bidRepository.save(bid);
}
}
Bid bid = new Bid()
...
bid.setAddendaAcknowledged(false)
Map<String, String> uriVariables = new HashMap<String, String>()
uriVariables.put("id", bid.id)
HttpHeaders headers = new HttpHeaders()
headers.setContentType(MediaType.APPLICATION_JSON)
HttpEntity<Bid> entity = new HttpEntity<>(bid, headers)
ResponseEntity<String> response = restTemplate.exchange(
"/bids/{id}", HttpMethod.PUT, entity, Bid.class, bid.id)
// Expected: response.statusCode == HttpStatus.BAD_REQUEST
// Found: response.statusCode == HttpStatus.OK
// Debugger showed that Validator was never invoked.
Any idea what I am missing?
|
Eddie Bush commented What's the current work-around for this? |
Rafael Renan Pacheco commented The workaround is blogged here: https://www.baeldung.com/spring-data-rest-validators You set the events you want to register in the events array, like "beforeCreate", and the code will look for all validators the starts with this string and register it. This way you can create your validators as components, like this: @Component
public class BeforeCreateItemValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return MyEntity.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required");
}
} And the workaround to load all validators that begins with "beforeCreate" is this: @Configuration
public class ValidatorEventRegister implements InitializingBean {
@Autowired
ValidatingRepositoryEventListener validatingRepositoryEventListener;
@Autowired
private Map<String, Validator> validators;
@Override
public void afterPropertiesSet() throws Exception {
List<String> events = Arrays.asList("beforeCreate");
for (Map.Entry<String, Validator> entry : validators.entrySet()) {
events.stream()
.filter(p -> entry.getKey().startsWith(p))
.findFirst()
.ifPresent(
p -> validatingRepositoryEventListener
.addValidator(p, entry.getValue()));
}
}
} If you add all possible events in the "events" array, you will get what Spring Data Rest should have been doing in the first place |
kwix commented Has anyone tried the workaround yet? I tried using the workaround but the events are not getting picked up. Would appreciate anyone's input on what might be causing this issue |
Servan Fichet commented Yes it is working for me! I added the configuration class and the Validator has been picked up. Do not forget to annotate the validator class with Do you know if the bug has been fixed? |
The above-mentioned code solved the issue on my side. I slightly modified it to also register JSR 380 bean validators: /**
* Configuration to merge multiple validator concepts.
*
* @author Sebastian Ullrich
* @since 1.0.0
*/
@Log4j2
@Configuration
@RequiredArgsConstructor
public class ValidatorConfig implements InitializingBean
{
public static final String BEFORE_CREATE = "beforeCreate";
public static final String BEFORE_SAVE = "beforeSave";
private final Map<String, Validator> validators;
private final LocalValidatorFactoryBean beanValidator;
private final ValidatingRepositoryEventListener validatingListener;
/**
* Assigns all present {@link org.springframework.validation.Validator Validators}
* to the {@link ValidatingRepositoryEventListener}.
*
* @see <a href="https://jira.spring.io/browse/DATAREST-524">DATAREST-524</a>
*/
@Override
public void afterPropertiesSet ()
{
// Assign custom validators
validators.entrySet().stream()
.filter(entry -> entry.getKey().startsWith(BEFORE_CREATE))
.map(Map.Entry::getValue)
.forEach(validator -> validatingListener.addValidator(BEFORE_CREATE, validator));
// Assign BeanValidator (JSR 380)
validatingListener.addValidator(BEFORE_CREATE, beanValidator);
validatingListener.addValidator(BEFORE_SAVE, beanValidator);
}
} |
This is still an issue as of 2021, according to baeldung, you can do: @Configuration
public class ValidatorEventRegister implements InitializingBean {
@Autowired
ValidatingRepositoryEventListener validatingRepositoryEventListener;
@Autowired
private Map<String, Validator> validators;
@Override
public void afterPropertiesSet() throws Exception {
List<String> events = Arrays.asList("beforeCreate");
for (Map.Entry<String, Validator> entry : validators.entrySet()) {
events.stream()
.filter(p -> entry.getKey().startsWith(p))
.findFirst()
.ifPresent(
p -> validatingRepositoryEventListener
.addValidator(p, entry.getValue()));
}
}
} |
In 2024, https://docs.spring.io/spring-data/rest/reference/validation.html mentioned auto wired still not work. |
Daniel Moses opened DATAREST-524 and commented
See documentation
http://docs.spring.io/spring-data/rest/docs/2.2.2.RELEASE/reference/html/#validation-chapter
Discovery should happen with Validator Prefix. Add a Validator bean to the context and notice that it does not get auto-detected. Manual wiring still works. Here is an example validator that will not work if included in the example Spring boot project:
See problem as reported:
http://stackoverflow.com/questions/24318405/spring-data-rest-validator
34 votes, 37 watchers
The text was updated successfully, but these errors were encountered: