new logic of validations

This commit is contained in:
Efstratios Giannopoulos 2023-12-19 14:54:17 +02:00
parent 3e97d0fdd1
commit 68c56d70a4
16 changed files with 684 additions and 100 deletions

View File

@ -1,47 +1,150 @@
package eu.eudat.commons.validation; package eu.eudat.commons.validation;
import eu.eudat.commons.validation.specification.*;
import eu.eudat.convention.ConventionService;
import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.errorcode.ErrorThesaurusProperties;
import gr.cite.tools.exception.MyValidationException; import gr.cite.tools.exception.MyValidationException;
import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.validation.FieldError; import org.springframework.validation.FieldError;
import org.springframework.validation.ValidationUtils;
import java.util.AbstractMap; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
public abstract class BaseValidator implements ModelValidator { public abstract class BaseValidator<T> implements Validator {
private BeanPropertyBindingResult result; private BeanPropertyBindingResult bindingResult;
protected final ConventionService conventionService;
protected final ErrorThesaurusProperties errors; protected final ErrorThesaurusProperties errors;
protected BaseValidator(ErrorThesaurusProperties errors) { protected BaseValidator(ConventionService conventionService, ErrorThesaurusProperties errors) {
this.conventionService = conventionService;
this.errors = errors; this.errors = errors;
} }
protected abstract Class<T> modelClass();
protected abstract List<Specification> specifications(T item);
@Override
public boolean supports(Class clazz) {
return clazz == null ? false : this.modelClass().equals(clazz);
}
@Override
public void validate(Object obj, Errors e) {
if (obj == null) return;
T item = this.modelClass().cast(obj);
List<Specification> specifications = this.specifications(item);
if (specifications == null) return;;
List<PropertySpecification> propertySpecifications = specifications.stream().filter(x-> x instanceof PropertySpecification).map(x-> (PropertySpecification)x).toList();
for (PropertySpecification propertySpecification : propertySpecifications){
if ((propertySpecification.getPrecondition() == null || propertySpecification.getPrecondition().get()) &&
(propertySpecification.getSpecification() == null || !propertySpecification.getSpecification().get())
){
e.rejectValue(propertySpecification.getErrorKey(), propertySpecification.getErrorCode(), propertySpecification.getErrorMessage());
}
}
List<NavigationReferenceSpecification> navigationReferenceSpecifications = specifications.stream().filter(x-> x instanceof NavigationReferenceSpecification).map(x-> (NavigationReferenceSpecification)x).toList();
for (NavigationReferenceSpecification navigationReferenceSpecification : navigationReferenceSpecifications){
if (navigationReferenceSpecification.getReference() != null && (navigationReferenceSpecification.getPrecondition() == null || navigationReferenceSpecification.getPrecondition().get())){
try {
e.pushNestedPath(navigationReferenceSpecification.getKey());
ValidationUtils.invokeValidator(navigationReferenceSpecification.getValidator().get(), navigationReferenceSpecification.getReference(), e);
} finally {
e.popNestedPath();
}
}
}
List<NavigationDetailsSpecification> navigationDetailsSpecifications = specifications.stream().filter(x-> x instanceof NavigationDetailsSpecification).map(x-> (NavigationDetailsSpecification)x).toList();
for (NavigationDetailsSpecification navigationDetailsSpecification : navigationDetailsSpecifications){
if (navigationDetailsSpecification.getDetails() != null && (navigationDetailsSpecification.getPrecondition() == null || navigationDetailsSpecification.getPrecondition().get())){
for (int i = 0; i < navigationDetailsSpecification.getDetails().size(); i++) {
try {
e.pushNestedPath(MessageFormat.format("{0}[{1}]", navigationDetailsSpecification.getKey(), i));
ValidationUtils.invokeValidator(navigationDetailsSpecification.getValidator().get(), navigationDetailsSpecification.getDetails().get(i), e);
} finally {
e.popNestedPath();
}
}
}
}
}
@Override @Override
public void validate(Object target){ public void validate(Object target){
this.result = new org.springframework.validation.BeanPropertyBindingResult(target, target.getClass().getName()); this.bindingResult = new org.springframework.validation.BeanPropertyBindingResult(target, target.getClass().getName());
this.validate(target, this.result); this.validate(target, this.bindingResult);
} }
@Override @Override
public void validateForce(Object target) { public void validateForce(Object target) {
this.validate(target); this.validate(target);
ValidationResult result = result();
if (this.result != null && result.hasErrors()){ if (!result.isValid()){
List<Map.Entry<String, List<String>>> errorsMap = new ArrayList<>(); List<Map.Entry<String, List<String>>> errorsMap = this.flattenValidationResult();
for (FieldError fieldError : result.getFieldErrors()){
errorsMap.add(new AbstractMap.SimpleEntry<>(fieldError.getField(), List.of(fieldError.getDefaultMessage())));
}
throw new MyValidationException(this.errors.getModelValidation().getCode(), errorsMap); throw new MyValidationException(this.errors.getModelValidation().getCode(), errorsMap);
} }
} }
protected List<Map.Entry<String, List<String>>> flattenValidationResult() {
ValidationResult result = result();
List<Map.Entry<String, List<String>>> errorsMap = new ArrayList<>();
for (ValidationFailure fieldError : result.getErrors()){
Map.Entry<String, List<String>> entry = errorsMap.stream().filter(x-> Objects.equals(x.getKey(), fieldError.getErrorKey())).findFirst().orElse(null);
if (entry == null) {
entry = new AbstractMap.SimpleEntry<>(fieldError.getErrorKey(), new ArrayList<>());
errorsMap.add(entry);
}
entry.getValue().add(fieldError.getErrorMessage());
}
return errorsMap;
}
protected PropertySpecificationBuilder spec() {
return new PropertySpecificationBuilder();
}
protected NavigationReferenceSpecificationBuilder refSpec() {
return new NavigationReferenceSpecificationBuilder();
}
protected NavigationDetailsSpecificationBuilder navSpec()
{
return new NavigationDetailsSpecificationBuilder();
}
@Override @Override
public Errors result() { public ValidationResult result() {
return this.result; ValidationResult validationResult = new ValidationResult();
if (this.bindingResult != null && bindingResult.hasErrors()){
for (FieldError fieldError : bindingResult.getFieldErrors()){
validationResult.add(new ValidationFailure(fieldError.getField(), fieldError.getDefaultMessage()));
}
}
return validationResult;
}
protected Boolean isValidGuid(UUID guid) {
return this.conventionService.isValidGuid(guid);
}
protected Boolean isValidHash(String hash) {
return this.conventionService.isValidHash(hash);
}
protected Boolean isEmpty(String value) {
return this.conventionService.isNullOrEmpty(value);
}
protected Boolean lessEqual(String value, int size) {
return value.length() <= size;
} }
} }

View File

@ -0,0 +1,24 @@
package eu.eudat.commons.validation;
public class ValidationFailure {
public String errorKey;
public String errorMessage;
public ValidationFailure(String errorMessage) {
this.errorMessage = errorMessage;
}
public ValidationFailure(String errorKey, String errorMessage) {
this.errorKey = errorKey;
this.errorMessage = errorMessage;
}
public String getErrorKey() {
return errorKey;
}
public String getErrorMessage() {
return errorMessage;
}
}

View File

@ -0,0 +1,34 @@
package eu.eudat.commons.validation;
import java.util.ArrayList;
import java.util.List;
public class ValidationResult {
private final List<ValidationFailure> errors;
public ValidationResult() {
this.errors = new ArrayList<>();
}
public Boolean isValid() {
return this.errors.isEmpty();
}
public ValidationResult add(ValidationFailure failure) {
if (failure != null) {
errors.add(failure);
}
return this;
}
public ValidationResult addAll(List<ValidationFailure> failures) {
if (failures != null) {
errors.addAll(failures);
}
return this;
}
public List<ValidationFailure> getErrors() {
return errors;
}
}

View File

@ -1,10 +1,9 @@
package eu.eudat.commons.validation; package eu.eudat.commons.validation;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public interface ModelValidator extends Validator { public interface Validator extends org.springframework.validation.Validator {
void validate(Object target); void validate(Object target);
void validateForce(Object target); void validateForce(Object target);
Errors result(); ValidationResult result();
} }

View File

@ -0,0 +1,33 @@
package eu.eudat.commons.validation;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
@Service
public class ValidatorFactory {
private final ApplicationContext applicationContext;
public ValidatorFactory(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public <T extends Validator> T validator(Class<T> type){
T item = this.applicationContext.getBean(type);
if (item == null || !(item instanceof Validator)) throw new RuntimeException("unrecognized validator " + type.getSimpleName());
return item;
}
public Validator validator(String validtor){
Validator item = this.applicationContext.getBean(validtor, Validator.class);
if (item == null || !(item instanceof Validator)) throw new RuntimeException("unrecognized validator " + validtor);
return item;
}
}

View File

@ -0,0 +1,16 @@
package eu.eudat.commons.validation.specification;
import eu.eudat.commons.validation.Validator;
import java.util.List;
import java.util.function.Supplier;
public interface NavigationDetailsSpecification extends Specification {
Supplier<Boolean> getPrecondition();
String getKey();
List<?> getDetails();
Supplier<Validator> getValidator();
}

View File

@ -0,0 +1,53 @@
package eu.eudat.commons.validation.specification;
import eu.eudat.commons.validation.Validator;
import java.util.List;
import java.util.function.Supplier;
public class NavigationDetailsSpecificationBuilder implements NavigationDetailsSpecification {
private Supplier<Boolean> precondition;
private String key;
private List<?> details;
private Supplier<Validator> validator;
public NavigationDetailsSpecificationBuilder iff(Supplier<Boolean> value){
this.precondition = value;
return this;
}
public NavigationDetailsSpecificationBuilder on(String value){
this.key = value;
return this;
}
public NavigationDetailsSpecificationBuilder over(List<?> value){
this.details = value;
return this;
}
public NavigationDetailsSpecificationBuilder using(Supplier<Validator> value){
this.validator = value;
return this;
}
@Override
public Supplier<Boolean> getPrecondition() {
return precondition;
}
@Override
public String getKey() {
return key;
}
@Override
public List<?> getDetails() {
return details;
}
@Override
public Supplier<Validator> getValidator() {
return validator;
}
}

View File

@ -0,0 +1,15 @@
package eu.eudat.commons.validation.specification;
import eu.eudat.commons.validation.Validator;
import java.util.function.Supplier;
public interface NavigationReferenceSpecification extends Specification{
Supplier<Boolean> getPrecondition();
String getKey();
Object getReference();
Supplier<Validator> getValidator();
}

View File

@ -0,0 +1,53 @@
package eu.eudat.commons.validation.specification;
import eu.eudat.commons.validation.Validator;
import java.util.function.Supplier;
public class NavigationReferenceSpecificationBuilder implements NavigationReferenceSpecification {
private Supplier<Boolean> precondition;
private String key;
private Object reference;
private Supplier<Validator> validator;
public NavigationReferenceSpecificationBuilder iff(Supplier<Boolean> value){
this.precondition = value;
return this;
}
public NavigationReferenceSpecificationBuilder on(String value){
this.key = value;
return this;
}
public NavigationReferenceSpecificationBuilder over(Object value){
this.reference = value;
return this;
}
public NavigationReferenceSpecificationBuilder using(Supplier<Validator> value){
this.validator = value;
return this;
}
@Override
public Supplier<Boolean> getPrecondition() {
return precondition;
}
@Override
public String getKey() {
return key;
}
@Override
public Object getReference() {
return reference;
}
@Override
public Supplier<Validator> getValidator() {
return validator;
}
}

View File

@ -0,0 +1,15 @@
package eu.eudat.commons.validation.specification;
import java.util.function.Supplier;
public interface PropertySpecification extends Specification {
Supplier<Boolean> getPrecondition();
Supplier<Boolean> getSpecification();
String getErrorKey();
String getErrorMessage();
String getErrorCode();
}

View File

@ -0,0 +1,62 @@
package eu.eudat.commons.validation.specification;
import java.util.function.Supplier;
public class PropertySpecificationBuilder implements PropertySpecification{
private Supplier<Boolean> precondition;
private Supplier<Boolean> specification;
private String errorKey;
private String errorMessage;
private String errorCode = "validationerror";
public PropertySpecificationBuilder iff(Supplier<Boolean> value){
this.precondition = value;
return this;
}
public PropertySpecificationBuilder must(Supplier<Boolean> value){
this.specification = value;
return this;
}
public PropertySpecificationBuilder failOn(String value){
this.errorKey = value;
return this;
}
public PropertySpecificationBuilder failWith(String value){
this.errorMessage = value;
return this;
}
public PropertySpecificationBuilder failWithCode(String value){
this.errorCode = value;
return this;
}
@Override
public Supplier<Boolean> getPrecondition() {
return precondition;
}
@Override
public Supplier<Boolean> getSpecification() {
return specification;
}
@Override
public String getErrorKey() {
return errorKey;
}
@Override
public String getErrorMessage() {
return errorMessage;
}
@Override
public String getErrorCode() {
return errorCode;
}
}

View File

@ -0,0 +1,6 @@
package eu.eudat.commons.validation.specification;
import java.util.function.Supplier;
public interface Specification {
}

View File

@ -2,25 +2,26 @@ package eu.eudat.model.persist;
import eu.eudat.commons.enums.DescriptionTemplateTypeStatus; import eu.eudat.commons.enums.DescriptionTemplateTypeStatus;
import eu.eudat.commons.validation.BaseValidator; import eu.eudat.commons.validation.*;
import eu.eudat.commons.validation.FieldNotNullIfOtherSet;
import eu.eudat.commons.validation.ValidEnum;
import eu.eudat.commons.validation.ValidId;
import eu.eudat.commons.validation.specification.Specification;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.DescriptionTemplateTypeEntity; import eu.eudat.data.DescriptionTemplateTypeEntity;
import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.errorcode.ErrorThesaurusProperties;
import eu.eudat.model.Description; import eu.eudat.model.Description;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils; import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -30,20 +31,30 @@ public class DescriptionTemplateTypePersist {
@ValidId(message = "{validation.invalidid}") @ValidId(message = "{validation.invalidid}")
private UUID id; private UUID id;
public final static String _id = "id";
@NotNull(message = "{validation.empty}") @NotNull(message = "{validation.empty}")
@NotEmpty(message = "{validation.empty}") @NotEmpty(message = "{validation.empty}")
@Size(max = DescriptionTemplateTypeEntity._nameLength, message = "{validation.largerthanmax}") @Size(max = DescriptionTemplateTypeEntity._nameLength, message = "{validation.largerthanmax}")
private String name = null; private String name = null;
public final static String _name = "name";
private String hash; private String hash;
public final static String _hash = "hash";
@ValidEnum(message = "{validation.empty}") @ValidEnum(message = "{validation.empty}")
private DescriptionTemplateTypeStatus status; private DescriptionTemplateTypeStatus status;
private List<DescriptionTemplateTypePersist> nested; private List<DescriptionTemplateTypePersist> nested;
public final static String _nested = "nested";
private DescriptionTemplateTypePersist obj; private DescriptionTemplateTypePersist obj;
public final static String _obj = "obj";
public UUID getId() { public UUID getId() {
return id; return id;
} }
@ -93,62 +104,53 @@ public class DescriptionTemplateTypePersist {
} }
@Component(DescriptionTemplateTypePersistValidator.ValidatorName) @Component(DescriptionTemplateTypePersistValidator.ValidatorName)
public static class DescriptionTemplateTypePersistValidator extends BaseValidator { @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static class DescriptionTemplateTypePersistValidator extends BaseValidator<DescriptionTemplateTypePersist> {
@Autowired
private DescriptionTemplateTypePersistValidator1 descriptionTemplateTypePersistValidator;
public static final String ValidatorName = "DescriptionTemplateTypePersistValidator"; public static final String ValidatorName = "DescriptionTemplateTypePersistValidator";
private final ValidatorFactory validatorFactory;
private final MessageSource messageSource; private final MessageSource messageSource;
public DescriptionTemplateTypePersistValidator(MessageSource messageSource, ErrorThesaurusProperties errors) { public DescriptionTemplateTypePersistValidator(MessageSource messageSource, ValidatorFactory validatorFactory, ConventionService conventionService, ErrorThesaurusProperties errors) {
super(errors); super(conventionService, errors);
this.messageSource = messageSource; this.messageSource = messageSource;
this.validatorFactory = validatorFactory;
} }
public boolean supports(Class clazz) { @Override
return DescriptionTemplateTypePersist.class.equals(clazz); protected Class<DescriptionTemplateTypePersist> modelClass() {
return DescriptionTemplateTypePersist.class;
} }
public void validate(Object obj, Errors e) { @Override
e.rejectValue("name", "negativevalue", messageSource.getMessage("General_ItemNotFound", new Object[]{"aaa", Description.class.getSimpleName()}, LocaleContextHolder.getLocale())); protected List<Specification> specifications(DescriptionTemplateTypePersist item) {
DescriptionTemplateTypePersist p = (DescriptionTemplateTypePersist) obj; return Arrays.asList(
try { this.spec()
e.pushNestedPath("obj"); .iff(() -> this.isValidGuid(item.getId()))
ValidationUtils.invokeValidator(descriptionTemplateTypePersistValidator, p.getObj(), e); .must(() -> this.isValidHash(item.getHash()))
} finally { .failOn(DescriptionTemplateTypePersist._hash).failWith(messageSource.getMessage("Validation_Required", new Object[]{DescriptionTemplateTypePersist._hash}, LocaleContextHolder.getLocale())),
e.popNestedPath(); this.spec()
} .iff(() -> !this.isValidGuid(item.getId()))
.must(() -> !this.isValidHash(item.getHash()))
.failOn(DescriptionTemplateTypePersist._hash).failWith(messageSource.getMessage("Validation_OverPosting", new Object[]{}, LocaleContextHolder.getLocale())),
for (int i = 0; i < p.getNested().size(); i++) { this.spec()
try { .must(() -> !this.isEmpty(item.getName()))
e.pushNestedPath("nested["+i+"]"); .failOn(DescriptionTemplateTypePersist._name).failWith(messageSource.getMessage("Validation_Required", new Object[]{DescriptionTemplateTypePersist._name}, LocaleContextHolder.getLocale())),
ValidationUtils.invokeValidator(descriptionTemplateTypePersistValidator, p.getObj(), e); this.spec()
} finally { .iff(() -> !this.isEmpty(item.getName()))
e.popNestedPath(); .must(() -> this.lessEqual(item.getName(), DescriptionTemplateTypeEntity._nameLength))
} .failOn(DescriptionTemplateTypePersist._name).failWith(messageSource.getMessage("Validation_MaxLength", new Object[]{DescriptionTemplateTypePersist._name}, LocaleContextHolder.getLocale())),
} this.refSpec()
} .iff(() -> item.getObj() != null)
} .on(DescriptionTemplateTypePersist._obj)
.over(item.getObj())
@Component(DescriptionTemplateTypePersistValidator1.ValidatorName) .using(() -> this.validatorFactory.validator(DescriptionTemplateTypePersistValidator.class)),
public static class DescriptionTemplateTypePersistValidator1 extends BaseValidator { this.navSpec()
.iff(() -> item.getNested() != null)
public static final String ValidatorName = "DescriptionTemplateTypePersistValidator1"; .on(DescriptionTemplateTypePersist._nested)
private final MessageSource messageSource; .over(item.getNested())
.using(() -> this.validatorFactory.validator(DescriptionTemplateTypePersistValidator.class))
public DescriptionTemplateTypePersistValidator1(MessageSource messageSource, ErrorThesaurusProperties errors) { );
super(errors);
this.messageSource = messageSource;
}
public boolean supports(Class clazz) {
return DescriptionTemplateTypePersist.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
e.rejectValue("name", "negativevalue", messageSource.getMessage("General_ItemNotFound", new Object[]{"aaa", Description.class.getSimpleName()}, LocaleContextHolder.getLocale()));
} }
} }

View File

@ -1,30 +1,191 @@
package eu.eudat.controllers.controllerhandler; package eu.eudat.controllers.controllerhandler;
import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.commons.JsonHandlingService;
import gr.cite.tools.exception.MyValidationException; import gr.cite.tools.exception.*;
import gr.cite.tools.logging.LoggerService;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
import java.text.MessageFormat;
import java.util.Map;
@RestControllerAdvice @RestControllerAdvice
@ControllerAdvice @ControllerAdvice
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(GlobalExceptionHandler.class));
private final ErrorThesaurusProperties errors; private final JsonHandlingService jsonHandlingService;
public GlobalExceptionHandler(ErrorThesaurusProperties errors) { public GlobalExceptionHandler(JsonHandlingService jsonHandlingService) {
this.errors = errors; this.jsonHandlingService = jsonHandlingService;
} }
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public ResponseEntity<?> handleUnexpectedErrors(Exception e, WebRequest request) throws Exception { public ResponseEntity<?> handleUnexpectedErrors(Exception exception, WebRequest request) throws Exception {
if (e instanceof MyValidationException argumentNotValidException) { HandledException handled = this.handleException(exception, request);
return new ResponseEntity<>(argumentNotValidException.getErrors(), HttpStatus.BAD_REQUEST); this.log(handled.getLevel(), exception, MessageFormat.format("returning code {0} and payload {1}", handled.getStatusCode(), handled.getMessage()));
} return new ResponseEntity<>(handled.getMessage(), handled.getStatusCode());
else {
throw e;
} }
public void log(System.Logger.Level level, Exception e, String message) {
if (level != null) {
switch (level) {
case TRACE:
logger.trace(message, e);
break;
case DEBUG:
logger.debug(message, e);
break;
case INFO:
logger.info(message, e);
break;
case WARNING:
logger.warn(message, e);
break;
case ERROR:
logger.error(message, e);
break;
}
}
}
public HandledException handleException(Exception exception, WebRequest request) throws Exception {
HttpStatus statusCode;
Map<String, Object> result;
System.Logger.Level logLevel;
switch (exception){
case MyNotFoundException myNotFoundException -> {
logLevel = System.Logger.Level.DEBUG;
statusCode = HttpStatus.NOT_FOUND;
int code = myNotFoundException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myNotFoundException.getMessage())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myNotFoundException.getMessage())
);
}
}
case MyUnauthorizedException myUnauthorizedException -> {
logLevel = System.Logger.Level.DEBUG;
statusCode = HttpStatus.UNAUTHORIZED;
int code = myUnauthorizedException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myUnauthorizedException.getMessage())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myUnauthorizedException.getMessage())
);
}
}
case MyForbiddenException myForbiddenException -> {
logLevel = System.Logger.Level.DEBUG;
statusCode = HttpStatus.FORBIDDEN;
int code = myForbiddenException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myForbiddenException.getMessage())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myForbiddenException.getMessage())
);
}
}
case MyValidationException myValidationException -> {
logLevel = System.Logger.Level.DEBUG;
statusCode = HttpStatus.BAD_REQUEST;
int code = myValidationException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myValidationException.getMessage()),
Map.entry("message", myValidationException.getErrors())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myValidationException.getMessage()),
Map.entry("message", myValidationException.getErrors())
);
}
}
case MyApplicationException myApplicationException -> {
logLevel = System.Logger.Level.ERROR;
statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
int code = myApplicationException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myApplicationException.getMessage())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myApplicationException.getMessage())
);
}
}
default -> {
logLevel = System.Logger.Level.ERROR;
statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
result = Map.ofEntries(
Map.entry("error", "System error")
);
}
};
String serialization = this.jsonHandlingService.toJsonSafe(result);
return new HandledException(statusCode, serialization, logLevel);
}
public static class HandledException{
public HttpStatus statusCode;
public String message;
public System.Logger.Level level;
public HandledException(HttpStatus statusCode, String message, System.Logger.Level level) {
this.statusCode = statusCode;
this.message = message;
this.level = level;
}
public HttpStatus getStatusCode() {
return statusCode;
}
public void setStatusCode(HttpStatus statusCode) {
this.statusCode = statusCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public System.Logger.Level getLevel() {
return level;
}
public void setLevel(System.Logger.Level level) {
this.level = level;
}
} }
} }

View File

@ -1,10 +1,9 @@
package eu.eudat.controllers.controllerhandler; package eu.eudat.controllers.controllerhandler;
import eu.eudat.commons.validation.BaseValidator; import eu.eudat.commons.validation.Validator;
import eu.eudat.commons.validation.ValidatorFactory;
import eu.eudat.commons.validation.ValidationFilterAnnotation; import eu.eudat.commons.validation.ValidationFilterAnnotation;
import eu.eudat.logic.services.ApiContext;
import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyApplicationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
@ -19,22 +18,28 @@ import java.util.Objects;
@ControllerAdvice @ControllerAdvice
@RestControllerAdvice @RestControllerAdvice
public class ValidatorRequestBodyAdvice implements RequestBodyAdvice { public class ValidatorRequestBodyAdvice implements RequestBodyAdvice {
@Autowired private final ValidatorFactory validatorFactory;
private ApiContext apiContext;
public ValidatorRequestBodyAdvice(ValidatorFactory validatorFactory) {
this.validatorFactory = validatorFactory;
}
@Override @Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) { Class<? extends HttpMessageConverter<?>> converterType) {
if (parameter.getMethod() != null) { if (parameter.getMethod() != null) {
ValidationFilterAnnotation annotation = parameter.getMethod().getAnnotation((ValidationFilterAnnotation.class)); ValidationFilterAnnotation[] annotations = parameter.getMethod().getAnnotationsByType((ValidationFilterAnnotation.class));
if (annotation == null || !Objects.equals(parameter.getParameterName(), annotation.argumentName())) return body; if (annotations == null) return body;
for (ValidationFilterAnnotation annotation : annotations){
if (!Objects.equals(parameter.getParameterName(), annotation.argumentName())) continue;
BaseValidator validator = this.apiContext.getOperationsContext().getApplicationContext().getBean(annotation.validator(), BaseValidator.class); Validator validator = validatorFactory.validator(annotation.validator());
if (validator == null) throw new MyApplicationException("validator not provided"); if (validator == null) throw new MyApplicationException("validator not provided");
validator.validateForce(body); validator.validateForce(body);
} }
}
return body; return body;
} }
@ -44,8 +49,8 @@ public class ValidatorRequestBodyAdvice implements RequestBodyAdvice {
} }
@Override @Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { public boolean supports(MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true; return parameter.getMethod() != null && parameter.getMethod().isAnnotationPresent((ValidationFilterAnnotation.class));
} }
@Override @Override

View File

@ -17,3 +17,6 @@ validation.largerthanmax=Value must be less than {value}
validation.invalidid=Not valid id validation.invalidid=Not valid id
General_ItemNotFound=Item {0} of type {1} not found General_ItemNotFound=Item {0} of type {1} not found
Validation_Required={0} is required Validation_Required={0} is required
Validation_OverPosting=Too much info
Validation_MaxLength={0} too long
Validation_UnexpectedValue=Unexpected value in field {0}