Skip to content

Commit 33a76db

Browse files
authored
Merge pull request #221 from crate-metadata/KeywordValidators
Switch KeywordValidators to use a factory model
2 parents 944e01a + 42ab769 commit 33a76db

16 files changed

+286
-235
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.github.fge.jsonschema.keyword.validator;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
5+
6+
/**
7+
* Interface for a keyword validator factory
8+
*/
9+
public interface KeywordValidatorFactory
10+
{
11+
/**
12+
* Create a validator for the instance
13+
*
14+
* @param node the instance to validate
15+
* @return a validator for the given instance
16+
* @throws ProcessingException an error occurs creating the validator
17+
*/
18+
KeywordValidator getKeywordValidator(JsonNode node)
19+
throws ProcessingException;
20+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.github.fge.jsonschema.keyword.validator;
2+
3+
import java.lang.reflect.Constructor;
4+
import java.lang.reflect.InvocationTargetException;
5+
6+
import com.fasterxml.jackson.databind.JsonNode;
7+
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
8+
import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
9+
import com.github.fge.msgsimple.bundle.MessageBundle;
10+
import com.github.fge.msgsimple.load.MessageBundles;
11+
12+
/**
13+
* A validator factory that uses reflection to create an instance of the
14+
* specified KeywordValidator class
15+
*/
16+
public class ReflectionKeywordValidatorFactory
17+
implements KeywordValidatorFactory
18+
{
19+
private static final String ERRMSG = "failed to build keyword validator";
20+
private static final MessageBundle BUNDLE
21+
= MessageBundles.getBundle(JsonSchemaConfigurationBundle.class);
22+
23+
private final Constructor<? extends KeywordValidator> constructor;
24+
25+
public ReflectionKeywordValidatorFactory(String name,
26+
Class<? extends KeywordValidator> clazz)
27+
{
28+
try {
29+
constructor = clazz.getConstructor(JsonNode.class);
30+
} catch (NoSuchMethodException ignored) {
31+
throw new IllegalArgumentException(BUNDLE.printf(
32+
"noAppropriateConstructor", name, clazz.getCanonicalName()
33+
));
34+
}
35+
}
36+
37+
@Override
38+
public KeywordValidator getKeywordValidator(JsonNode node)
39+
throws ProcessingException
40+
{
41+
try {
42+
return constructor.newInstance(node);
43+
} catch (InstantiationException e) {
44+
throw new ProcessingException(ERRMSG, e);
45+
} catch (IllegalAccessException e) {
46+
throw new ProcessingException(ERRMSG, e);
47+
} catch (InvocationTargetException e) {
48+
throw new ProcessingException(ERRMSG, e);
49+
}
50+
}
51+
52+
}

src/main/java/com/github/fge/jsonschema/library/Keyword.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@
2222
import com.github.fge.Frozen;
2323
import com.github.fge.jsonschema.core.keyword.syntax.checkers.SyntaxChecker;
2424
import com.github.fge.jsonschema.keyword.digest.Digester;
25-
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
26-
27-
import java.lang.reflect.Constructor;
25+
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
2826

2927

3028
/**
@@ -51,9 +49,9 @@ public final class Keyword
5149
final Digester digester;
5250

5351
/**
54-
* {@link KeywordValidator} constructor
52+
* Validator factory
5553
*/
56-
final Constructor<? extends KeywordValidator> constructor;
54+
final KeywordValidatorFactory validatorFactory;
5755

5856
/**
5957
* Instantiate a new keyword builder
@@ -79,7 +77,7 @@ public static KeywordBuilder newBuilder(final String name)
7977
name = builder.name;
8078
syntaxChecker = builder.syntaxChecker;
8179
digester = builder.digester;
82-
constructor = builder.constructor;
80+
validatorFactory = builder.validatorFactory;
8381
}
8482

8583
/**

src/main/java/com/github/fge/jsonschema/library/KeywordBuilder.java

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,19 @@
1919

2020
package com.github.fge.jsonschema.library;
2121

22-
import com.fasterxml.jackson.databind.JsonNode;
2322
import com.github.fge.Thawed;
2423
import com.github.fge.jackson.NodeType;
2524
import com.github.fge.jsonschema.core.keyword.syntax.checkers.SyntaxChecker;
2625
import com.github.fge.jsonschema.keyword.digest.Digester;
2726
import com.github.fge.jsonschema.keyword.digest.helpers.IdentityDigester;
2827
import com.github.fge.jsonschema.keyword.digest.helpers.SimpleDigester;
2928
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
29+
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
30+
import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
3031
import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
3132
import com.github.fge.msgsimple.bundle.MessageBundle;
3233
import com.github.fge.msgsimple.load.MessageBundles;
3334

34-
import java.lang.reflect.Constructor;
35-
3635
/**
3736
* A keyword builder -- the thawed version of a {@link Keyword}
3837
*
@@ -48,7 +47,7 @@ public final class KeywordBuilder
4847
final String name;
4948
SyntaxChecker syntaxChecker;
5049
Digester digester;
51-
Constructor<? extends KeywordValidator> constructor;
50+
KeywordValidatorFactory validatorFactory;
5251

5352
/**
5453
* Create a new, empty keyword builder
@@ -74,7 +73,7 @@ public final class KeywordBuilder
7473
name = keyword.name;
7574
syntaxChecker = keyword.syntaxChecker;
7675
digester = keyword.digester;
77-
constructor = keyword.constructor;
76+
validatorFactory = keyword.validatorFactory;
7877
}
7978

8079
/**
@@ -149,7 +148,20 @@ public KeywordBuilder withSimpleDigester(final NodeType first,
149148
public KeywordBuilder withValidatorClass(
150149
final Class<? extends KeywordValidator> c)
151150
{
152-
constructor = getConstructor(name, c);
151+
validatorFactory = new ReflectionKeywordValidatorFactory(name, c);
152+
return this;
153+
}
154+
155+
/**
156+
* Set the validator factory for this keyword
157+
*
158+
* @param factory the factory
159+
* @return this
160+
*/
161+
public KeywordBuilder withValidatorFactory(
162+
KeywordValidatorFactory factory)
163+
{
164+
validatorFactory = factory;
153165
return this;
154166
}
155167

@@ -169,24 +181,11 @@ public Keyword freeze()
169181
* We can have a keyword without a validator; however, if there is one,
170182
* there must be a digester.
171183
*/
172-
BUNDLE.checkArgumentPrintf(constructor == null || digester != null,
184+
BUNDLE.checkArgumentPrintf(validatorFactory == null || digester != null,
173185
"malformedKeyword", name);
174186
return new Keyword(this);
175187
}
176188

177-
178-
private static Constructor<? extends KeywordValidator> getConstructor(
179-
final String name, final Class<? extends KeywordValidator> c)
180-
{
181-
try {
182-
return c.getConstructor(JsonNode.class);
183-
} catch (NoSuchMethodException ignored) {
184-
throw new IllegalArgumentException(BUNDLE.printf(
185-
"noAppropriateConstructor", name, c.getCanonicalName()
186-
));
187-
}
188-
}
189-
190189
private static NodeType checkType(final NodeType type)
191190
{
192191
return BUNDLE.checkNotNull(type, "nullType");

src/main/java/com/github/fge/jsonschema/library/Library.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@
2626
import com.github.fge.jsonschema.core.util.Dictionary;
2727
import com.github.fge.jsonschema.format.FormatAttribute;
2828
import com.github.fge.jsonschema.keyword.digest.Digester;
29-
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
30-
31-
import java.lang.reflect.Constructor;
29+
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
3230

3331
/**
3432
* A schema keyword library
@@ -54,9 +52,9 @@ public final class Library
5452
final Dictionary<Digester> digesters;
5553

5654
/**
57-
* Dictionary of keyword validator constructors
55+
* Dictionary of keyword validator factories
5856
*/
59-
final Dictionary<Constructor<? extends KeywordValidator>> validators;
57+
final Dictionary<KeywordValidatorFactory> validators;
6058

6159
/**
6260
* Dictionary of format attributes
@@ -97,7 +95,7 @@ public static LibraryBuilder newBuilder()
9795
*/
9896
Library(final Dictionary<SyntaxChecker> syntaxCheckers,
9997
final Dictionary<Digester> digesters,
100-
final Dictionary<Constructor<? extends KeywordValidator>> validators,
98+
final Dictionary<KeywordValidatorFactory> validators,
10199
final Dictionary<FormatAttribute> formatAttributes)
102100
{
103101
this.syntaxCheckers = syntaxCheckers;
@@ -131,7 +129,7 @@ public Dictionary<Digester> getDigesters()
131129
*
132130
* @return a dictionary
133131
*/
134-
public Dictionary<Constructor<? extends KeywordValidator>> getValidators()
132+
public Dictionary<KeywordValidatorFactory> getValidators()
135133
{
136134
return validators;
137135
}

src/main/java/com/github/fge/jsonschema/library/LibraryBuilder.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,11 @@
2525
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
2626
import com.github.fge.jsonschema.format.FormatAttribute;
2727
import com.github.fge.jsonschema.keyword.digest.Digester;
28-
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
28+
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
2929
import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
3030
import com.github.fge.msgsimple.bundle.MessageBundle;
3131
import com.github.fge.msgsimple.load.MessageBundles;
3232

33-
import java.lang.reflect.Constructor;
34-
3533
/**
3634
* Mutable version of a library
3735
*
@@ -60,7 +58,7 @@ public final class LibraryBuilder
6058
/**
6159
* Dictionary builder of keyword validator constructors
6260
*/
63-
final DictionaryBuilder<Constructor<? extends KeywordValidator>> validators;
61+
final DictionaryBuilder<KeywordValidatorFactory> validators;
6462

6563
/**
6664
* Dictionary builder of format attributes
@@ -107,9 +105,9 @@ public LibraryBuilder addKeyword(final Keyword keyword)
107105

108106
syntaxCheckers.addEntry(name, keyword.syntaxChecker);
109107

110-
if (keyword.constructor != null) {
108+
if (keyword.validatorFactory != null) {
111109
digesters.addEntry(name, keyword.digester);
112-
validators.addEntry(name, keyword.constructor);
110+
validators.addEntry(name, keyword.validatorFactory);
113111
}
114112
return this;
115113
}

src/main/java/com/github/fge/jsonschema/library/validator/CommonValidatorDictionary.java

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919

2020
package com.github.fge.jsonschema.library.validator;
2121

22-
import com.fasterxml.jackson.databind.JsonNode;
2322
import com.github.fge.jsonschema.core.util.Dictionary;
2423
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
2524
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
25+
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
26+
import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
2627
import com.github.fge.jsonschema.keyword.validator.common.AdditionalItemsValidator;
2728
import com.github.fge.jsonschema.keyword.validator.common.AdditionalPropertiesValidator;
2829
import com.github.fge.jsonschema.keyword.validator.common.EnumValidator;
@@ -35,27 +36,25 @@
3536
import com.github.fge.jsonschema.keyword.validator.common.PatternValidator;
3637
import com.github.fge.jsonschema.keyword.validator.common.UniqueItemsValidator;
3738

38-
import java.lang.reflect.Constructor;
39-
4039
/**
4140
* Keyword validator constructors common to draft v4 and v3
4241
*/
4342
public final class CommonValidatorDictionary
4443
{
45-
private static final Dictionary<Constructor<? extends KeywordValidator>>
44+
private static final Dictionary<KeywordValidatorFactory>
4645
DICTIONARY;
4746

4847
private CommonValidatorDictionary()
4948
{
5049
}
5150

52-
public static Dictionary<Constructor<? extends KeywordValidator>> get()
51+
public static Dictionary<KeywordValidatorFactory> get()
5352
{
5453
return DICTIONARY;
5554
}
5655

5756
static {
58-
final DictionaryBuilder<Constructor<? extends KeywordValidator>>
57+
final DictionaryBuilder<KeywordValidatorFactory>
5958
builder = Dictionary.newBuilder();
6059

6160
String keyword;
@@ -66,67 +65,63 @@ public static Dictionary<Constructor<? extends KeywordValidator>> get()
6665
*/
6766
keyword = "additionalItems";
6867
c = AdditionalItemsValidator.class;
69-
builder.addEntry(keyword, constructor(c));
68+
builder.addEntry(keyword, factory(keyword, c));
7069

7170
keyword = "minItems";
7271
c = MinItemsValidator.class;
73-
builder.addEntry(keyword, constructor(c));
72+
builder.addEntry(keyword, factory(keyword, c));
7473

7574
keyword = "maxItems";
7675
c = MaxItemsValidator.class;
77-
builder.addEntry(keyword, constructor(c));
76+
builder.addEntry(keyword, factory(keyword, c));
7877

7978
keyword = "uniqueItems";
8079
c = UniqueItemsValidator.class;
81-
builder.addEntry(keyword, constructor(c));
80+
builder.addEntry(keyword, factory(keyword, c));
8281

8382
/*
8483
* Numbers and integers
8584
*/
8685
keyword = "minimum";
8786
c = MinimumValidator.class;
88-
builder.addEntry(keyword, constructor(c));
87+
builder.addEntry(keyword, factory(keyword, c));
8988

9089
keyword = "maximum";
9190
c = MaximumValidator.class;
92-
builder.addEntry(keyword, constructor(c));
91+
builder.addEntry(keyword, factory(keyword, c));
9392

9493
/*
9594
* Objects
9695
*/
9796
keyword = "additionalProperties";
9897
c = AdditionalPropertiesValidator.class;
99-
builder.addEntry(keyword, constructor(c));
98+
builder.addEntry(keyword, factory(keyword, c));
10099

101100
/*
102101
* Strings
103102
*/
104103
keyword = "minLength";
105104
c = MinLengthValidator.class;
106-
builder.addEntry(keyword, constructor(c));
105+
builder.addEntry(keyword, factory(keyword, c));
107106

108107
keyword = "maxLength";
109108
c = MaxLengthValidator.class;
110-
builder.addEntry(keyword, constructor(c));
109+
builder.addEntry(keyword, factory(keyword, c));
111110

112111
keyword = "pattern";
113112
c = PatternValidator.class;
114-
builder.addEntry(keyword, constructor(c));
113+
builder.addEntry(keyword, factory(keyword, c));
115114

116115
keyword = "enum";
117116
c = EnumValidator.class;
118-
builder.addEntry(keyword, constructor(c));
117+
builder.addEntry(keyword, factory(keyword, c));
119118

120119
DICTIONARY = builder.freeze();
121120
}
122121

123-
private static Constructor<? extends KeywordValidator> constructor(
122+
private static KeywordValidatorFactory factory(String name,
124123
final Class<? extends KeywordValidator> c)
125124
{
126-
try {
127-
return c.getConstructor(JsonNode.class);
128-
} catch (NoSuchMethodException e) {
129-
throw new RuntimeException("No appropriate constructor", e);
130-
}
125+
return new ReflectionKeywordValidatorFactory(name, c);
131126
}
132127
}

0 commit comments

Comments
 (0)