Skip to content

Commit c9e2028

Browse files
author
Ted Liang
committed
Introduce ConstructorValidatorFactory
1 parent 63e57b0 commit c9e2028

15 files changed

+100
-244
lines changed

src/main/java/org/unbrokendome/jackson/beanvalidation/BeanValidationModule.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.fasterxml.jackson.databind.Module;
88
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
99

10+
import javax.annotation.Nullable;
1011
import javax.validation.ConstraintViolationException;
1112
import javax.validation.ValidatorFactory;
1213
import java.io.IOException;
@@ -17,6 +18,7 @@ public final class BeanValidationModule extends Module {
1718

1819
private final ValidatorFactory validatorFactory;
1920
private final EnumSet<BeanValidationFeature> features;
21+
@Nullable private ConstructorValidatorFactory constructorValidatorFactory;
2022

2123

2224
public BeanValidationModule(ValidatorFactory validatorFactory) {
@@ -58,13 +60,19 @@ public BeanValidationModule disable(BeanValidationFeature feature) {
5860
return this;
5961
}
6062

63+
public BeanValidationModule setConstructorValidatorFactory(@Nullable ConstructorValidatorFactory factory) {
64+
this.constructorValidatorFactory = factory;
65+
return this;
66+
}
67+
6168

6269
@Override
6370
public void setupModule(SetupContext context) {
6471

6572
BeanValidationFeatureSet featureSet = new BeanValidationFeatureSet(features);
6673

67-
context.addBeanDeserializerModifier(new ValidationBeanDeserializerModifier(validatorFactory, featureSet));
74+
context.addBeanDeserializerModifier(new ValidationBeanDeserializerModifier(
75+
validatorFactory, featureSet, constructorValidatorFactory));
6876

6977
context.addDeserializationProblemHandler(new DeserializationProblemHandler() {
7078
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.unbrokendome.jackson.beanvalidation;
2+
3+
import javax.validation.Validator;
4+
import javax.validation.ValidatorFactory;
5+
import java.lang.reflect.Constructor;
6+
7+
public interface ConstructorValidatorFactory {
8+
Validator getValidator(ValidatorFactory validatorFactory, Constructor constructor, Object[] parameterValues);
9+
}

src/main/java/org/unbrokendome/jackson/beanvalidation/ValidatingValueInstantiator.java

+9-15
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@
1616
import javax.validation.ConstraintViolationException;
1717
import javax.validation.ElementKind;
1818
import javax.validation.Path;
19+
import javax.validation.Validator;
1920
import javax.validation.ValidatorFactory;
2021
import javax.validation.executable.ExecutableValidator;
2122
import java.io.IOException;
2223
import java.lang.reflect.Constructor;
23-
import java.lang.reflect.Field;
2424
import java.lang.reflect.Member;
2525
import java.lang.reflect.Method;
2626
import java.util.Collections;
27-
import java.util.HashMap;
2827
import java.util.LinkedHashSet;
2928
import java.util.Map;
3029
import java.util.Set;
@@ -34,16 +33,21 @@ class ValidatingValueInstantiator extends AbstractDelegatingValueInstantiator {
3433

3534
private final ValidatorFactory validatorFactory;
3635
private final BeanValidationFeatureSet features;
36+
private final ConstructorValidatorFactory constructorValidatorFactory;
3737
private boolean validationEnabled = false;
3838

3939

4040
ValidatingValueInstantiator(
4141
StdValueInstantiator delegate, ValidatorFactory validatorFactory,
42-
BeanValidationFeatureSet features
42+
BeanValidationFeatureSet features,
43+
@Nullable ConstructorValidatorFactory constructorValidatorFactory
4344
) {
4445
super(delegate);
4546
this.validatorFactory = validatorFactory;
4647
this.features = features;
48+
this.constructorValidatorFactory = constructorValidatorFactory != null
49+
? constructorValidatorFactory
50+
: (factory, constructor, parameterValues) -> factory.getValidator();
4751
}
4852

4953

@@ -184,21 +188,11 @@ private Set<ConstraintViolation<?>> validateCreatorArgs(
184188
}
185189

186190
Member creatorMember = getWithArgsCreator().getMember();
187-
ExecutableValidator executableValidator = validatorFactory.getValidator().forExecutables();
188191

189192
if (creatorMember instanceof Constructor) {
190-
Map<String, Object> hints = new HashMap<>(args.length);
191193
Constructor constructor = (Constructor) creatorMember;
192-
Field[] declaredFields = constructor.getDeclaringClass().getDeclaredFields();
193-
if (declaredFields.length >= args.length) {
194-
for (int i = 0; i < args.length; i++) {
195-
hints.put(declaredFields[i].getName(), args[i]);
196-
}
197-
}
198-
ValidationContextHolder.hints.set(hints);
199-
Set violations = executableValidator.validateConstructorParameters(constructor, args);
200-
ValidationContextHolder.hints.remove();
201-
return violations;
194+
Validator validator = constructorValidatorFactory.getValidator(validatorFactory, constructor, args);
195+
return validator.forExecutables().validateConstructorParameters(constructor, args);
202196

203197
} else if (creatorMember instanceof Method) {
204198
// Bean validation doesn't support parameter validation for static methods :-(

src/main/java/org/unbrokendome/jackson/beanvalidation/ValidationBeanDeserializerModifier.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.fasterxml.jackson.databind.deser.impl.MethodProperty;
99
import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator;
1010

11+
import javax.annotation.Nullable;
1112
import javax.validation.Validator;
1213
import javax.validation.ValidatorFactory;
1314
import java.util.ArrayList;
@@ -18,11 +19,14 @@ final class ValidationBeanDeserializerModifier extends BeanDeserializerModifier
1819

1920
private final ValidatorFactory validatorFactory;
2021
private final BeanValidationFeatureSet features;
22+
private final ConstructorValidatorFactory constructorValidatorFactory;
2123

2224

23-
ValidationBeanDeserializerModifier(ValidatorFactory validatorFactory, BeanValidationFeatureSet features) {
25+
ValidationBeanDeserializerModifier(ValidatorFactory validatorFactory, BeanValidationFeatureSet features,
26+
@Nullable ConstructorValidatorFactory constructorValidatorFactory) {
2427
this.validatorFactory = validatorFactory;
2528
this.features = features;
29+
this.constructorValidatorFactory = constructorValidatorFactory;
2630
}
2731

2832

@@ -49,7 +53,7 @@ public BeanDeserializerBuilder updateBuilder(
4953
ValueInstantiator valueInstantiator = builder.getValueInstantiator();
5054
if (valueInstantiator instanceof StdValueInstantiator) {
5155
builder.setValueInstantiator(new ValidatingValueInstantiator(
52-
(StdValueInstantiator) valueInstantiator, validatorFactory, features));
56+
(StdValueInstantiator) valueInstantiator, validatorFactory, features, constructorValidatorFactory));
5357
}
5458

5559
return builder;

src/main/java/org/unbrokendome/jackson/beanvalidation/ValidationContextHolder.java

-13
This file was deleted.

src/main/java/org/unbrokendome/jackson/beanvalidation/constraints/NotBlankWhen.java

-42
This file was deleted.

src/main/java/org/unbrokendome/jackson/beanvalidation/constraints/NotBlankWhenValidator.java

-27
This file was deleted.

src/main/java/org/unbrokendome/jackson/beanvalidation/constraints/NotNullWhen.java

-41
This file was deleted.

src/main/java/org/unbrokendome/jackson/beanvalidation/constraints/NotNullWhenValidator.java

-26
This file was deleted.

src/test/kotlin/org/unbrokendome/jackson/beanvalidation/AbstractValidationTest.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ import javax.validation.ConstraintViolationException
99
import javax.validation.Validation
1010

1111

12-
abstract class AbstractValidationTest {
12+
abstract class AbstractValidationTest(constructorValidatorFactory: ConstructorValidatorFactory? = null) {
1313

1414
private val validatorFactory = Validation.byDefaultProvider()
1515
.configure()
1616
.messageInterpolator(ParameterMessageInterpolator())
1717
.buildValidatorFactory()
1818

1919
protected val beanValidationModule: BeanValidationModule = BeanValidationModule(validatorFactory)
20+
.setConstructorValidatorFactory(constructorValidatorFactory)
2021

2122
protected val objectMapper: ObjectMapper = ObjectMapper()
2223
.registerModule(beanValidationModule)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.unbrokendome.jackson.beanvalidation.constraints
2+
3+
import org.hibernate.validator.HibernateValidatorFactory
4+
import org.unbrokendome.jackson.beanvalidation.ConstructorValidatorFactory
5+
import java.lang.reflect.Constructor
6+
import javax.validation.Validator
7+
import javax.validation.ValidatorFactory
8+
9+
class HibernateConstructorValidatorFactory : ConstructorValidatorFactory {
10+
override fun getValidator(validatorFactory: ValidatorFactory, constructor: Constructor<Any>, parameterValues: Array<out Any>): Validator {
11+
val declaredFields = constructor.declaringClass.declaredFields
12+
val payload: Map<String, Any> = parameterValues
13+
.mapIndexed { index, value -> declaredFields[index].name to value}
14+
.toMap()
15+
16+
return validatorFactory.unwrap(HibernateValidatorFactory::class.java)
17+
.usingContext().constraintValidatorPayload(payload).validator
18+
}
19+
}

0 commit comments

Comments
 (0)