Skip to content

Commit 851198f

Browse files
committed
Merge branch 'release/2.0.0'
2 parents 65cdfc6 + b02ca56 commit 851198f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+946
-444
lines changed

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: java
2+
after_success:
3+
- bash <(curl -s https://codecov.io/bash)

pom.xml

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>dev.ditsche</groupId>
88
<artifactId>validator</artifactId>
9-
<version>1.1.3</version>
9+
<version>2.0.0-NIGHTLY</version>
1010

1111
<packaging>jar</packaging>
1212

@@ -43,17 +43,17 @@
4343
<artifactId>lombok</artifactId>
4444
<version>1.18.12</version>
4545
</dependency>
46-
<dependency>
47-
<groupId>com.sun.mail</groupId>
48-
<artifactId>javax.mail</artifactId>
49-
<version>1.6.2</version>
50-
</dependency>
5146
<dependency>
5247
<groupId>org.junit.jupiter</groupId>
5348
<artifactId>junit-jupiter</artifactId>
5449
<version>5.6.2</version>
5550
<scope>test</scope>
5651
</dependency>
52+
<dependency>
53+
<groupId>org.apache.commons</groupId>
54+
<artifactId>commons-lang3</artifactId>
55+
<version>3.10</version>
56+
</dependency>
5757
<dependency>
5858
<groupId>org.assertj</groupId>
5959
<artifactId>assertj-core</artifactId>
@@ -82,6 +82,16 @@
8282

8383
<build>
8484
<plugins>
85+
<plugin>
86+
<groupId>org.apache.maven.plugins</groupId>
87+
<artifactId>maven-surefire-plugin</artifactId>
88+
<version>2.22.0</version>
89+
</plugin>
90+
<plugin>
91+
<groupId>org.apache.maven.plugins</groupId>
92+
<artifactId>maven-failsafe-plugin</artifactId>
93+
<version>2.22.0</version>
94+
</plugin>
8595
<plugin>
8696
<groupId>org.apache.maven.plugins</groupId>
8797
<artifactId>maven-source-plugin</artifactId>

src/main/java/dev/ditsche/validator/Validator.java

Lines changed: 41 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
package dev.ditsche.validator;
22

33
import dev.ditsche.validator.error.ErrorBag;
4+
import dev.ditsche.validator.error.FieldNotAccessibleException;
5+
import dev.ditsche.validator.error.ValidationError;
46
import dev.ditsche.validator.error.ValidationException;
57
import dev.ditsche.validator.rule.*;
8+
import dev.ditsche.validator.rule.builder.Builder;
9+
import dev.ditsche.validator.validation.Validatable;
10+
import dev.ditsche.validator.validation.ValidationResult;
11+
import org.apache.commons.lang3.reflect.FieldUtils;
612

713
import java.lang.reflect.Field;
8-
import java.lang.reflect.InvocationTargetException;
9-
import java.lang.reflect.Method;
1014
import java.util.ArrayList;
1115
import java.util.Arrays;
12-
import java.util.LinkedList;
1316
import java.util.List;
1417

1518
/**
1619
* Validates an object against a defined schema.
17-
*
18-
* @param <T> The type of the validated object.
1920
*/
20-
public class Validator<T> {
21+
public class Validator {
2122

2223
/**
2324
* The error bag for the
@@ -28,7 +29,7 @@ public class Validator<T> {
2829
/**
2930
* All registered fields.
3031
*/
31-
private List<? extends Validatable> fields;
32+
private List<Validatable> fields;
3233

3334
/**
3435
* Parses a pattern and creates a Rule instance dynamically if it
@@ -39,121 +40,51 @@ public class Validator<T> {
3940
/**
4041
* Create a new validator instance based on a given type.
4142
*/
42-
public Validator() {
43+
private Validator() {
4344
this.errorBag = new ErrorBag();
4445
this.ruleParser = new RuleParser();
4546
this.fields = new ArrayList<>();
4647
}
4748

48-
/**
49-
* Adds a field to the schema.
50-
* You can add any amount of rules for a field.
51-
* <p>
52-
* When a field is already existing the rules will be added to the fields rules.
53-
* Already existing rules will be overwritten.
54-
* <p>
55-
* The given fields need to have a getter method starting with {@code get} or {@code is}.
56-
*
57-
* @param field The name of the field.
58-
* @param rules The assigned rules.
59-
* @return The instance of the validator.
60-
*/
61-
public Validator<T> addField(String field, Rule...rules) {
62-
ValidationField vf = fields.stream().filter(f -> f.getField().equals(field))
63-
.findFirst().orElse(null);
64-
if(vf == null) {
65-
fields.add(new ValidationField(field, rules));
66-
return this;
67-
} else {
68-
fields.remove(vf);
69-
for(Rule rule : rules) {
70-
vf.addRule(rule);
71-
}
49+
public static Validator fromRules(Builder ...builders) {
50+
Validator validator = new Validator();
51+
for(Builder builder : builders) {
52+
validator.add(builder);
7253
}
73-
fields.add(vf);
74-
return this;
54+
return validator;
7555
}
7656

77-
/**
78-
* Adds a field and rules based on a string representation. Divide rule using a
79-
* {@code |} symbol. Parameters can be passed using a {@code :} syntax.
80-
* E.g: "required|max:50|length:10:50"
81-
* <p>
82-
* The given fields need to have a getter method starting with {@code get} or {@code is}.
83-
*
84-
* @param field The name of the field.
85-
* @param rulesString he assigned rules in string representation.
86-
* @return The instance of the validator.
87-
*/
88-
public Validator<T> addField(String field, String rulesString) {
89-
String[] rules = rulesString.split("\\|");
90-
Rule[] parsed = new Rule[rules.length];
91-
for(int i = 0; i < rules.length; i++) {
92-
int finalI = i;
93-
ruleParser.parse(rules[i]).ifPresent(rule -> parsed[finalI] = rule);
57+
public static Validator fromRules(Validatable ...rules) {
58+
Validator validator = new Validator();
59+
for(Validatable validatable : rules) {
60+
validator.add(validatable);
9461
}
95-
return addField(field, parsed);
62+
return validator;
9663
}
9764

98-
/**
99-
* Adds a field using the ValidationField class.
100-
*
101-
* @param validationField
102-
* @return
103-
*/
104-
public Validator<T> addField(ValidationField validationField) {
105-
return addField(validationField.getField(), (Rule[]) validationField.getRules().toArray());
65+
public static Validator empty() {
66+
return new Validator();
10667
}
10768

108-
/**
109-
* Adds a field using the ValidationObject class.
110-
*
111-
* @param validationField
112-
* @return
113-
*/
114-
public Validator<T> addField(ValidationObject validationObject) {
115-
return null;
69+
public Validator add(Builder builder) {
70+
return add(builder.build());
11671
}
11772

118-
public T validate(T object) throws ValidationException, IllegalAccessException {
119-
return validate(object, false);
73+
public Validator add(Validatable validatable) {
74+
this.fields.add(validatable);
75+
return this;
12076
}
12177

122-
/**
123-
* Validates an object against a schema and returns an error bag.
124-
*
125-
* @param object The object that need to be validated.
126-
* @throws ValidationException Thrown when at least one rule fails.
127-
* @throws IllegalAccessException Thrown when the field is not public.
128-
*/
129-
public T validate(T object, boolean abortEarly) throws ValidationException, IllegalAccessException {
130-
errorBag.clear();
131-
List<Field> fieldSet = new ArrayList<>();
132-
for (Class<?> c = object.getClass(); c != null; c = c.getSuperclass())
133-
{
134-
Field[] fields = c.getDeclaredFields();
135-
fieldSet.addAll(Arrays.asList(fields));
136-
}
137-
for(Validatable validatable : this.fields) {
138-
Field field = fieldSet.stream().filter(f -> f.getName().equals(validatable.getField())).findFirst().orElse(null);
139-
if(field == null) continue;
140-
Object value = getValue(field, object);
141-
errorBag.merge(validatable.validate(value, abortEarly));
142-
}
143-
if(!errorBag.isEmpty())
144-
throw new ValidationException(errorBag);
145-
146-
return object;
78+
public <T> T validate(T object) {
79+
return validate(object, false);
14780
}
14881

14982
/**
15083
* Validates an object against a schema and returns an error bag.
15184
*
15285
* @param object The object that need to be validated.
153-
* @throws ValidationException Thrown when at least one rule fails.
154-
* @throws IllegalAccessException Thrown when the field is not public.
15586
*/
156-
public void tryValidate(T object) throws ValidationException, IllegalAccessException {
87+
public <T> T validate(T object, boolean abortEarly) {
15788
errorBag.clear();
15889
List<Field> fieldSet = new ArrayList<>();
15990
for (Class<?> c = object.getClass(); c != null; c = c.getSuperclass())
@@ -162,39 +93,22 @@ public void tryValidate(T object) throws ValidationException, IllegalAccessExcep
16293
fieldSet.addAll(Arrays.asList(fields));
16394
}
16495
for(Validatable validatable : this.fields) {
165-
Field field = fieldSet.stream().filter(f -> f.getName().equals(validatable.getField())).findFirst().orElse(null);
166-
if(field == null) continue;
167-
Object value = getValue(field, object);
168-
errorBag.merge(validatable.validate(value, abortEarly));
96+
try {
97+
Field field = fieldSet.stream().filter(f -> f.getName().equals(validatable.getField())).findFirst().orElse(null);
98+
if(field == null) continue;
99+
Object value = FieldUtils.readField(field, object, true);
100+
ValidationResult result = validatable.validate("", value, abortEarly);
101+
if(result.isChanged())
102+
FieldUtils.writeField(field, object, result.getValue(), true);
103+
errorBag.merge(result.getErrorBag());
104+
} catch (IllegalAccessException ex) {
105+
throw new FieldNotAccessibleException();
106+
}
169107
}
170108
if(!errorBag.isEmpty())
171109
throw new ValidationException(errorBag);
172-
}
173110

174-
/**
175-
* Uses reflection to invoke a getter of the validation target.
176-
* Falls back to the fields default getter. Will fail if the variable
177-
* is not publicly accessible.
178-
*
179-
* @param field The field name whose value should be received.
180-
* @param object The validation target object.
181-
* @return {@code null} if the field cannot be resolved, or the value.
182-
*/
183-
private Object getValue(Field field, Object object) throws IllegalAccessException {
184-
for (Method method : object.getClass().getMethods()) {
185-
if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)) ||
186-
(method.getName().startsWith("is")) && (method.getName().length() == (field.getName().length() + 2))) {
187-
if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) {
188-
try {
189-
return method.invoke(object);
190-
}
191-
catch (IllegalAccessException | InvocationTargetException e) {
192-
e.printStackTrace();
193-
}
194-
}
195-
}
196-
}
197-
return field.get(object);
111+
return object;
198112
}
199113

200114
/**

src/main/java/dev/ditsche/validator/error/ErrorBag.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import lombok.Getter;
44

55
import java.util.HashMap;
6-
import java.util.LinkedList;
76
import java.util.List;
8-
import java.util.Map;
97

108
/**
119
* The error bag holds the fields for which at least one rule has not passed.

src/main/java/dev/ditsche/validator/error/ValueNotAccessibleException.java renamed to src/main/java/dev/ditsche/validator/error/FieldNotAccessibleException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
/**
44
* @author Tobias Dittmann
55
*/
6-
public class ValueNotAccessibleException extends RuntimeException {
6+
public class FieldNotAccessibleException extends RuntimeException {
77
}

src/main/java/dev/ditsche/validator/error/ValidationError.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import lombok.Data;
55
import lombok.NoArgsConstructor;
66

7-
import java.util.ArrayList;
87
import java.util.LinkedList;
98
import java.util.List;
109

src/main/java/dev/ditsche/validator/error/ValidationException.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package dev.ditsche.validator.error;
22

33
import java.util.Collection;
4-
import java.util.HashMap;
5-
import java.util.HashSet;
6-
import java.util.List;
74

85
/**
96
* Thrown when the validation of an object fails.

src/main/java/dev/ditsche/validator/rule/Rule.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public interface Rule {
1212
* @param value The value that will be tested.
1313
* @return {@code true} if the test passes, {@code false} if not.
1414
*/
15-
boolean passes(Object value);
15+
RuleResult passes(Object value);
1616

1717
/**
1818
* The error message, when the test does not pass.

src/main/java/dev/ditsche/validator/rule/RuleMap.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dev.ditsche.validator.rule;
22

3-
import dev.ditsche.validator.rule.builder.StringRuleBuilder;
4-
import dev.ditsche.validator.ruleset.*;
3+
import dev.ditsche.validator.rule.ruleset.*;
54

65
import java.util.HashMap;
76
import java.util.Optional;
@@ -37,6 +36,12 @@ private void init() {
3736
add("email", new RuleInfo(EmailRule.class));
3837
add("size", new RuleInfo(SizeRule.class, long.class, long.class));
3938
add("pattern", new RuleInfo(PatternRule.class, String.class));
39+
add("ip", new RuleInfo(IpAddressRule.class));
40+
add("creditCard", new RuleInfo(CreditCardRule.class));
41+
add("length", new RuleInfo(LengthRule.class, long.class));
42+
add("number", new RuleInfo(NumberRule.class));
43+
add("string", new RuleInfo(StringRule.class));
44+
add("default", new RuleInfo(DefaultRule.class, Object.class));
4045
}
4146

4247
/**
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package dev.ditsche.validator.rule;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.NoArgsConstructor;
6+
7+
/**
8+
* @author Tobias Dittmann
9+
*/
10+
@Data
11+
@NoArgsConstructor
12+
@AllArgsConstructor
13+
public class RuleResult {
14+
15+
private boolean passed;
16+
17+
private Object value;
18+
19+
private boolean changed;
20+
21+
public static RuleResult passes(boolean passes) {
22+
return new RuleResult(passes, null, false);
23+
}
24+
25+
public static RuleResult resolve() {
26+
return new RuleResult(true, null, false);
27+
}
28+
29+
public static RuleResult resolve(Object object) {
30+
return new RuleResult(true, object, true);
31+
}
32+
33+
public static RuleResult reject() {
34+
return new RuleResult(false, null, false);
35+
}
36+
37+
}

0 commit comments

Comments
 (0)