From 3ab4f766edc972da40ce087b67b4b75a0a825df2 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Fri, 19 Apr 2024 13:40:29 +0200 Subject: [PATCH] Throw exception if lazy validation processing detects any errors --- .../github/joschi/jadconfig/JadConfig.java | 16 ++++-- .../jadconfig/LazyValidationException.java | 39 +++++++++++++ .../JadConfigLazyProcessingTest.java | 55 ++++++++++--------- .../testbeans/ValidatedConfigurationBean.java | 3 +- 4 files changed, 79 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/github/joschi/jadconfig/LazyValidationException.java diff --git a/src/main/java/com/github/joschi/jadconfig/JadConfig.java b/src/main/java/com/github/joschi/jadconfig/JadConfig.java index 1ae2c2d5..6bd0a195 100644 --- a/src/main/java/com/github/joschi/jadconfig/JadConfig.java +++ b/src/main/java/com/github/joschi/jadconfig/JadConfig.java @@ -107,14 +107,18 @@ public void process() throws RepositoryException, ValidationException { /** * Processes the configuration provided by the configured {@link Repository} and filling the provided configuration * beans. - * - * Instead of stopping processing on first encountered exception, tries to collect all validation problems and return them in single response, - * allowing identifying many problems at once. - * - * @return Response object, containing encountered problems if processing was not successful. + *

+ * Instead of stopping processing on first encountered exception, tries to collect all validation problems and in + * case of any problems aggregate them all into single exception, listing all the field and validation issues. */ - public ProcessingResponse processFailingLazily() throws RepositoryException { + public void processFailingLazily() throws RepositoryException, LazyValidationException { + final ProcessingResponse result = doProcessFailingLazily(); + if (!result.isSuccess()) { + throw new LazyValidationException(result); + } + } + ProcessingResponse doProcessFailingLazily() throws RepositoryException { ProcessingResponse response = new ProcessingResponse(); for (Repository repository : repositories) { diff --git a/src/main/java/com/github/joschi/jadconfig/LazyValidationException.java b/src/main/java/com/github/joschi/jadconfig/LazyValidationException.java new file mode 100644 index 00000000..146655ba --- /dev/null +++ b/src/main/java/com/github/joschi/jadconfig/LazyValidationException.java @@ -0,0 +1,39 @@ +package com.github.joschi.jadconfig; + +import com.github.joschi.jadconfig.response.ProcessingOutcome; +import com.github.joschi.jadconfig.response.ProcessingResponse; + +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Stream; + +public class LazyValidationException extends ValidationException { + private final ProcessingResponse processingResponse; + + public LazyValidationException(ProcessingResponse result) { + super(toMessage(result)); + this.processingResponse = result; + } + + private static String toMessage(ProcessingResponse result) { + final List stringBuilder = new LinkedList<>(); + stringBuilder.add("Following errors ocurred during configuration processing:"); + result.getOutcomes().stream() + .filter(ProcessingOutcome::hasProblems) + .flatMap(processingOutcome -> Stream.concat( + processingOutcome.getFieldProcessingProblems().values().stream().map(e -> toMessage(processingOutcome, e)), + processingOutcome.getValidationMethodsProblems().values().stream().map(e -> toMessage(processingOutcome, e)) + )).forEach(stringBuilder::add); + return String.join("\n", stringBuilder); + } + + private static String toMessage(ProcessingOutcome processingOutcome, Exception exception) { + // TODO: should we distinct between field processing problem and validation method? + // TODO: should we include class name of the bean or not? + return exception.getMessage(); + } + + public ProcessingResponse getProcessingResponse() { + return processingResponse; + } +} diff --git a/src/test/java/com/github/joschi/jadconfig/JadConfigLazyProcessingTest.java b/src/test/java/com/github/joschi/jadconfig/JadConfigLazyProcessingTest.java index 226436bf..086301ba 100644 --- a/src/test/java/com/github/joschi/jadconfig/JadConfigLazyProcessingTest.java +++ b/src/test/java/com/github/joschi/jadconfig/JadConfigLazyProcessingTest.java @@ -4,6 +4,7 @@ import com.github.joschi.jadconfig.response.ProcessingOutcome; import com.github.joschi.jadconfig.response.ProcessingResponse; import com.github.joschi.jadconfig.testbeans.ValidatedConfigurationBean; +import org.junit.Assert; import org.junit.Test; import java.util.HashMap; @@ -13,35 +14,37 @@ public class JadConfigLazyProcessingTest { - private JadConfig jadConfig; - private Repository repository; - - @Test public void testProcess() throws RepositoryException { HashMap properties = new HashMap<>(); - properties.put("test.byte","1"); - properties.put("test.short","2"); - properties.put("test.integer","-3");//negative, smaller than test.short - properties.put("test.integer.port","70000"); //bigger than allowed port - properties.put("test.long","4"); - properties.put("test.string","Test"); - repository = new InMemoryRepository(properties); + properties.put("test.byte", "1"); + properties.put("test.short", "2"); + properties.put("test.integer", "-3");//negative, smaller than test.short + properties.put("test.integer.port", "70000"); //bigger than allowed port + properties.put("test.long", "4"); + properties.put("test.string", "Test"); + Repository repository = new InMemoryRepository(properties); ValidatedConfigurationBean configurationBean = new ValidatedConfigurationBean(); - jadConfig = new JadConfig(repository, configurationBean); - - ProcessingResponse response = jadConfig.processFailingLazily(); - assertFalse(response.isSuccess()); - assertEquals(1, response.getOutcomes().size()); - ProcessingOutcome processingOutcome = response.getOutcomes().get(0); - assertEquals(configurationBean, processingOutcome.getConfigurationBean()); - Map fieldProcessingProblems = processingOutcome.getFieldProcessingProblems(); - assertEquals(2, fieldProcessingProblems.size()); - assertTrue(fieldProcessingProblems.containsKey("test.integer")); - assertTrue(fieldProcessingProblems.containsKey("test.integer.port")); - - Map validationMethodsProblems = processingOutcome.getValidationMethodsProblems(); - assertEquals(1, validationMethodsProblems.size()); - assertTrue(validationMethodsProblems.containsKey("validate")); + JadConfig jadConfig = new JadConfig(repository, configurationBean); + try { + jadConfig.processFailingLazily(); + Assert.fail("Should throw an exception!"); + } catch (LazyValidationException e) { + final ProcessingResponse response = e.getProcessingResponse(); + assertFalse(response.isSuccess()); + assertEquals(1, response.getOutcomes().size()); + ProcessingOutcome processingOutcome = response.getOutcomes().get(0); + assertEquals(configurationBean, processingOutcome.getConfigurationBean()); + Map fieldProcessingProblems = processingOutcome.getFieldProcessingProblems(); + assertEquals(2, fieldProcessingProblems.size()); + assertTrue(fieldProcessingProblems.containsKey("test.integer")); + assertTrue(fieldProcessingProblems.containsKey("test.integer.port")); + + Map validationMethodsProblems = processingOutcome.getValidationMethodsProblems(); + assertEquals(1, validationMethodsProblems.size()); + assertTrue(validationMethodsProblems.containsKey("myCustomValidatorMethod")); + } + + } } diff --git a/src/test/java/com/github/joschi/jadconfig/testbeans/ValidatedConfigurationBean.java b/src/test/java/com/github/joschi/jadconfig/testbeans/ValidatedConfigurationBean.java index dda6046b..b13ad10e 100644 --- a/src/test/java/com/github/joschi/jadconfig/testbeans/ValidatedConfigurationBean.java +++ b/src/test/java/com/github/joschi/jadconfig/testbeans/ValidatedConfigurationBean.java @@ -7,7 +7,6 @@ import com.github.joschi.jadconfig.validators.NoValidator; import com.github.joschi.jadconfig.validators.PositiveIntegerValidator; import com.github.joschi.jadconfig.validators.PositiveLongValidator; -import com.github.joschi.jadconfig.validators.PositiveSizeValidator; public class ValidatedConfigurationBean { @@ -54,7 +53,7 @@ public long getMyLong() { } @ValidatorMethod - public void validate() throws ValidationException { + public void myCustomValidatorMethod() throws ValidationException { if (!"Test".equals(myString)) { throw new ValidationException("BOOM");