We use a standard SEAM setup here ... complete with the validation system that uses hibernate.
Basically what happens is a user enters a value into an html input and seam validates the value they entered using the hibernate validation.
Works fine for the most part except here's my problem: We need to record the results of validation on each field and I can't figure out a good way to do it ... ideally it would be done through communicating with the seam/hibernate validation system and just recording the validation results but as far as I can tell there isn't a way to do this?
Has anyone done anything like this in the past? There are a couple nasty work arounds but I'd prefer to do it cleanly.
Just a quick overview of the process that we have happening right now for context:
1) user enters field value
2) onblur value is set with ajax (a4j:support) at this point the validators fire and the div is re-rendered, if any validation errors occured they're now visible on the page
What I'd like to have happen at step2 is a 'ValidationListener' or something similar is called which would allow us to record the results of the validation.
Thanks if anyone is able to help :o
You should be able to do it by creating a Bean that has a method observing the org.jboss.seam.validationFailed event. That method can then do whatever logging you want.
#Name("validationObserver")
public class ValidationObserver() {
#Observer("org.jboss.seam.validationFailed")
public void validationFailed() {
//Do stuff
}
}
The validationFailed event doesn't pass any parameters so you'll have to interrogate the FacesMessages or possibly the Hibernate Validation framework itself if you want to record what the error was.
I you are only using Hibernate for validation, you can use the Hibernate ClassValidator in the validationFailed() method, as recommended by Damo.
Example:
public <T> InvalidValue[] validateWithHibernate(T object) {
ClassValidator<T> validator = new ClassValidator(object.getClass());
InvalidValue[] invalidValues = validator.getInvalidValues(object);
return invalidValues;
}
Related
I am migrating and existing crud application into Axon, and I have some concerns with the following scenario. I have an api given below to create groups,
#PostMapping
public Mono<IdDto> createGroup(#RequestBody #Valid CreateGroupCommand command) {
log.trace("Create GroupResponseInfoDto request {}", command);
return commandGateway.send(command)
.map((o) -> new IdDto((UUID) o));
}
The command looks like,
#Data
public class CreateGroupCommand {
#NotBlank
private String name;
#NotBlank
private String description;
}
and the main requirement here is that the group name must be unique.
Therefore, in the Aggregate I have the following code to check this logic.
#CommandHandler
public GroupAggregate(CreateGroupCommand command, GroupRepository groupRepository, ModelMapper mapper) {
log.trace("Handle create group command {}", command);
groupRepository.findByName(command.getName())
.ifPresent((g) -> {
throw new ApplicationException(UserMsError.GROUP_ALREADY_EXISTS.name());
});
GroupCreatedEvent event = mapper.map(command, GroupCreatedEvent.class);
event.setId(UUID.randomUUID());
AggregateLifecycle.apply(event);
}
And once the validation pareses, the event is persisted by a projector into the db.
#EventSourcingHandler
public void on(GroupCreatedEvent event) {
log.trace("Group create event {}", event);
groupRepository.findByName(event.getName())
.ifPresent((g) -> {
throw new ApplicationException(UserMsError.GROUP_ALREADY_EXISTS.name());
});
Group group = modelMapper.map(event, Group.class);
groupRepository.save(group);
}
The problem now is, there is some lap time between the command execution and the persistance of the event results into group table. If another user creates a group in that time, the command does not fail as the record does not exist in the db. Now, I see in Axon site there is a way to create a temporary table where we put the command execution into some temporary table which we can use for validation purpose, but that requires additional coding and quite extra effort for each such requirement. It also means, if we persist the details on command execution, and for some reason the process fails then the record will exist in our validation table but not on the system. If we try to validate the scenario on event execution, that extra effort might not be required but in this case the problem is I am not able to fail the API call so that the user knows the results. Could you please recommend if there is an alternative approach to validate the input without an intermediate check?
The problem you are looking at is set-based validation. Whenever you're dealing with CQRS, it's the sets that will require extra work to be validated.
Although uncertain, I assume you're talking about the Set-Based Consistency Validation blog? That is, for a reason, the suggested approach to deal with set validation. Note that the implementation used in the blog can be found here.
Added, it quite recently has seen an update that does not include the problem you describe as follows:
It also means, if we persist the details on command execution, and for some reason, the process fails, then the record will exist in our validation table but not on the system.
Axon's transaction logic, supported through the UnitOfWork, will roll back the entire transaction if something fails. This thus anything you'd do inside the UnitOfWork, including updates to another table for validation.
I get that it's some boilerplate code, but it is the predicament of having the uniqueness requirement on a set. What might be something you can look into is forcing the uniqueness through the Aggregate Identifier. Axon's Event Store logic ensures no two events are using the same aggregate identifier. So, if you try to input a new aggregate (hence a new event) for an already existing aggregate identifier, the operation will fail.
This approach is typically not feasible whenever the set-based consistency validation issue is described, though, so I am guessing it won't help you out.
Concluding, I'd take your win from the shared repository on the blog to minimize your personal effort on the matter.
If I take a service method named public void delete(int id); as the pointcut, I want to add an after-returning advice on it, but I don't know what kind of object was deleted(however, the servlet which called the service knows the type value), so I was wondering if I can pass a customized value to this after-returning advice when it is activated, like 'user'. I've already checked the related document on Spring's website and I still know nothing. I'd appreciate your answer, THX.
One solution but its required refactoring in Service method
1) Refactoring
public class DeleteRequest {
String type;
Long id;
}
public boolean delete(DeleteRequest request){ // impl}
2) Use Around Advice
2.1) Before proceeding method execution, read passed parameter & get to be deleted object for "XYZ" requirement.
2.2) Capture result of delete method execution
IF its TRUE then DO your stuff
Note: I used this approach for deleted entity notification. So how we can get deleted entity information in after-advice, hence keep it entity information in before phase & use it in after-successful execution.
I created a Spring Webflow exception-handler for my application and defined it in my abstract parent flow.
In this handler I add FacesMessages to display several errors in a generic way.
Now i got the problem that i can't handle an exception that occures in an action-state. I try to go back to the last valid view-state or something like that (or maybe go to the start-state). Anyway, I don't want the application to crash or show a blank page.
#Override
public void handle(FlowExecutionException exception, RequestControlContext context) {
Object testState = context.getCurrentState();
if(testState instanceof ActionState){
//what to do here?
}
}
I am using Spring Webflow Version 2.3.0.RELEASE with JSF 2 on MyFaces.
Best regards,
Patrick
You can execute a transition to another state (the transition must exist). So, inside your if statement you could do the following:
TransitionDefinition errorDefinition = context.getMatchingTransition("errorState");
Transition errorTransition = (Transition)errorDefinition;
context.execute(errorTransition);
The transition could be a global transition to a generic error page.
Regards.
We all know, that Spring MVC integrate well with Hibernate Validator and JSR-303 in general. But Hibernate Validator, as someone said, is something for Bean Validation only, which means that more complex validations should be pushed to the data layer. Examples of such validations: business key uniqueness, intra-records dependence (which is usually something pointing at DB design problems, but we all live in an imperfect world). Even simple validations like string field length may be driven by some DB value, which makes Hibernate Validator unusable.
So my question is, is there something Spring or Hibernate or JSR offers to perform such complex validations? Is there some established pattern or technology piece to perform such a validation in a standard Controller-Service-Repository setup based on Spring and Hibernate?
UPDATE: Let me be more specific. For example, there's a form which sends an AJAX save request to the controller's save method. If some validation error occurs -- either simple or "complex" -- we should get back to the browser with some json indicating a problematic field and associated error. For simple errors I can extract the field (if any) and error message from BindingResult. What infrastructure (maybe specific, not ad-hoc exceptions?) would you propose for "complex" errors? Using exception handler doesn't seem like a good idea to me, because separating single process of validation between save method and #ExceptionHandler makes things intricate. Currently I use some ad-hoc exception (like, ValidationException):
public #ResponseBody Result save(#Valid Entity entity, BindingResult errors) {
Result r = new Result();
if (errors.hasErrors()) {
r.setStatus(Result.VALIDATION_ERROR);
// ...
} else {
try {
dao.save(entity);
r.setStatus(Result.SUCCESS);
} except (ValidationException e) {
r.setStatus(Result.VALIDATION_ERROR);
r.setText(e.getMessage());
}
}
return r;
}
Can you offer some more optimal approach?
Yes, there is the good old established Java pattern of Exception throwing.
Spring MVC integrates it pretty well (for code examples, you can directly skip to the second part of my answer).
What you call "complex validations" are in fact exceptions : business key unicity error, low layer or DB errors, etc.
Reminder : what is validation in Spring MVC ?
Validation should happen on the presentation layer. It is basically about validating submitted form fields.
We could classify them into two kinds :
1) Light validation (with JSR-303/Hibernate validation) : checking that a submitted field has a given #Size/#Length, that it is #NotNull or #NotEmpty/#NotBlank, checking that it has an #Email format, etc.
2) Heavy validation, or complex validation are more about particular cases of field validations, such as cross-field validation :
Example 1 : The form has fieldA, fieldB and fieldC. Individually, each field can be empty, but at least one of them must not be empty.
Example 2 : if userAge field has a value under 18, responsibleUser field must not be null and responsibleUser's age must be over 21.
These validations can be implemented with Spring Validator implementations, or custom annotations/constraints.
Now I understand that with all these validation facilites, plus the fact that Spring is not intrusive at all and lets you do anything you want (for better or for worse), one can be tempted to use the "validation hammer" for anything vaguely related to error handling.
And it would work : with validation only, you check every possible problem in your validators/annotations (and hardly throw any exception in lower layers). It is bad, because you pray that you thought about all the cases. You don't leverage Java exceptions that would allow you to simplify your logic and reduce the chance of making a mistake by forgetting to check that something had an error.
So in the Spring MVC world, one should not mistake validation (that is to say, UI validation) for lower layer exceptions, such has Service exceptions or DB exceptions (key unicity, etc.).
How to handle exceptions in Spring MVC in a handy way ?
Some people think "Oh god, so in my controller I would have to check all possible checked exceptions one by one, and think about a message error for each of them ? NO WAY !". I am one of those people. :-)
For most of the cases, just use some generic checked exception class that all your exceptions would extend. Then simply handle it in your Spring MVC controller with #ExceptionHandler and a generic error message.
Code example :
public class MyAppTechnicalException extends Exception { ... }
and
#Controller
public class MyController {
...
#RequestMapping(...)
public void createMyObject(...) throws MyAppTechnicalException {
...
someServiceThanCanThrowMyAppTechnicalException.create(...);
...
}
...
#ExceptionHandler(MyAppTechnicalException.class)
public String handleMyAppTechnicalException(MyAppTechnicalException e, Model model) {
// Compute your generic error message/code with e.
// Or just use a generic error/code, in which case you can remove e from the parameters
String genericErrorMessage = "Some technical exception has occured blah blah blah" ;
// There are many other ways to pass an error to the view, but you get the idea
model.addAttribute("myErrors", genericErrorMessage);
return "myView";
}
}
Simple, quick, easy and clean !
For those times when you need to display error messages for some specific exceptions, or when you cannot have a generic top-level exception because of a poorly designed legacy system you cannot modify, just add other #ExceptionHandlers.
Another trick : for less cluttered code, you can process multiple exceptions with
#ExceptionHandler({MyException1.class, MyException2.class, ...})
public String yourMethod(Exception e, Model model) {
...
}
Bottom line : when to use validation ? when to use exceptions ?
Errors from the UI = validation = validation facilities (JSR-303 annotations, custom annotations, Spring validator)
Errors from lower layers = exceptions
When I say "Errors from the UI", I mean "the user entered something wrong in his form".
References :
Passing errors back to the view from the service layer
Very informative blog post about bean validation
Stripes allows you to validate your form input values using the #Validate annotation on your member variables. Does anyone have any experience testing these annotations directly. I could do this by testing the validation errors that come back from the ActionBean, but this seems a little long winded and I would like a more direct method of testing if an input value is valid.
I'm not that familiar with the innards of the Framework yet, and I was hoping someone could give me some direction on where to start. TIA.
One method I've used is Stripes' built in MockRoundtrip. It is useful for simulating a complete test of an action bean event outside the container.
Example from the documentation:
MockServletContext context = ...;
MockRoundtrip trip = new MockRoundtrip(context, CalculatorActionBean.class);
trip.setParameter("numberOne", "2");
trip.setParameter("numberTwo", "2");
trip.execute();
CalculatorActionBean bean = trip.getActionBean(CalculatorActionBean.class);
Assert.assertEquals(bean.getResult(), 4, "two plus two should equal four");
Assert.assertEquals(trip.getDestination(), ""/quickstart/index.jsp");
Additionally, you could use trip.getValidationErrors() and assert that your error is in there.