<commit_before>package net.dean.jraw.models.meta;

import net.dean.jraw.models.JsonModel;
import org.codehaus.jackson.JsonNode;

import java.util.HashMap;
import java.util.Map;

/**
 * This class is responsible for managing the creation of JsonModels. It keeps a cache of common {@link JsonSerializer}s
 * and {@link Model} classes. This class is a singleton.
 */
public class ModelManager {
    private static ModelManager instance = new ModelManager();
    public static ModelManager getInstance() { return instance; }

    /**
     * Convenience method equivalent to {@link #getInstance()}.{@link #parse(JsonNode, Class)}
     */
    public static <T extends JsonModel> T create(JsonNode rootNode, Class<T> expectedClass) {
        return getInstance().parse(rootNode, expectedClass);
    }

    private Map<Class<?>, Model> modelCache;
    private Map<Class<? extends JsonSerializer>, JsonSerializer> serializers;

    private ModelManager() {
        this.modelCache = new HashMap<>();
        this.serializers = new HashMap<>();
    }

    /**
     * Asserts that the given class contains a {@link Model} annotation and returns it
     */
    private Model ensureModelClass(Class<?> clazz) {
        // modelCache will only contain classes that have the @Model annotation
        if (!modelCache.containsKey(clazz)) {
            if (!clazz.isAnnotationPresent(Model.class)) {
                throw new IllegalArgumentException(String.format("Class %s is not annotated with %s",
                        clazz.getName(), Model.class.getName()));
            }
        }

        return clazz.getAnnotation(Model.class);
    }

    /**
     * Gets the instance of the JsonSerializer for the given Model class.
     * @param clazz The class that has the Model annotation
     */
    private JsonSerializer getSerializer(Class<? extends JsonModel> clazz) {
        ensureModelClass(clazz);
        Class<? extends JsonSerializer> serClass = clazz.getAnnotation(Model.class).serializer();
        if (serializers.containsKey(serClass)) {
            return serializers.get(serClass);
        }

        JsonSerializer serializer;
        try {
            serializer = serClass.newInstance();
        } catch (InstantiationException e) {
            throw new IllegalArgumentException("JsonSerializer " + clazz.getName() + " has no default constructor or is abstract");
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        serializers.put(serClass, serializer);
        return serializer;
    }

    /**
     * Gets the Model annotation for the given class
     */
    private Model getModel(Class<?> modelClass) {
        ensureModelClass(modelClass);

        if (modelCache.containsKey(modelClass)) {
            return modelCache.get(modelClass);
        }

        Model model = modelClass.getAnnotation(Model.class);
        modelCache.put(modelClass, model);
        return model;
    }

    /**
     * Validates that the given JsonNode can be applied to the given class. If the value of {@link Model#kind()} does
     * not match the value of
     *
     * @param rootNode The root node of the JSON model. Must contain two children: "kind" and "data".
     * @param expectedClass The class to use as validation.
     */
    public void validate(JsonNode rootNode, Class<?> expectedClass) {
        Model type = getModel(expectedClass);
        if (!rootNode.has("kind")) {
            throw new IllegalArgumentException("JsonNode does not have a 'kind' child");
        }

        String actual = rootNode.get("kind").asText();
        String expected = type.kind().getValue();
        if (!rootNode.get("kind").asText().equals(type.kind().getValue())) {
            throw new IllegalArgumentException(String.format("Expected kind was not found. Expected '%s', got '%s'",
                    expected, actual));
        }
    }

    /**
     * Parses a JsonNode into a JsonModel. The given class must be annotated with {@link Model}. If the Model's kind()
     * is {@link Model.Kind#ABSTRACT} or {@link Model.Kind#NONE}, then the JsonNode will not be validated via<commit_msg>Add missing javadoc<commit_after>package net.dean.jraw.models.meta;

import net.dean.jraw.models.JsonModel;
import org.codehaus.jackson.JsonNode;

import java.util.HashMap;
import java.util.Map;

/**
 * This class is responsible for managing the creation of JsonModels. It keeps a cache of common {@link JsonSerializer}s
 * and {@link Model} classes. This class is a singleton.
 */
public class ModelManager {
    private static ModelManager instance = new ModelManager();
    public static ModelManager getInstance() { return instance; }

    /**
     * Convenience method equivalent to {@link #getInstance()}.{@link #parse(JsonNode, Class)}
     */
    public static <T extends JsonModel> T create(JsonNode rootNode, Class<T> expectedClass) {
        return getInstance().parse(rootNode, expectedClass);
    }

    private Map<Class<?>, Model> modelCache;
    private Map<Class<? extends JsonSerializer>, JsonSerializer> serializers;

    private ModelManager() {
        this.modelCache = new HashMap<>();
        this.serializers = new HashMap<>();
    }

    /**
     * Asserts that the given class contains a {@link Model} annotation and returns it
     */
    private Model ensureModelClass(Class<?> clazz) {
        // modelCache will only contain classes that have the @Model annotation
        if (!modelCache.containsKey(clazz)) {
            if (!clazz.isAnnotationPresent(Model.class)) {
                throw new IllegalArgumentException(String.format("Class %s is not annotated with %s",
                        clazz.getName(), Model.class.getName()));
            }
        }

        return clazz.getAnnotation(Model.class);
    }

    /**
     * Gets the instance of the JsonSerializer for the given Model class.
     * @param clazz The class that has the Model annotation
     */
    private JsonSerializer getSerializer(Class<? extends JsonModel> clazz) {
        ensureModelClass(clazz);
        Class<? extends JsonSerializer> serClass = clazz.getAnnotation(Model.class).serializer();
        if (serializers.containsKey(serClass)) {
            return serializers.get(serClass);
        }

        JsonSerializer serializer;
        try {
            serializer = serClass.newInstance();
        } catch (InstantiationException e) {
            throw new IllegalArgumentException("JsonSerializer " + clazz.getName() + " has no default constructor or is abstract");
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        serializers.put(serClass, serializer);
        return serializer;
    }

    /**
     * Gets the Model annotation for the given class
     */
    private Model getModel(Class<?> modelClass) {
        ensureModelClass(modelClass);

        if (modelCache.containsKey(modelClass)) {
            return modelCache.get(modelClass);
        }

        Model model = modelClass.getAnnotation(Model.class);
        modelCache.put(modelClass, model);
        return model;
    }

    /**
     * Validates that the given JsonNode can be applied to the given class. If the value of {@link Model#kind()} does
     * not match the value of the "kind" node, then an IllegalArgumentException is thrown.
     *
     * @param rootNode The root node of the JSON model. Must contain two children: "kind" and "data".
     * @param expectedClass The class to use as validation.
     * @throws IllegalArgumentException If the root node does not have a "kind" node or if the expected value for that
     *                                  node was not found.
     */
    public void validate(JsonNode rootNode, Class<?> expectedClass) {
        Model type = getModel(expectedClass);
        if (!rootNode.has("kind")) {
            throw new IllegalArgumentException("JsonNode does not have a 'kind' child");
        }

        String actual = rootNode.get("kind").asText();
        String expected = type.kind().getValue();
        if (!rootNode.get("kind").asText().equals(type.kind().getValue())) {
            throw new IllegalArgumentException(String.format("Expected kind was not found. Expected '%s', got '%s'",
                    expected, actual));
        }
    }

    /**
     * Parses a JsonNode into a JsonModel. The given class must be annotated with {@link Model}. If the Model's kind()
     * is {@link Model.Kind#ABSTRACT} or {@link Model.Kind#NONE}, then the JsonNode will not be validated via
{'fraction_non_alphanumeric': 0.10274454609429978, 'fraction_numerical': 0.0, 'mean_word_length': 2.7122333478450154, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3399334', 'n_tokens_mistral': 2198, 'n_tokens_neox': 2148, 'n_words': 724}