diff --git a/CHANGELOG.md b/CHANGELOG.md
index 568ad27285..41303ce101 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Add iconStyle + onClick option and story shot for icon component ([#1100](https://github.com/scm-manager/scm-manager/pull/1100))
- Making WebElements (Servlet or Filter) optional by using the `@Requires` annotation ([#1101](https://github.com/scm-manager/scm-manager/pull/1101))
+- Add class to manually validate rest data transfer objects with javax validation annotations ([#1114](https://github.com/scm-manager/scm-manager/pull/1114))
### Changed
- Removed the `requires` attribute on the `@Extension` annotation and instead create a new `@Requires` annotation ([#1097](https://github.com/scm-manager/scm-manager/pull/1097))
diff --git a/scm-core/pom.xml b/scm-core/pom.xml
index ac86a33f4d..5ba07696a4 100644
--- a/scm-core/pom.xml
+++ b/scm-core/pom.xml
@@ -194,6 +194,20 @@
hibernate-validator
+
+ javax.el
+ javax.el-api
+ 3.0.0
+ test
+
+
+
+ org.glassfish
+ javax.el
+ 3.0.1-b11
+ test
+
+
diff --git a/scm-core/src/main/java/sonia/scm/web/api/DtoValidator.java b/scm-core/src/main/java/sonia/scm/web/api/DtoValidator.java
new file mode 100644
index 0000000000..2b81fe6c62
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/web/api/DtoValidator.java
@@ -0,0 +1,47 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020-present Cloudogu GmbH and Contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package sonia.scm.web.api;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+import java.util.Set;
+
+public final class DtoValidator {
+
+ private DtoValidator() {
+ }
+
+ public static void validate(Object configuration) {
+ ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ Validator validator = factory.getValidator();
+ Set> violations = validator.validate(configuration);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+ }
+}
diff --git a/scm-core/src/test/java/sonia/scm/web/api/DtoValidatorTest.java b/scm-core/src/test/java/sonia/scm/web/api/DtoValidatorTest.java
new file mode 100644
index 0000000000..f3370bd252
--- /dev/null
+++ b/scm-core/src/test/java/sonia/scm/web/api/DtoValidatorTest.java
@@ -0,0 +1,59 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020-present Cloudogu GmbH and Contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package sonia.scm.web.api;
+
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ValidationException;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class DtoValidatorTest {
+
+ @Test
+ void shouldValidateInvalidBean() {
+ assertThrows(
+ ValidationException.class,
+ () -> DtoValidator.validate(new AnyQuestion(43))
+ );
+ }
+
+ @Test
+ void shouldValidateValidBean() {
+ DtoValidator.validate(new AnyQuestion(42));
+ }
+
+ static class AnyQuestion {
+ @Min(42)
+ @Max(42)
+ int answer;
+
+ public AnyQuestion(int answer) {
+ this.answer = answer;
+ }
+ }
+}
diff --git a/scm-core/src/test/resources/META-INF/validation.xml b/scm-core/src/test/resources/META-INF/validation.xml
new file mode 100644
index 0000000000..521ef2b195
--- /dev/null
+++ b/scm-core/src/test/resources/META-INF/validation.xml
@@ -0,0 +1,34 @@
+
+
+
+ org.hibernate.validator.parameternameprovider.ReflectionParameterNameProvider
+
+
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/ResteasyValidationExceptionMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/JavaxValidationExceptionMapper.java
similarity index 83%
rename from scm-webapp/src/main/java/sonia/scm/api/v2/ResteasyValidationExceptionMapper.java
rename to scm-webapp/src/main/java/sonia/scm/api/v2/JavaxValidationExceptionMapper.java
index 48eea0a5d4..43f6be6e14 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/v2/ResteasyValidationExceptionMapper.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/JavaxValidationExceptionMapper.java
@@ -21,30 +21,30 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-
+
package sonia.scm.api.v2;
-import org.jboss.resteasy.api.validation.ResteasyViolationException;
import sonia.scm.api.v2.resources.ResteasyViolationExceptionToErrorDtoMapper;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
+import javax.validation.ConstraintViolationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
@Provider
-public class ResteasyValidationExceptionMapper implements ExceptionMapper {
+public class JavaxValidationExceptionMapper implements ExceptionMapper {
private final ResteasyViolationExceptionToErrorDtoMapper mapper;
@Inject
- public ResteasyValidationExceptionMapper(ResteasyViolationExceptionToErrorDtoMapper mapper) {
+ public JavaxValidationExceptionMapper(ResteasyViolationExceptionToErrorDtoMapper mapper) {
this.mapper = mapper;
}
@Override
- public Response toResponse(ResteasyViolationException exception) {
+ public Response toResponse(ConstraintViolationException exception) {
return Response
.status(Response.Status.BAD_REQUEST)
.type(VndMediaType.ERROR_TYPE)
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResteasyViolationExceptionToErrorDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResteasyViolationExceptionToErrorDtoMapper.java
index 1c726489f9..e94bd57503 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResteasyViolationExceptionToErrorDtoMapper.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResteasyViolationExceptionToErrorDtoMapper.java
@@ -21,10 +21,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-
+
package sonia.scm.api.v2.resources;
-import org.jboss.resteasy.api.validation.ResteasyViolationException;
import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@@ -32,6 +31,7 @@ import org.mapstruct.MappingTarget;
import org.slf4j.MDC;
import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;
@@ -42,7 +42,8 @@ public abstract class ResteasyViolationExceptionToErrorDtoMapper {
@Mapping(target = "transactionId", ignore = true)
@Mapping(target = "context", ignore = true)
@Mapping(target = "url", ignore = true)
- public abstract ErrorDto map(ResteasyViolationException exception);
+ @Mapping(target = "violations", ignore = true)
+ public abstract ErrorDto map(ConstraintViolationException exception);
@AfterMapping
void setTransactionId(@MappingTarget ErrorDto dto) {
@@ -50,7 +51,7 @@ public abstract class ResteasyViolationExceptionToErrorDtoMapper {
}
@AfterMapping
- void mapViolations(ResteasyViolationException exception, @MappingTarget ErrorDto dto) {
+ void mapViolations(ConstraintViolationException exception, @MappingTarget ErrorDto dto) {
List violations =
exception.getConstraintViolations()
.stream()