Skip to content

Commit 4378267

Browse files
committed
Fixed the required rule
1 parent defca2c commit 4378267

File tree

2 files changed

+124
-40
lines changed

2 files changed

+124
-40
lines changed

src/main/java/org/javawebstack/validator/Validator.java

Lines changed: 75 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.javawebstack.graph.GraphArray;
66
import org.javawebstack.graph.GraphElement;
77
import org.javawebstack.graph.GraphMapper;
8+
import org.javawebstack.graph.GraphNull;
89
import org.javawebstack.validator.rule.*;
910

1011
import java.lang.reflect.Constructor;
@@ -128,54 +129,88 @@ public Validator rule(String key, ValidationRule... rules){
128129

129130
public ValidationResult validate(GraphElement rootElement){
130131
Map<String[], List<String>> errors = new HashMap<>();
131-
for(String[] sourceKey : rules.keySet()){
132-
Map<String[], GraphElement> map = matchKeys(sourceKey, rootElement);
133-
List<ValidationRule> validators = rules.get(sourceKey);
134-
map.forEach((key, value) -> {
135-
List<String> fieldErrors = new ArrayList<>();
136-
for(ValidationRule rule : validators){
137-
String error = rule.validate(this, value);
138-
if(error != null)
139-
fieldErrors.add(error);
140-
}
141-
if(fieldErrors.size() > 0)
142-
errors.put(key, fieldErrors);
143-
});
132+
for(String[] key : rules.keySet()){
133+
errors.putAll(check(rules, new String[0], new String[0], key, rootElement));
144134
}
145135
return new ValidationResult(errors);
146136
}
147137

148-
private Map<String[], GraphElement> matchKeys(String[] keys, GraphElement element){
149-
Map<String[], GraphElement> result = new HashMap<>();
150-
if(keys.length == 0){
151-
result.put(keys, element);
152-
return result;
138+
private Map<String[], List<String>> check(Map<String[], List<ValidationRule>> rules, String[] keyPrefix, String[] resolvedKeyPrefix, String[] key, GraphElement element){
139+
if(key.length == 0){
140+
Map<String[], List<String>> errors = new HashMap<>();
141+
for(ValidationRule rule : getMapValue(rules, keyPrefix)){
142+
String error = rule.validate(this, element);
143+
if(error != null){
144+
if(!errors.containsKey(resolvedKeyPrefix))
145+
errors.put(resolvedKeyPrefix, new ArrayList<>());
146+
errors.get(resolvedKeyPrefix).add(error);
147+
}
148+
}
149+
return errors;
150+
}
151+
if(element == null)
152+
element = GraphNull.INSTANCE;
153+
String[] innerKey = new String[key.length-1];
154+
System.arraycopy(key, 1, innerKey, 0, innerKey.length);
155+
String[] innerKeyPrefix = new String[keyPrefix.length+1];
156+
System.arraycopy(keyPrefix, 0, innerKeyPrefix, 0, keyPrefix.length);
157+
innerKeyPrefix[innerKeyPrefix.length-1] = key[0];
158+
if(key[0].equals("*")){
159+
Map<String[], List<String>> errors = new HashMap<>();
160+
if(element.isArray()){
161+
for(int i=0; i<element.array().size(); i++){
162+
String[] innerResolvedKeyPrefix = new String[keyPrefix.length+1];
163+
System.arraycopy(resolvedKeyPrefix, 0, innerResolvedKeyPrefix, 0, resolvedKeyPrefix.length);
164+
innerResolvedKeyPrefix[innerResolvedKeyPrefix.length-1] = String.valueOf(i);
165+
errors.putAll(check(rules, innerKeyPrefix, innerResolvedKeyPrefix, innerKey, element.array().get(i)));
166+
}
167+
}
168+
if(element.isObject()){
169+
for(String k : element.object().keys()){
170+
String[] innerResolvedKeyPrefix = new String[keyPrefix.length+1];
171+
System.arraycopy(resolvedKeyPrefix, 0, innerResolvedKeyPrefix, 0, resolvedKeyPrefix.length);
172+
innerResolvedKeyPrefix[innerResolvedKeyPrefix.length-1] = k;
173+
errors.putAll(check(rules, innerKeyPrefix, innerResolvedKeyPrefix, innerKey, element.object().get(k)));
174+
}
175+
}
176+
return errors;
177+
}
178+
GraphElement value = GraphNull.INSTANCE;
179+
if(element.isArray()){
180+
try {
181+
value = element.array().get(Integer.parseInt(key[0]));
182+
}catch (Exception ignored){}
153183
}
154-
if(element.isArray())
155-
element = element.object();
156184
if(element.isObject()){
157-
String currentKey = keys[0];
158-
String[] newKeys = new String[keys.length-1];
159-
System.arraycopy(keys, 1, newKeys, 0, newKeys.length);
160-
if(currentKey != null){
161-
matchKeys(newKeys, element.object().get(currentKey)).forEach((nk, actualValue) -> {
162-
String[] actualKey = new String[nk.length + 1];
163-
actualKey[0] = currentKey;
164-
System.arraycopy(nk, 0, actualKey, 1, nk.length);
165-
result.put(actualKey, actualValue);
166-
});
167-
}else{
168-
element.object().forEach((k, value) -> {
169-
matchKeys(newKeys, value).forEach((nk, actualValue) -> {
170-
String[] actualKey = new String[nk.length + 1];
171-
actualKey[0] = k;
172-
System.arraycopy(nk, 0, actualKey, 1, nk.length);
173-
result.put(actualKey, actualValue);
174-
});
175-
});
185+
value = element.object().get(key[0]);
186+
}
187+
String[] innerResolvedKeyPrefix = new String[keyPrefix.length+1];
188+
System.arraycopy(resolvedKeyPrefix, 0, innerResolvedKeyPrefix, 0, resolvedKeyPrefix.length);
189+
innerResolvedKeyPrefix[innerResolvedKeyPrefix.length-1] = key[0];
190+
return check(rules, innerKeyPrefix, innerResolvedKeyPrefix, innerKey, value);
191+
}
192+
193+
private static boolean stringArrayEqual(String[] a, String[] b){
194+
if(a.length != b.length)
195+
return false;
196+
for(int i=0; i<a.length; i++){
197+
if(a[0] == null && b[0] == null)
198+
continue;
199+
if(a[0] == null || b[0] == null)
200+
return false;
201+
if(!a[0].equals(b[0]))
202+
return false;
203+
}
204+
return true;
205+
}
206+
207+
private static <V> V getMapValue(Map<String[], V> map, String[] key){
208+
for(String[] k : map.keySet()){
209+
if(stringArrayEqual(k, key)){
210+
return map.get(k);
176211
}
177212
}
178-
return result;
213+
return null;
179214
}
180215

181216
private static Map<String[], List<ValidationRule>> getClassRules(Class<?> type){
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package test.org.javawebstack.validator;
2+
3+
import com.google.gson.annotations.Expose;
4+
import org.javawebstack.graph.GraphMapper;
5+
import org.javawebstack.validator.Rule;
6+
import org.javawebstack.validator.Validator;
7+
import org.junit.jupiter.api.Test;
8+
import static org.junit.jupiter.api.Assertions.*;
9+
10+
public class RequiredRuleTest {
11+
12+
@Test
13+
public void testSimpleRequiredRule(){
14+
Validator validator = Validator.getValidator(TestObject1.class);
15+
TestObject1 test = new TestObject1();
16+
assertFalse(validator.validate(new GraphMapper().toGraph(test)).isValid());
17+
test.name = "Test";
18+
assertTrue(validator.validate(new GraphMapper().toGraph(test)).isValid());
19+
}
20+
21+
@Test
22+
public void testInnerRequiredRule(){
23+
Validator validator = Validator.getValidator(TestObject2.class);
24+
TestObject2 test = new TestObject2();
25+
assertTrue(validator.validate(new GraphMapper().toGraph(test)).isValid());
26+
test.inners = new TestObject2.Inner[0];
27+
assertTrue(validator.validate(new GraphMapper().toGraph(test)).isValid());
28+
test.inners = new TestObject2.Inner[]{
29+
new TestObject2.Inner()
30+
};
31+
assertFalse(validator.validate(new GraphMapper().toGraph(test)).isValid());
32+
test.inners[0].name = "Test";
33+
assertTrue(validator.validate(new GraphMapper().toGraph(test)).isValid());
34+
}
35+
36+
private static class TestObject1 {
37+
@Rule("required")
38+
String name;
39+
}
40+
41+
private static class TestObject2 {
42+
private Inner[] inners;
43+
public static class Inner {
44+
@Rule("required")
45+
private String name;
46+
}
47+
}
48+
49+
}

0 commit comments

Comments
 (0)