001/*
002 * JDrupes Builder
003 * Copyright (C) 2025 Michael N. Lipp
004 * 
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.builder.api;
020
021import java.util.function.Supplier;
022
023/// Defines a named parameter. Java doesn't have named parameters, but
024/// this comes pretty close. Define the named parameters that you need
025/// as static members of your class:
026///
027///     public static NamedParameter<String> name(String name) {
028///         return new NamedParameter<>("name", name);
029///     }
030/// 
031/// Defines the method that is to be invoked with named parameters as
032///
033///     public void method(NamedParameter<?>... params) {
034///         var name = NamedParameter.<String> get(params, "name", null);
035///     }
036///
037/// And invoke it with:
038///
039///     method(name("test"));
040///
041/// Of course, this requires a static import for `name`. If you have several
042/// classes using the pattern, you'll have to use `className.paramName(...)`
043/// to provide the value for the parameter which is, admittedly less elegant.
044///
045/// A possible workaround is to define a hierarchy of classes with
046/// [NamedParameter] as base class and put commonly used names in the base
047/// classes. 
048///
049/// @param <T> the generic type
050/// @param name the name
051/// @param value the value
052///
053public record NamedParameter<T>(String name, T value) {
054
055    /// Looks up the named parameter with the given `name` in array
056    /// of [NamedParameter]s. If it isn't found, return the result
057    /// from invoking the supplier (or `null`).
058    ///
059    /// @param <T> the generic type
060    /// @param parameters the parameters
061    /// @param name the name
062    /// @param fallback supplier for a fallback value or `null`
063    /// @return the value
064    ///
065    @SuppressWarnings("unchecked")
066    public static <T> T get(NamedParameter<?>[] parameters, String name,
067            Supplier<T> fallback) {
068        for (var param : parameters) {
069            if (param.name.equals(name)) {
070                return (T) param.value;
071            }
072        }
073        if (fallback != null) {
074            return fallback.get();
075        }
076        return null;
077    }
078}