Skip to content

Commit a0810bd

Browse files
committed
splitting validator implementations into multiple files, and implementing formatValidator handling in StringSchema
1 parent 8c79af2 commit a0810bd

14 files changed

+438
-277
lines changed

core/src/main/java/org/everit/json/schema/Format.java

Lines changed: 0 additions & 85 deletions
This file was deleted.

core/src/main/java/org/everit/json/schema/FormatValidator.java

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@
1515
*/
1616
package org.everit.json.schema;
1717

18+
import java.util.Objects;
1819
import java.util.Optional;
1920

20-
import org.everit.json.schema.internal.DefaultFormatValidator;
21+
import org.everit.json.schema.internal.DateTimeFormatValidator;
22+
import org.everit.json.schema.internal.EmailFormatValidator;
23+
import org.everit.json.schema.internal.HostnameFormatValidator;
24+
import org.everit.json.schema.internal.IPV4Validator;
25+
import org.everit.json.schema.internal.IPV6Validator;
26+
import org.everit.json.schema.internal.URIFormatValidator;
2127

2228
/**
2329
* Implementations perform the validation against the "format" keyword (see JSON Schema spec section
@@ -29,10 +35,41 @@ public interface FormatValidator {
2935
/**
3036
* No-operation implementation (never throws {always returns {@link Optional#empty()}).
3137
*/
32-
FormatValidator NONE = (subject, format) -> Optional.empty();
38+
FormatValidator NONE = subject -> Optional.empty();
3339

34-
FormatValidator DEFAULT = new DefaultFormatValidator();
40+
/**
41+
* Static factory method for {@code FormatValidator} implementations supporting the
42+
* {@code formatName}s mandated by the json schema spec.
43+
*
44+
* <ul>
45+
* <li>date-time</li>
46+
* <li>email</li>
47+
* <li>hostname</li>
48+
* <li>uri</li>
49+
* <li>ipv4</li>
50+
* <li>ipv6</li>
51+
* </ul>
52+
*/
53+
static FormatValidator forFormat(final String formatName) {
54+
Objects.requireNonNull(formatName, "formatName cannot be null");
55+
switch (formatName) {
56+
case "date-time":
57+
return new DateTimeFormatValidator();
58+
case "email":
59+
return new EmailFormatValidator();
60+
case "hostname":
61+
return new HostnameFormatValidator();
62+
case "uri":
63+
return new URIFormatValidator();
64+
case "ipv4":
65+
return new IPV4Validator();
66+
case "ipv6":
67+
return new IPV6Validator();
68+
default:
69+
throw new IllegalArgumentException("unsupported format: " + formatName);
70+
}
71+
}
3572

36-
Optional<String> validate(String subject, Format format);
73+
Optional<String> validate(String subject);
3774

3875
}

core/src/main/java/org/everit/json/schema/StringSchema.java

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
*/
1616
package org.everit.json.schema;
1717

18+
import java.util.ArrayList;
19+
import java.util.Arrays;
20+
import java.util.Collections;
21+
import java.util.List;
22+
import java.util.Objects;
1823
import java.util.regex.Pattern;
1924

2025
/**
@@ -35,11 +40,24 @@ public static class Builder extends Schema.Builder<StringSchema> {
3540

3641
private boolean requiresString = true;
3742

43+
private FormatValidator formatValidator = FormatValidator.NONE;
44+
3845
@Override
3946
public StringSchema build() {
4047
return new StringSchema(this);
4148
}
4249

50+
/**
51+
* Setter for the format validator. It should be used in conjunction with
52+
* {@link FormatValidator#forFormat(String)} if a {@code "format"} value is found in a schema
53+
* json.
54+
*/
55+
public Builder formatValidator(final FormatValidator formatValidator) {
56+
this.formatValidator = Objects.requireNonNull(formatValidator,
57+
"formatValidator cannot be null");
58+
return this;
59+
}
60+
4361
public Builder maxLength(final Integer maxLength) {
4462
this.maxLength = maxLength;
4563
return this;
@@ -74,6 +92,8 @@ public static Builder builder() {
7492

7593
private final boolean requiresString;
7694

95+
private final FormatValidator formatValidator;
96+
7797
public StringSchema() {
7898
this(builder());
7999
}
@@ -94,6 +114,7 @@ public StringSchema(final Builder builder) {
94114
} else {
95115
this.pattern = null;
96116
}
117+
this.formatValidator = builder.formatValidator;
97118
}
98119

99120
public Integer getMaxLength() {
@@ -108,23 +129,27 @@ public Pattern getPattern() {
108129
return pattern;
109130
}
110131

111-
private void testLength(final String subject) {
132+
private List<ValidationException> testLength(final String subject) {
112133
int actualLength = subject.length();
134+
List<ValidationException> rval = new ArrayList<>();
113135
if (minLength != null && actualLength < minLength.intValue()) {
114-
throw new ValidationException(this, "expected minLength: " + minLength + ", actual: "
115-
+ actualLength);
136+
rval.add(new ValidationException(this, "expected minLength: " + minLength + ", actual: "
137+
+ actualLength));
116138
}
117139
if (maxLength != null && actualLength > maxLength.intValue()) {
118-
throw new ValidationException(this, "expected maxLength: " + maxLength + ", actual: "
119-
+ actualLength);
140+
rval.add(new ValidationException(this, "expected maxLength: " + maxLength + ", actual: "
141+
+ actualLength));
120142
}
143+
return rval;
121144
}
122145

123-
private void testPattern(final String subject) {
146+
private List<ValidationException> testPattern(final String subject) {
124147
if (pattern != null && !pattern.matcher(subject).find()) {
125-
throw new ValidationException(this, String.format("string [%s] does not match pattern %s",
126-
subject, pattern.pattern()));
148+
return Arrays.asList(new ValidationException(this, String.format(
149+
"string [%s] does not match pattern %s",
150+
subject, pattern.pattern())));
127151
}
152+
return Collections.emptyList();
128153
}
129154

130155
@Override
@@ -135,9 +160,13 @@ public void validate(final Object subject) {
135160
}
136161
} else {
137162
String stringSubject = (String) subject;
138-
testLength(stringSubject);
139-
testPattern(stringSubject);
163+
List<ValidationException> rval = new ArrayList<>();
164+
rval.addAll(testLength(stringSubject));
165+
rval.addAll(testPattern(stringSubject));
166+
formatValidator.validate(stringSubject)
167+
.map(failure -> new ValidationException(this, failure))
168+
.ifPresent(rval::add);
169+
ValidationException.throwFor(this, rval);
140170
}
141171
}
142-
143172
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (C) 2011 Everit Kft. (http://www.everit.org)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.everit.json.schema.internal;
17+
18+
import java.text.ParseException;
19+
import java.text.SimpleDateFormat;
20+
import java.util.Optional;
21+
22+
import org.everit.json.schema.FormatValidator;
23+
24+
/**
25+
* Implementation of the "date-time" format value.
26+
*/
27+
public class DateTimeFormatValidator implements FormatValidator {
28+
29+
private static final String DATETIME_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssXXX";
30+
31+
private static final String DATETIME_FORMAT_STRING_SECFRAC = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
32+
33+
@Override
34+
public Optional<String> validate(final String subject) {
35+
try {
36+
new SimpleDateFormat(DATETIME_FORMAT_STRING).parse(subject);
37+
return Optional.empty();
38+
} catch (ParseException e) {
39+
try {
40+
new SimpleDateFormat(DATETIME_FORMAT_STRING_SECFRAC).parse(subject);
41+
return Optional.empty();
42+
} catch (ParseException e1) {
43+
return Optional.of(String.format("[%s] is not a valid date-time", subject));
44+
}
45+
}
46+
}
47+
48+
}

0 commit comments

Comments
 (0)