Generator.java

package dev.orne.test.rnd;

/*-
 * #%L
 * Orne Test Generators
 * %%
 * Copyright (C) 2021 Orne Developments
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import javax.validation.constraints.NotNull;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;

import dev.orne.test.rnd.params.GeneratorNotParameterizableException;
import dev.orne.test.rnd.params.ParameterizableGenerator;

/**
 * Interface for random value generators.
 * 
 * @author <a href="mailto:wamphiry@orne.dev">(w) Iker Hernaez</a>
 * @version 1.0, 2021-03
 * @since 0.1
 */
@API(status=Status.STABLE, since="0.1")
public interface Generator {

    /**
     * Checks if values of the specified type can be generated by this
     * instance.
     * 
     * @param type The type to check.
     * @return If values of the specified type can be generated.
     */
    boolean supports(@NotNull Class<?> type);

    /**
     * Returns the default value for the specified type.
     * 
     * @param <T> The requested value type.
     * @param type The requested value type.
     * @return The default value for the specified type.
     * @throws UnsupportedValueTypeException If the specified type is not supported.
     * @throws GenerationException If an error occurs generating the value
     */
    @NotNull <T> T defaultValue(@NotNull Class<T> type);

    /**
     * Returns the default value for the specified type allowing {@code null}
     * values.
     * <p>
     * This method should return {@code null} except for native types.
     * 
     * @param <T> The requested value type.
     * @param type The requested value type.
     * @return The nullable default value for the specified type.
     * @throws UnsupportedValueTypeException If the specified type is not supported.
     * @throws GenerationException If an error occurs generating the value
     */
    <T> T nullableDefaultValue(@NotNull Class<T> type);

    /**
     * Returns a random value of the specified type.
     * 
     * @param <T> The requested value type.
     * @param type The requested value type.
     * @return A random value for the specified type.
     * @throws UnsupportedValueTypeException If the specified type is not supported.
     * @throws GenerationException If an error occurs generating the value
     */
    @NotNull <T> T randomValue(@NotNull Class<T> type);

    /**
     * Returns a random value of the specified type allowing {@code null}
     * values.
     * <p>
     * The returned value has a probability of be {@code null} except for
     * native types. If not {@code null} behaves as {@code randomValue()}.
     * 
     * @param <T> The requested value type.
     * @param type The requested value type.
     * @return A random nullable value for the specified type.
     * @throws UnsupportedValueTypeException If the specified type is not supported.
     * @throws GenerationException If an error occurs generating the value
     * @see #randomValue(Class)
     */
    <T> T nullableRandomValue(@NotNull Class<T> type);

    /**
     * Returns the priority of this generator.
     * 
     * @return The priority of this generator
     */
    default int getPriority() {
        final Class<?> type = getClass();
        final Priority annot = type.getAnnotation(Priority.class);
        return annot == null ? Priority.DEFAULT : annot.value();
    }

    /**
     * Returns this generator as a parameterizable generator.
     * <p>
     * If the generator is not parameterizable throws an exception.
     * 
     * @return This generator as a parameterizable generator.
     * @throws GeneratorNotParameterizableException If the generator
     * is not parameterizable.
     */
    default @NotNull ParameterizableGenerator asParameterizable() {
        if (!(this instanceof ParameterizableGenerator)) {
            throw new GeneratorNotParameterizableException(
                    String.format("Generator of type %s is not parameterizable", getClass()));
        }
        return (ParameterizableGenerator) this;
    }
}