All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.harrel.jsonschema.EvaluatorFactory Maven / Gradle / Ivy

There is a newer version: 1.7.3
Show newest version
package dev.harrel.jsonschema;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

import static java.util.Collections.*;

/**
 * {@code EvaluatorFactory} interface is responsible for creation of {@link Evaluator} instances.
 * It should hold information about keyword relation with {@link Evaluator}.
 */
public interface EvaluatorFactory {
    /**
     * This method will be invoked for each JSON object field during schema parsing process.
     * Must not throw any exceptions.
     *
     * @param ctx       current schema parsing context
     * @param fieldName field name (keyword) in JSON object for which {@link Evaluator} should be created
     * @param fieldNode value of field in JSON object
     * @return If this factory supports given field name (keyword) it should return corresponding {@link Evaluator}
     * wrapped in {@link Optional}, {@code Optional.empty()} otherwise.
     */
    Optional create(SchemaParsingContext ctx, String fieldName, JsonNode fieldNode);

    /**
     * Composes multiple {@link EvaluatorFactory} instances into one.
     * Calls {@link EvaluatorFactory#create(SchemaParsingContext, String, JsonNode)} on each instance until non-empty
     * {@code Optional} is returned.
     * @param factories EvaluatorFactories to be composed
     * @return composed EvaluatorFactory
     */
    static EvaluatorFactory compose(EvaluatorFactory... factories) {
        return new CompositeEvaluatorFactory(factories);
    }

    /**
     * Builder for constructing {@link EvaluatorFactory} instances which is an alternative for providing a custom implementation.
     * It is recommended when the {@code Evaluator} creation logic is simple and depends only on keyword name.
     * To create factory which supports only "custom" and "type" keywords, you can write the following code:
     * 
     *     new EvaluatorFactory.Builder()
     *          .withKeyword("custom", CustomEvaluator::new)
     *          .withKeyword("type", CustomTypeEvaluator::new)
     *          .build();
     * 
*/ final class Builder { private final Map> providers = new HashMap<>(); /** * Registers an evaluator with a given keyword. * @implNote As creating an evaluator might depend on keyword value (or type), provided function might return null * or throw an exception to cancel registration process. * @param keyword field name in JSON schema object * @param evaluatorProvider function that creates {@code Evaluator} instance. Invoked only during schema parsing process. * Can return null or throw an exception, which will cancel the registration process. * @return this */ public Builder withKeyword(String keyword, BiFunction evaluatorProvider) { providers.put(Objects.requireNonNull(keyword), Objects.requireNonNull(evaluatorProvider)); return this; } /** * @see EvaluatorFactory.Builder#withKeyword(String, BiFunction) */ public Builder withKeyword(String keyword, Function evaluatorProvider) { return withKeyword(keyword, (ctx, jsonNode) -> evaluatorProvider.apply(jsonNode)); } /** * @see EvaluatorFactory.Builder#withKeyword(String, BiFunction) */ public Builder withKeyword(String keyword, Supplier evaluatorProvider) { return withKeyword(keyword, (ctx, jsonNode) -> evaluatorProvider.get()); } /** * Creates factory instance. * @return factory instance */ public EvaluatorFactory build() { return new MapEvaluatorFactory(providers); } } } final class CompositeEvaluatorFactory implements EvaluatorFactory { private final EvaluatorFactory[] factories; CompositeEvaluatorFactory(EvaluatorFactory[] factories) { this.factories = factories; } @Override public Optional create(SchemaParsingContext ctx, String fieldName, JsonNode fieldNode) { return Arrays.stream(factories) .map(factory -> factory.create(ctx, fieldName, fieldNode)) .filter(Optional::isPresent) .map(Optional::get) .findFirst(); } } final class MapEvaluatorFactory implements EvaluatorFactory { private final Map> providers; MapEvaluatorFactory(Map> providers) { this.providers = unmodifiableMap(new HashMap<>(providers)); } @Override public Optional create(SchemaParsingContext ctx, String fieldName, JsonNode fieldNode) { BiFunction provider = providers.get(fieldName); if (provider == null) { return Optional.empty(); } try { return Optional.ofNullable(provider.apply(ctx, fieldNode)); } catch (Exception e) { return Optional.empty(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy