ProvidedAttribute.java

/*
 *
 * The DbUnit Database Testing Framework
 * Copyright (C)2002-2026, DbUnit.org
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
package org.dbunit.annotation.runtime;

/**
 * The shared rules, and the one message shape, for an {@code org.dbunit.annotation} attribute
 * that can be given inline or through a provider class. Three rules recur across
 * {@code @DbUnitPrep}/{@code @DbUnitExpected} {@code value()}/{@code provider()},
 * {@code @DbUnitConfig} {@code properties()}/{@code propertiesProvider()}, {@code @DbUnitExpected}
 * {@code verify()}/{@code verifyDefinitions()}/{@code verifyTables()}, and
 * {@code @DbUnitConfig} {@code databaseTesterFactory()}: setting two mutually exclusive ways is
 * an error, a provider returning {@code null} is an error, and a provider returning nothing -
 * where nothing is a misconfiguration rather than a valid "none" - is an error. Routing every
 * site's diagnostic through here keeps a user who trips two of them across different attributes
 * from getting two differently shaped messages for the same class of mistake.
 *
 * <p>Public so a binding outside {@code org.dbunit.annotation.runtime} - such as
 * {@code DbUnitExtension}, for {@code databaseTesterFactory()} - can reach it too.
 *
 * @author Jeff Jensen
 * @since 3.6.0
 */
public class ProvidedAttribute
{
    private ProvidedAttribute()
    {
    }

    /**
     * Throws an {@link IllegalStateException} when two mutually exclusive ways of setting the
     * same attribute were both used.
     *
     * @param bothSet Whether both were given a non-default value.
     * @param owner The annotation carrying both attributes, with the test class where that
     *            adds clarity, e.g. {@code "@DbUnitConfig"} or
     *            {@code "@DbUnitPrep on com.example.FooTest"}.
     * @param attributeA One attribute, e.g. {@code "value()"}.
     * @param attributeB The other, e.g. {@code "provider()"}.
     * @param note An extra sentence appended after {@code "set only one."}, or {@code null} for
     *            none.
     */
    public static void rejectBothSet(final boolean bothSet, final String owner,
            final String attributeA, final String attributeB, final String note)
    {
        if (!bothSet)
        {
            return;
        }
        final String tail = note == null ? "" : " " + note;
        throw new IllegalStateException(owner + " sets both " + attributeA + " and "
                + attributeB + "; set only one." + tail);
    }

    /**
     * Returns {@code provided} unless the provider returned {@code null}, in which case it
     * throws an {@link IllegalStateException} naming the provider, its class, the attribute
     * that named it, and the method called.
     *
     * @param <T> The provider's value type.
     * @param provided The value the provider returned.
     * @param providerInterface The provider interface's simple name, e.g.
     *            {@code "DataSetPathsProvider"}.
     * @param providerClass The provider implementation class.
     * @param namedBy The attribute that named the provider, e.g. {@code "@DbUnitPrep.provider"}.
     * @param getter The provider method called, without parentheses, e.g. {@code "getDataSetPaths"}.
     * @return {@code provided}, when non-{@code null}.
     */
    public static <T> T requireProvided(final T provided, final String providerInterface,
            final Class<?> providerClass, final String namedBy, final String getter)
    {
        if (provided == null)
        {
            throw new IllegalStateException(describe(providerInterface, providerClass, namedBy)
                    + " returned null from " + getter + "().");
        }
        return provided;
    }

    /**
     * Throws an {@link IllegalStateException} when a provider returned nothing.
     *
     * @param empty Whether the provider's output is empty.
     * @param providerInterface The provider interface's simple name.
     * @param providerClass The provider implementation class.
     * @param namedBy The attribute that named the provider.
     * @param getter The provider method called, without parentheses.
     * @param note Guidance appended to the message explaining why nothing is a misconfiguration.
     */
    public static void rejectEmptyProvider(final boolean empty, final String providerInterface,
            final Class<?> providerClass, final String namedBy, final String getter,
            final String note)
    {
        if (empty)
        {
            throw new IllegalStateException(describe(providerInterface, providerClass, namedBy)
                    + " returned nothing from " + getter + "(). " + note);
        }
    }

    private static String describe(final String providerInterface, final Class<?> providerClass,
            final String namedBy)
    {
        return providerInterface + " " + providerClass.getName() + ", named by " + namedBy + ",";
    }
}