com um clique
localized-exceptions-and-validation-skill
// This skill describes how to work with localized error messages for REST exceptions and Spring validators in OpenL Tablets WebStudio.
// This skill describes how to work with localized error messages for REST exceptions and Spring validators in OpenL Tablets WebStudio.
| name | localized-exceptions-and-validation-skill |
| description | This skill describes how to work with localized error messages for REST exceptions and Spring validators in OpenL Tablets WebStudio. |
This skill describes how to work with localized error messages for REST exceptions and Spring validators in OpenL Tablets WebStudio.
OpenL Tablets uses a consistent pattern for localizing error messages:
Validator interface with Errors objectRestRuntimeException with @ResponseStatus annotationValidationMessages.propertiesFor Spring validators, message keys use the pattern:
openl.error.<feature>.<detail>.message
Example:
openl.error.resource.base-path.invalid.message = The base path ''{0}'' is not valid.
openl.error.branch.name.empty.message = The branch name cannot be empty.
For REST exceptions, message keys include the HTTP status code:
openl.error.<status_code>.<feature>.<detail>.message
The status code is derived from @ResponseStatus annotation on the exception class.
Example:
openl.error.400.resource.base-path.not-folder.message = The base path ''{0}'' is not a folder.
openl.error.404.project.not-found.message = The project ''{0}'' is not found.
openl.error.409.project.locked.message = The project is locked by another user.
Use short keys (without openl.error. prefix):
// Field-level error
errors.rejectValue("fieldName", "resource.base-path.invalid.message", new Object[]{basePath}, null);
// Global/object-level error
errors.reject("branch.name.empty.message");
// With message arguments
errors.rejectValue("extensions", "resource.extension.invalid.message", new Object[]{ext}, null);
Use short keys (without openl.error.<status>. prefix):
// NotFoundException (404)
throw new NotFoundException("project.not-found.message", projectName);
// BadRequestException (400)
throw new BadRequestException("resource.base-path.not-folder.message", new Object[]{basePath});
// ConflictException (409)
throw new ConflictException("project.locked.message");
| Exception Class | HTTP Status | Annotation |
|---|---|---|
BadRequestException | 400 | @ResponseStatus(HttpStatus.BAD_REQUEST) |
ForbiddenException | 403 | @ResponseStatus(HttpStatus.FORBIDDEN) |
NotFoundException | 404 | @ResponseStatus(HttpStatus.NOT_FOUND) |
ConflictException | 409 | @ResponseStatus(HttpStatus.CONFLICT) |
Location: org.openl.studio.common.exception
package org.openl.studio.projects.validator.resource;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
@Component
public class MyModelValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return MyModel.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
var model = (MyModel) target;
if (model.getName() == null) {
errors.rejectValue("name", "mymodel.name.empty.message");
}
}
}
openl.error.mymodel.name.empty.message = The name cannot be empty.
@Service
public class MyService {
private final BeanValidationProvider validationProvider;
private final MyModelValidator myModelValidator;
public MyService(BeanValidationProvider validationProvider,
MyModelValidator myModelValidator) {
this.validationProvider = validationProvider;
this.myModelValidator = myModelValidator;
}
public void process(MyModel model) {
validationProvider.validate(model, myModelValidator);
// If validation fails, ValidationException is thrown automatically
// ... rest of the logic
}
}
Use {0}, {1}, etc. for positional arguments, or '' for literal single quotes:
openl.error.branch.name.exists.message = Branch ''{0}'' already exists in repository.
openl.error.branch.name.exists.1.message = Cannot create branch ''{0}'' because ''{1}'' already exists.
| File | Purpose |
|---|---|
STUDIO/.../resources/ValidationMessages.properties | All localized messages |
STUDIO/.../common/exception/*.java | Exception classes |
STUDIO/.../common/validation/BeanValidationProvider.java | Validation executor |
STUDIO/.../validator/**/*.java | Validator implementations |
See NewBranchValidator for a complete example using predicate chains:
@Override
public void validate(Object target, Errors errors) {
Predicate<String> chain = name -> validateNotEmpty(name, errors);
chain = chain.and(name -> validateFormat(name, errors));
chain = chain.and(name -> validateUniqueness(name, errors));
chain.test((String) target);
}
private boolean validateNotEmpty(String name, Errors errors) {
if (StringUtils.isBlank(name)) {
errors.reject("branch.name.empty.message");
return false; // Stop chain
}
return true; // Continue chain
}