-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
371 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>io.avaje</groupId> | ||
<artifactId>avaje-validator-parent</artifactId> | ||
<version>1.5-SNAPSHOT</version> | ||
</parent> | ||
<artifactId>avaje-validation-spring-starter</artifactId> | ||
|
||
<dependencyManagement> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-dependencies</artifactId> | ||
<version>3.3.0</version> | ||
<type>pom</type> | ||
<scope>import</scope> | ||
</dependency> | ||
</dependencies> | ||
</dependencyManagement> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.avaje</groupId> | ||
<artifactId>avaje-validator</artifactId> | ||
<version>${project.version}</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>jakarta.inject</groupId> | ||
<artifactId>jakarta.inject-api</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-aop</artifactId> | ||
<exclusions> | ||
<exclusion> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-logging</artifactId> | ||
</exclusion> | ||
<exclusion> | ||
<groupId>org.yaml</groupId> | ||
<artifactId>snakeyaml</artifactId> | ||
</exclusion> | ||
<exclusion> | ||
<groupId>io.micrometer</groupId> | ||
<artifactId>micrometer-observation</artifactId> | ||
</exclusion> | ||
<exclusion> | ||
<groupId>org.springframework</groupId> | ||
<artifactId>spring-core</artifactId> | ||
</exclusion> | ||
<exclusion> | ||
<groupId>jakarta.annotation</groupId> | ||
<artifactId>jakarta.annotation-api</artifactId> | ||
</exclusion> | ||
</exclusions> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.avaje</groupId> | ||
<artifactId>avaje-validator-constraints</artifactId> | ||
<version>${project.version}</version> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-test</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
21 changes: 21 additions & 0 deletions
21
...er/src/main/java/io/avaje/validation/spring/aspect/MethodValidationAutoConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package io.avaje.validation.spring.aspect; | ||
|
||
import java.util.List; | ||
|
||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.EnableAspectJAutoProxy; | ||
|
||
import io.avaje.validation.Validator; | ||
import io.avaje.validation.adapter.MethodAdapterProvider; | ||
|
||
@Configuration | ||
@EnableAspectJAutoProxy | ||
@ConditionalOnBean({Validator.class, MethodAdapterProvider.class}) | ||
public class MethodValidationAutoConfiguration { | ||
|
||
public SpringAOPMethodValidator validator( | ||
Validator validator, List<MethodAdapterProvider> providers) throws Exception { | ||
return new SpringAOPMethodValidator(validator, providers); | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
...ator-spring-starter/src/main/java/io/avaje/validation/spring/aspect/ParamInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package io.avaje.validation.spring.aspect; | ||
|
||
import java.util.List; | ||
import java.util.Locale; | ||
|
||
import org.aspectj.lang.ProceedingJoinPoint; | ||
|
||
import io.avaje.validation.adapter.ValidationAdapter; | ||
import io.avaje.validation.adapter.ValidationContext; | ||
|
||
final class ParamInterceptor { | ||
|
||
private final Locale locale; | ||
private final boolean throwOnParamFailure; | ||
private final List<ValidationAdapter<Object>> paramValidationAdapter; | ||
private final ValidationAdapter<Object> returnValidationAdapter; | ||
private final ValidationContext ctx; | ||
private final ValidationAdapter<Object[]> crossParamAdapter; | ||
|
||
public ParamInterceptor( | ||
Locale locale, | ||
boolean throwOnParamFailure, | ||
ValidationContext ctx, | ||
List<ValidationAdapter<Object>> paramValidationAdapter, | ||
ValidationAdapter<Object> returnValidationAdapter, | ||
ValidationAdapter<Object[]> crossParamAdapter) { | ||
this.locale = locale; | ||
this.throwOnParamFailure = throwOnParamFailure; | ||
this.paramValidationAdapter = paramValidationAdapter; | ||
this.returnValidationAdapter = returnValidationAdapter; | ||
this.ctx = ctx; | ||
this.crossParamAdapter = crossParamAdapter; | ||
} | ||
|
||
public void invoke(ProceedingJoinPoint invocation) throws Throwable { | ||
|
||
final var args = invocation.getArgs(); | ||
final var req = ctx.request(locale, List.of()); | ||
var i = 0; | ||
for (final var adapter : paramValidationAdapter) { | ||
final Object object = args[i]; | ||
adapter.validate(object, req); | ||
++i; | ||
} | ||
crossParamAdapter.validate(args, req); | ||
if (throwOnParamFailure) { | ||
req.throwWithViolations(); | ||
} | ||
returnValidationAdapter.validate(invocation.proceed(), req); | ||
req.throwWithViolations(); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
...ing-starter/src/main/java/io/avaje/validation/spring/aspect/SpringAOPMethodValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package io.avaje.validation.spring.aspect; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Locale; | ||
import java.util.Map; | ||
|
||
import org.aspectj.lang.ProceedingJoinPoint; | ||
import org.aspectj.lang.annotation.Around; | ||
import org.aspectj.lang.annotation.Aspect; | ||
import org.aspectj.lang.reflect.MethodSignature; | ||
|
||
import io.avaje.validation.ValidMethod; | ||
import io.avaje.validation.Validator; | ||
import io.avaje.validation.adapter.MethodAdapterProvider; | ||
|
||
@Aspect | ||
public class SpringAOPMethodValidator { | ||
|
||
private final Map<Method, ParamInterceptor> interceptorMap = new HashMap<>(); | ||
|
||
public SpringAOPMethodValidator(Validator validator, List<MethodAdapterProvider> providers) | ||
throws Exception { | ||
var ctx = validator.context(); | ||
for (var provider : providers) { | ||
|
||
var method = provider.method(); | ||
ValidMethod validMethod = method.getAnnotation(ValidMethod.class); | ||
final var localeStr = validMethod.locale(); | ||
final Locale locale = localeStr.isBlank() ? null : Locale.forLanguageTag(localeStr); | ||
var paramValidationAdapter = provider.paramAdapters(ctx); | ||
var returnValidationAdapter = provider.returnAdapter(ctx); | ||
var crossParamAdapter = provider.crossParamAdapter(ctx); | ||
|
||
interceptorMap.put( | ||
method, | ||
new ParamInterceptor( | ||
locale, | ||
validMethod.throwOnParamFailure(), | ||
ctx, | ||
paramValidationAdapter, | ||
returnValidationAdapter, | ||
crossParamAdapter)); | ||
} | ||
} | ||
|
||
@Around("@annotation(io.avaje.validation.ValidMethod)") | ||
public void interceptor(ProceedingJoinPoint joinPoint) throws Throwable { | ||
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); | ||
var methodValidator = interceptorMap.get(signature.getMethod()); | ||
methodValidator.invoke(joinPoint); | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
...r/src/main/java/io/avaje/validation/spring/validator/AvajeValidatorAutoConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package io.avaje.validation.spring.validator; | ||
|
||
import java.time.Duration; | ||
import java.time.temporal.ChronoUnit; | ||
import java.util.Arrays; | ||
import java.util.Locale; | ||
import java.util.Optional; | ||
|
||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
import io.avaje.validation.Validator; | ||
|
||
/** Autoconfiguration of Avaje Validator. */ | ||
@Configuration | ||
public class AvajeValidatorAutoConfiguration { | ||
|
||
@Bean | ||
@ConditionalOnMissingBean | ||
Validator validator( | ||
@Value("${validation.failFast:false}") boolean failFast, | ||
@Value("${validation.resourcebundle.names:#{null}}") Optional<String> resourceBundleNames, | ||
@Value("${validation.locale.default:#{null}}") Optional<String> defaultLocal, | ||
@Value("${validation.locale.addedLocales:#{null}}") Optional<String> addedLocales, | ||
@Value("${validation.temporal.tolerance.value:#{null}}") Optional<String> temporalTolerance, | ||
@Value("${validation.temporal.tolerance.chronoUnit:MILLIS}") ChronoUnit chronoUnit) { | ||
final var validator = Validator.builder().failFast(failFast); | ||
|
||
resourceBundleNames.map(s -> s.split(",")).ifPresent(validator::addResourceBundles); | ||
defaultLocal.map(Locale::forLanguageTag).ifPresent(validator::setDefaultLocale); | ||
|
||
addedLocales.stream() | ||
.flatMap(s -> Arrays.stream(s.split(","))) | ||
.map(Locale::forLanguageTag) | ||
.forEach(validator::addLocales); | ||
|
||
temporalTolerance | ||
.map(Long::valueOf) | ||
.ifPresent( | ||
duration -> { | ||
final var unit = chronoUnit; | ||
validator.temporalTolerance(Duration.of(duration, unit)); | ||
}); | ||
return validator.build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module io.avaje.validation.spring { | ||
|
||
exports io.avaje.validation.spring.aspect; | ||
exports io.avaje.validation.spring.validator; | ||
|
||
requires transitive io.avaje.validation; | ||
requires transitive jakarta.inject; | ||
requires transitive org.aspectj.weaver; | ||
requires transitive spring.beans; | ||
requires transitive spring.context; | ||
requires transitive spring.boot.autoconfigure; | ||
|
||
} |
2 changes: 2 additions & 0 deletions
2
...esources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
io.avaje.validation.spring.aspect.MethodValidationAutoConfiguration | ||
io.avaje.validation.spring.validator.AvajeValidatorAutoConfiguration |
43 changes: 43 additions & 0 deletions
43
...-spring-starter/src/test/java/io/avaje/validation/spring/aspect/MethodValidationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package io.avaje.validation.spring.aspect; | ||
|
||
import static org.assertj.core.api.Assertions.assertThatNoException; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
||
import java.util.List; | ||
|
||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
|
||
import io.avaje.validation.ConstraintViolationException; | ||
import io.avaje.validation.Validator; | ||
import io.avaje.validation.spring.validator.AvajeValidatorAutoConfiguration; | ||
import jakarta.inject.Inject; | ||
|
||
@SpringBootTest( | ||
classes = { | ||
AvajeValidatorAutoConfiguration.class, | ||
MethodValidationAutoConfiguration.class, | ||
SpringAOPMethodValidator.class, | ||
TestParamProvider.class, | ||
ValidMethodClass.class, | ||
Validator.class | ||
}) | ||
class MethodValidationTest { | ||
|
||
@Inject private ValidMethodClass test; | ||
|
||
@BeforeAll | ||
static void setUpBeforeClass() throws Exception {} | ||
|
||
@Test | ||
void test() { | ||
assertThatNoException().isThrownBy(() -> test.test(List.of(""), 1, null)); | ||
} | ||
|
||
@Test | ||
void invalid() { | ||
assertThatThrownBy(() -> test.test(null, 0, null)) | ||
.isInstanceOf(ConstraintViolationException.class); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
...tor-spring-starter/src/test/java/io/avaje/validation/spring/aspect/TestParamProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package io.avaje.validation.spring.aspect; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import org.springframework.stereotype.Component; | ||
|
||
import io.avaje.validation.adapter.MethodAdapterProvider; | ||
import io.avaje.validation.adapter.ValidationAdapter; | ||
import io.avaje.validation.adapter.ValidationContext; | ||
import io.avaje.validation.constraints.NotEmpty; | ||
import io.avaje.validation.constraints.NotNull; | ||
import io.avaje.validation.constraints.Positive; | ||
import jakarta.inject.Singleton; | ||
|
||
@Singleton | ||
public final class TestParamProvider implements MethodAdapterProvider { | ||
|
||
@Override | ||
public Method method() throws Exception { | ||
|
||
return ValidMethodClass.class.getDeclaredMethod("test", List.class, int.class, String.class); | ||
} | ||
|
||
@Override | ||
public List<ValidationAdapter<Object>> paramAdapters(ValidationContext ctx) { | ||
return List.of( | ||
ctx.<Object>adapter( | ||
NotEmpty.class, Map.of("groups", Set.of(), "message", "{avaje.NotEmpty.message}")) | ||
.list() | ||
.andThenMulti( | ||
ctx.adapter( | ||
NotNull.class, | ||
Map.of("groups", Set.of(), "message", "{avaje.NotEmpty.message}"))), | ||
ctx.<Object>adapter( | ||
Positive.class, Map.of("groups", Set.of(), "message", "{avaje.Positive.message}")), | ||
ctx.noop()); | ||
} | ||
} |
Oops, something went wrong.