Skip to content

Switch KeywordValidators to use a factory model #221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.github.fge.jsonschema.keyword.validator;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;

/**
* Interface for a keyword validator factory
*/
public interface KeywordValidatorFactory
{
/**
* Create a validator for the instance
*
* @param node the instance to validate
* @return a validator for the given instance
* @throws ProcessingException an error occurs creating the validator
*/
KeywordValidator getKeywordValidator(JsonNode node)
throws ProcessingException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.github.fge.jsonschema.keyword.validator;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;

/**
* A validator factory that uses reflection to create an instance of the
* specified KeywordValidator class
*/
public class ReflectionKeywordValidatorFactory
implements KeywordValidatorFactory
{
private static final String ERRMSG = "failed to build keyword validator";
private static final MessageBundle BUNDLE
= MessageBundles.getBundle(JsonSchemaConfigurationBundle.class);

private final Constructor<? extends KeywordValidator> constructor;

public ReflectionKeywordValidatorFactory(String name,
Class<? extends KeywordValidator> clazz)
{
try {
constructor = clazz.getConstructor(JsonNode.class);
} catch (NoSuchMethodException ignored) {
throw new IllegalArgumentException(BUNDLE.printf(
"noAppropriateConstructor", name, clazz.getCanonicalName()
));
}
}

@Override
public KeywordValidator getKeywordValidator(JsonNode node)
throws ProcessingException
{
try {
return constructor.newInstance(node);
} catch (InstantiationException e) {
throw new ProcessingException(ERRMSG, e);
} catch (IllegalAccessException e) {
throw new ProcessingException(ERRMSG, e);
} catch (InvocationTargetException e) {
throw new ProcessingException(ERRMSG, e);
}
}

}
10 changes: 4 additions & 6 deletions src/main/java/com/github/fge/jsonschema/library/Keyword.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@
import com.github.fge.Frozen;
import com.github.fge.jsonschema.core.keyword.syntax.checkers.SyntaxChecker;
import com.github.fge.jsonschema.keyword.digest.Digester;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;

import java.lang.reflect.Constructor;
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;


/**
Expand All @@ -51,9 +49,9 @@ public final class Keyword
final Digester digester;

/**
* {@link KeywordValidator} constructor
* Validator factory
*/
final Constructor<? extends KeywordValidator> constructor;
final KeywordValidatorFactory validatorFactory;

/**
* Instantiate a new keyword builder
Expand All @@ -79,7 +77,7 @@ public static KeywordBuilder newBuilder(final String name)
name = builder.name;
syntaxChecker = builder.syntaxChecker;
digester = builder.digester;
constructor = builder.constructor;
validatorFactory = builder.validatorFactory;
}

/**
Expand Down
39 changes: 19 additions & 20 deletions src/main/java/com/github/fge/jsonschema/library/KeywordBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,19 @@

package com.github.fge.jsonschema.library;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.Thawed;
import com.github.fge.jackson.NodeType;
import com.github.fge.jsonschema.core.keyword.syntax.checkers.SyntaxChecker;
import com.github.fge.jsonschema.keyword.digest.Digester;
import com.github.fge.jsonschema.keyword.digest.helpers.IdentityDigester;
import com.github.fge.jsonschema.keyword.digest.helpers.SimpleDigester;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;

import java.lang.reflect.Constructor;

/**
* A keyword builder -- the thawed version of a {@link Keyword}
*
Expand All @@ -48,7 +47,7 @@ public final class KeywordBuilder
final String name;
SyntaxChecker syntaxChecker;
Digester digester;
Constructor<? extends KeywordValidator> constructor;
KeywordValidatorFactory validatorFactory;

/**
* Create a new, empty keyword builder
Expand All @@ -74,7 +73,7 @@ public final class KeywordBuilder
name = keyword.name;
syntaxChecker = keyword.syntaxChecker;
digester = keyword.digester;
constructor = keyword.constructor;
validatorFactory = keyword.validatorFactory;
}

/**
Expand Down Expand Up @@ -149,7 +148,20 @@ public KeywordBuilder withSimpleDigester(final NodeType first,
public KeywordBuilder withValidatorClass(
final Class<? extends KeywordValidator> c)
{
constructor = getConstructor(name, c);
validatorFactory = new ReflectionKeywordValidatorFactory(name, c);
return this;
}

/**
* Set the validator factory for this keyword
*
* @param factory the factory
* @return this
*/
public KeywordBuilder withValidatorFactory(
KeywordValidatorFactory factory)
{
validatorFactory = factory;
return this;
}

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


private static Constructor<? extends KeywordValidator> getConstructor(
final String name, final Class<? extends KeywordValidator> c)
{
try {
return c.getConstructor(JsonNode.class);
} catch (NoSuchMethodException ignored) {
throw new IllegalArgumentException(BUNDLE.printf(
"noAppropriateConstructor", name, c.getCanonicalName()
));
}
}

private static NodeType checkType(final NodeType type)
{
return BUNDLE.checkNotNull(type, "nullType");
Expand Down
12 changes: 5 additions & 7 deletions src/main/java/com/github/fge/jsonschema/library/Library.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.format.FormatAttribute;
import com.github.fge.jsonschema.keyword.digest.Digester;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;

import java.lang.reflect.Constructor;
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;

/**
* A schema keyword library
Expand All @@ -54,9 +52,9 @@ public final class Library
final Dictionary<Digester> digesters;

/**
* Dictionary of keyword validator constructors
* Dictionary of keyword validator factories
*/
final Dictionary<Constructor<? extends KeywordValidator>> validators;
final Dictionary<KeywordValidatorFactory> validators;

/**
* Dictionary of format attributes
Expand Down Expand Up @@ -97,7 +95,7 @@ public static LibraryBuilder newBuilder()
*/
Library(final Dictionary<SyntaxChecker> syntaxCheckers,
final Dictionary<Digester> digesters,
final Dictionary<Constructor<? extends KeywordValidator>> validators,
final Dictionary<KeywordValidatorFactory> validators,
final Dictionary<FormatAttribute> formatAttributes)
{
this.syntaxCheckers = syntaxCheckers;
Expand Down Expand Up @@ -131,7 +129,7 @@ public Dictionary<Digester> getDigesters()
*
* @return a dictionary
*/
public Dictionary<Constructor<? extends KeywordValidator>> getValidators()
public Dictionary<KeywordValidatorFactory> getValidators()
{
return validators;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,11 @@
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.format.FormatAttribute;
import com.github.fge.jsonschema.keyword.digest.Digester;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;

import java.lang.reflect.Constructor;

/**
* Mutable version of a library
*
Expand Down Expand Up @@ -60,7 +58,7 @@ public final class LibraryBuilder
/**
* Dictionary builder of keyword validator constructors
*/
final DictionaryBuilder<Constructor<? extends KeywordValidator>> validators;
final DictionaryBuilder<KeywordValidatorFactory> validators;

/**
* Dictionary builder of format attributes
Expand Down Expand Up @@ -107,9 +105,9 @@ public LibraryBuilder addKeyword(final Keyword keyword)

syntaxCheckers.addEntry(name, keyword.syntaxChecker);

if (keyword.constructor != null) {
if (keyword.validatorFactory != null) {
digesters.addEntry(name, keyword.digester);
validators.addEntry(name, keyword.constructor);
validators.addEntry(name, keyword.validatorFactory);
}
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@

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

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
import com.github.fge.jsonschema.keyword.validator.common.AdditionalItemsValidator;
import com.github.fge.jsonschema.keyword.validator.common.AdditionalPropertiesValidator;
import com.github.fge.jsonschema.keyword.validator.common.EnumValidator;
Expand All @@ -35,27 +36,25 @@
import com.github.fge.jsonschema.keyword.validator.common.PatternValidator;
import com.github.fge.jsonschema.keyword.validator.common.UniqueItemsValidator;

import java.lang.reflect.Constructor;

/**
* Keyword validator constructors common to draft v4 and v3
*/
public final class CommonValidatorDictionary
{
private static final Dictionary<Constructor<? extends KeywordValidator>>
private static final Dictionary<KeywordValidatorFactory>
DICTIONARY;

private CommonValidatorDictionary()
{
}

public static Dictionary<Constructor<? extends KeywordValidator>> get()
public static Dictionary<KeywordValidatorFactory> get()
{
return DICTIONARY;
}

static {
final DictionaryBuilder<Constructor<? extends KeywordValidator>>
final DictionaryBuilder<KeywordValidatorFactory>
builder = Dictionary.newBuilder();

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

keyword = "minItems";
c = MinItemsValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

keyword = "maxItems";
c = MaxItemsValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

keyword = "uniqueItems";
c = UniqueItemsValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

/*
* Numbers and integers
*/
keyword = "minimum";
c = MinimumValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

keyword = "maximum";
c = MaximumValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

/*
* Objects
*/
keyword = "additionalProperties";
c = AdditionalPropertiesValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

/*
* Strings
*/
keyword = "minLength";
c = MinLengthValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

keyword = "maxLength";
c = MaxLengthValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

keyword = "pattern";
c = PatternValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

keyword = "enum";
c = EnumValidator.class;
builder.addEntry(keyword, constructor(c));
builder.addEntry(keyword, factory(keyword, c));

DICTIONARY = builder.freeze();
}

private static Constructor<? extends KeywordValidator> constructor(
private static KeywordValidatorFactory factory(String name,
final Class<? extends KeywordValidator> c)
{
try {
return c.getConstructor(JsonNode.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException("No appropriate constructor", e);
}
return new ReflectionKeywordValidatorFactory(name, c);
}
}
Loading