001/*
002 * ============================================================================
003 * Copyright © 2002-2026 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 *
007 * Licensed to the public under the agreements of the GNU Lesser General Public
008 * License, version 3.0 (the "License"). You may obtain a copy of the License at
009 *
010 *      http://www.gnu.org/licenses/lgpl.html
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015 * License for the specific language governing permissions and limitations
016 * under the License.
017 */
018
019package org.tquadrat.foundation.lang.internal;
020
021import org.apiguardian.api.API;
022import org.tquadrat.foundation.annotation.ClassVersion;
023import org.tquadrat.foundation.annotation.MountPoint;
024import org.tquadrat.foundation.lang.StringConverter;
025
026import java.io.Serial;
027import java.util.Collection;
028import java.util.List;
029
030import static java.lang.String.format;
031import static java.util.Arrays.stream;
032import static org.apiguardian.api.API.Status.INTERNAL;
033import static org.tquadrat.foundation.lang.Objects.isNull;
034import static org.tquadrat.foundation.lang.Objects.nonNull;
035import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
036
037/**
038 *  <p>{@summary The default implementation of
039 *  {@link StringConverter}
040 *  for types that are derived from
041 *  {@link Enum}.}</p>
042 *  <p>The implementation of
043 *  {@link #fromString(CharSequence)}
044 *  provided here uses
045 *  {@link Class#getEnumConstants()}
046 *  to find the {@code enum} value:</p>
047 *  <div class="source-container"><pre>&hellip;
048 *  T result = stream( m_EnumType.getEnumConstants() )
049 *      .filter( constant -&gt; value.equals( constant.name() ) )
050 *      .findFirst()
051 *      .orElseThrow( () -&gt; new IllegalArgumentException( &hellip; );
052 *  &hellip;</pre></div>
053 *  <p>The implementation of
054 *  {@link #toString(Enum)}
055 *  in this class will return the value of
056 *  {@link Enum#name()}.</p>
057 *
058 *  @param  <T> The concrete data type that is handled by this string converter
059 *      implementation.
060 *
061 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
062 *  @version $Id: DefaultEnumStringConverter.java 1163 2026-03-20 15:28:33Z tquadrat $
063 *  @since 0.1.0
064 *
065 *  @UMLGraph.link
066 */
067@ClassVersion( sourceVersion = "$Id: DefaultEnumStringConverter.java 1163 2026-03-20 15:28:33Z tquadrat $" )
068@API( status = INTERNAL, since = "0.1.0" )
069public class DefaultEnumStringConverter<T extends Enum<T>> implements StringConverter<T>
070{
071        /*-----------*\
072    ====** Constants **========================================================
073        \*-----------*/
074    /**
075     *  The error message for the name of an unknown class on the command line:
076     *  {@value}.
077     */
078    public static final String MSG_UnknownValue = "Unknown/invalid value: %1$s";
079
080        /*------------*\
081    ====** Attributes **=======================================================
082        \*------------*/
083    /**
084     *  The data type of the property to set.
085     *
086     *  @serial
087     */
088    private final Class<T> m_EnumType;
089
090        /*------------------------*\
091    ====** Static Initialisations **===========================================
092        \*------------------------*/
093    /**
094     *  The serial version UID for objects of this class: {@value}.
095     *
096     *  @hidden
097     */
098    @Serial
099    private static final long serialVersionUID = 1L;
100
101        /*--------------*\
102    ====** Constructors **=====================================================
103        \*--------------*/
104    /**
105     *  Creates a new {@code EnumValueHandler} instance.
106     *
107     *  @param  enumType    The data type for the property.
108     */
109    public DefaultEnumStringConverter( final Class<T> enumType )
110    {
111        m_EnumType = requireNonNullArgument( enumType, "enumType" );
112    }   //  EnumValueHandler()
113
114        /*---------*\
115    ====** Methods **==========================================================
116        \*---------*/
117    /**
118     *  {@inheritDoc}
119     */
120    @MountPoint
121    @Override
122    public T fromString( final CharSequence source ) throws IllegalArgumentException
123    {
124        T retValue = null;
125        if( nonNull( source ) )
126        {
127            if( source.isEmpty() ) throw new IllegalArgumentException( format( MSG_UnknownValue, source ) );
128            retValue = stream( m_EnumType.getEnumConstants() )
129                .filter( constant -> source.toString().equals( constant.name() ) )
130                .findFirst()
131                .orElseThrow( () -> new IllegalArgumentException( format( MSG_UnknownValue, source ) ) );
132        }
133
134        //---* Done *----------------------------------------------------------
135        return retValue;
136    }   //  fromString()
137
138    /**
139     *  Provides the subject class for this converter.
140     *
141     * @return The subject class.
142     */
143    @SuppressWarnings( "PublicMethodNotExposedInInterface" )
144    public final Collection<Class<T>> getSubjectClass() { return List.of( m_EnumType ); }
145
146    /**
147     *  {@inheritDoc}
148     */
149    @MountPoint
150    @Override
151    public String toString( final T source )
152    {
153        final var retValue = isNull( source ) ? null : source.name();
154
155        //---* Done *----------------------------------------------------------
156        return retValue;
157    }   //  toString()
158}
159//  class DefaultEnumStringConverter
160
161/*
162 *  End of File
163 */