Skip to content

Commit daca727

Browse files
jooby-hbv module draft
1 parent c61e7d8 commit daca727

13 files changed

Lines changed: 230 additions & 8 deletions

File tree

jooby/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@
4949
<artifactId>jakarta.inject-api</artifactId>
5050
</dependency>
5151

52+
<!-- jakarta.validation -->
53+
<dependency>
54+
<groupId>jakarta.validation</groupId>
55+
<artifactId>jakarta.validation-api</artifactId>
56+
</dependency>
57+
5258
<!-- config -->
5359
<dependency>
5460
<groupId>com.typesafe</groupId>

jooby/src/main/java/io/jooby/DefaultContext.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@
2020
import java.nio.charset.StandardCharsets;
2121
import java.nio.file.Path;
2222
import java.time.Instant;
23-
import java.util.Date;
24-
import java.util.List;
25-
import java.util.Map;
26-
import java.util.Objects;
27-
import java.util.Optional;
23+
import java.util.*;
2824
import java.util.stream.Collectors;
2925

26+
import jakarta.validation.ConstraintViolation;
27+
import jakarta.validation.ConstraintViolationException;
28+
import jakarta.validation.Validator;
3029
import org.slf4j.Logger;
3130

3231
import edu.umd.cs.findbugs.annotations.NonNull;
@@ -417,7 +416,20 @@ default boolean isSecure() {
417416
T result = ValueConverters.convert(body(), type, getRouter());
418417
return result;
419418
}
420-
return (T) decoder(contentType).decode(this, type);
419+
T object = (T) decoder(contentType).decode(this, type);
420+
421+
MessageValidator messageValidator = getRouter().getMessageValidator();
422+
if (messageValidator != null) {
423+
if (messageValidator.predicate().test(type)) {
424+
Validator validator = messageValidator.validator();
425+
Set<ConstraintViolation<T>> violations = validator.validate(object);
426+
if (!violations.isEmpty()) {
427+
throw new ConstraintViolationException(violations);
428+
}
429+
}
430+
}
431+
return object;
432+
421433
} catch (Exception x) {
422434
throw SneakyThrows.propagate(x);
423435
}

jooby/src/main/java/io/jooby/Jooby.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import java.io.IOException;
1414
import java.lang.reflect.Constructor;
15+
import java.lang.reflect.Type;
1516
import java.nio.file.Files;
1617
import java.nio.file.Path;
1718
import java.nio.file.Paths;
@@ -41,6 +42,7 @@
4142
import java.util.function.Supplier;
4243
import java.util.stream.Collectors;
4344

45+
import jakarta.validation.Validator;
4446
import org.slf4j.Logger;
4547
import org.slf4j.LoggerFactory;
4648

@@ -627,6 +629,19 @@ public Jooby decoder(@NonNull MediaType contentType, @NonNull MessageDecoder dec
627629
return this;
628630
}
629631

632+
@NonNull
633+
@Override
634+
public Router messageValidator(@NonNull Validator validator, @NonNull Predicate<Type> predicate) {
635+
router.messageValidator(validator, predicate);
636+
return this;
637+
}
638+
639+
@Nullable
640+
@Override
641+
public MessageValidator getMessageValidator() {
642+
return router.getMessageValidator();
643+
}
644+
630645
@NonNull @Override
631646
public Jooby encoder(@NonNull MediaType contentType, @NonNull MessageEncoder encoder) {
632647
router.encoder(contentType, encoder);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.jooby;
2+
3+
import jakarta.validation.Validator;
4+
5+
import java.lang.reflect.Type;
6+
import java.util.function.Predicate;
7+
8+
public record MessageValidator(Validator validator, Predicate<Type> predicate) {
9+
}

jooby/src/main/java/io/jooby/Router.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static java.util.Collections.unmodifiableList;
99
import static java.util.Objects.requireNonNull;
1010

11+
import java.lang.reflect.Type;
1112
import java.nio.file.Files;
1213
import java.nio.file.Path;
1314
import java.nio.file.Paths;
@@ -28,6 +29,7 @@
2829
import java.util.stream.IntStream;
2930
import java.util.stream.Stream;
3031

32+
import jakarta.validation.Validator;
3133
import org.slf4j.Logger;
3234

3335
import com.typesafe.config.Config;
@@ -508,6 +510,8 @@ default Object execute(@NonNull Context context) {
508510
*/
509511
@NonNull Router decoder(@NonNull MediaType contentType, @NonNull MessageDecoder decoder);
510512

513+
@NonNull Router messageValidator(@NonNull Validator validator, @NonNull Predicate<Type> predicate);
514+
@Nullable MessageValidator getMessageValidator();
511515
/**
512516
* Returns the worker thread pool. This thread pool is used to run application blocking code.
513517
*

jooby/src/main/java/io/jooby/internal/RouterImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static java.util.Objects.requireNonNull;
99

1010
import java.io.FileNotFoundException;
11+
import java.lang.reflect.Type;
1112
import java.nio.charset.StandardCharsets;
1213
import java.nio.file.NoSuchFileException;
1314
import java.nio.file.Path;
@@ -35,6 +36,7 @@
3536
import java.util.stream.IntStream;
3637
import java.util.stream.Stream;
3738

39+
import jakarta.validation.Validator;
3840
import org.slf4j.Logger;
3941
import org.slf4j.LoggerFactory;
4042

@@ -147,6 +149,8 @@ public Stack executor(Executor executor) {
147149

148150
private Map<String, MessageDecoder> decoders = new HashMap<>();
149151

152+
private MessageValidator messageValidator = null;
153+
150154
private Map<String, Object> attributes = new ConcurrentHashMap<>();
151155

152156
private ServiceRegistry services = new ServiceRegistryImpl();
@@ -368,6 +372,18 @@ public Router decoder(@NonNull MediaType contentType, @NonNull MessageDecoder de
368372
return this;
369373
}
370374

375+
@NonNull
376+
@Override
377+
public Router messageValidator(@NonNull Validator validator, @NonNull Predicate<Type> predicate) {
378+
this.messageValidator = new MessageValidator(validator, predicate);
379+
return this;
380+
}
381+
382+
@Override
383+
public MessageValidator getMessageValidator() {
384+
return messageValidator;
385+
}
386+
371387
@NonNull @Override
372388
public Executor getWorker() {
373389
return worker;

jooby/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* True core deps
2323
*/
2424
requires jakarta.inject;
25+
requires jakarta.validation;
2526
requires org.slf4j;
2627
requires static com.github.spotbugs.annotations;
2728
requires typesafe.config;

modules/jooby-hbv/pom.xml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
6+
<parent>
7+
<groupId>io.jooby</groupId>
8+
<artifactId>modules</artifactId>
9+
<version>3.3.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<modelVersion>4.0.0</modelVersion>
13+
<artifactId>jooby-hbv</artifactId>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>io.jooby</groupId>
18+
<artifactId>jooby</artifactId>
19+
<version>${jooby.version}</version>
20+
</dependency>
21+
22+
<!-- Hibernate Validator -->
23+
<dependency>
24+
<groupId>org.hibernate.validator</groupId>
25+
<artifactId>hibernate-validator</artifactId>
26+
<version>8.0.1.Final</version>
27+
</dependency>
28+
29+
<dependency>
30+
<groupId>jakarta.el</groupId>
31+
<artifactId>jakarta.el-api</artifactId>
32+
<version>5.0.1</version>
33+
</dependency>
34+
35+
<dependency>
36+
<groupId>org.glassfish.expressly</groupId>
37+
<artifactId>expressly</artifactId>
38+
<version>5.0.0</version>
39+
</dependency>
40+
41+
<!-- Test dependencies -->
42+
<dependency>
43+
<groupId>org.junit.jupiter</groupId>
44+
<artifactId>junit-jupiter-engine</artifactId>
45+
<scope>test</scope>
46+
</dependency>
47+
48+
<dependency>
49+
<groupId>org.jacoco</groupId>
50+
<artifactId>org.jacoco.agent</artifactId>
51+
<classifier>runtime</classifier>
52+
<scope>test</scope>
53+
</dependency>
54+
55+
<dependency>
56+
<groupId>org.mockito</groupId>
57+
<artifactId>mockito-core</artifactId>
58+
<scope>test</scope>
59+
</dependency>
60+
61+
</dependencies>
62+
</project>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.hbv;
7+
8+
9+
import edu.umd.cs.findbugs.annotations.NonNull;
10+
import io.jooby.Extension;
11+
import io.jooby.Jooby;
12+
import jakarta.validation.Validator;
13+
import jakarta.validation.ValidatorFactory;
14+
import org.hibernate.validator.HibernateValidator;
15+
import org.hibernate.validator.HibernateValidatorConfiguration;
16+
17+
import java.lang.reflect.Type;
18+
import java.util.Set;
19+
import java.util.function.Consumer;
20+
import java.util.function.Predicate;
21+
22+
import static jakarta.validation.Validation.byProvider;
23+
import static java.util.Objects.requireNonNull;
24+
25+
public class HbvModule implements Extension {
26+
27+
private final Predicate<Type> predicate;
28+
private Consumer<HibernateValidatorConfiguration> configurer;
29+
30+
public HbvModule() {
31+
this(none());
32+
}
33+
34+
public HbvModule(Predicate<Type> predicate) {
35+
this.predicate = requireNonNull(predicate, "Predicate is required.");
36+
}
37+
38+
public HbvModule(final Class<?>... classes) {
39+
this.predicate = typeIs(Set.of(classes));
40+
}
41+
42+
public HbvModule doWith(final Consumer<HibernateValidatorConfiguration> configurer) {
43+
this.configurer = requireNonNull(configurer, "Configurer callback is required.");
44+
return this;
45+
}
46+
47+
@Override
48+
public void install(@NonNull Jooby application) {
49+
HibernateValidatorConfiguration cfg = byProvider(HibernateValidator.class).configure();
50+
51+
if (configurer != null) {
52+
configurer.accept(cfg);
53+
}
54+
55+
try (ValidatorFactory factory = cfg.buildValidatorFactory()) {
56+
Validator validator = factory.getValidator();
57+
application.messageValidator(validator, predicate);
58+
application.getServices().put(Validator.class, validator);
59+
}
60+
61+
}
62+
63+
static Predicate<Type> typeIs(final Set<Class<?>> classes) {
64+
return type -> classes.contains((Class<?>) type);
65+
}
66+
67+
static Predicate<Type> none() {
68+
return type -> false;
69+
}
70+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package io.jooby.hbv;

0 commit comments

Comments
 (0)