001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.spongepowered.configurate.objectmapping;
018
019import static java.util.Objects.requireNonNull;
020
021import org.checkerframework.checker.nullness.qual.Nullable;
022import org.spongepowered.configurate.serialize.SerializationException;
023import org.spongepowered.configurate.util.CheckedFunction;
024
025import java.lang.reflect.AnnotatedElement;
026import java.lang.reflect.AnnotatedType;
027import java.util.function.Supplier;
028
029/**
030 * Interface that gathers metadata from classes.
031 *
032 * <p>Any type of data object can be added this way.</p>
033 *
034 * @param <I> intermediate data type
035 * @since 4.0.0
036 */
037@FunctionalInterface
038public interface FieldDiscoverer<I> {
039
040    /**
041     * Create a new field discoverer that will handle record classes.
042     *
043     * <p>This discoverer will use the record's canonical constructor to create
044     * new instances, passing {@code null} for any missing parameters. The
045     * accessor methods for each record component will be used to read
046     * values from the record.</p>
047     *
048     * @implNote To avoid requiring preview features to run on Java 14 and 15,
049     *     the record discoverer accesses methods reflectively, and can safely
050     *     be created and applied to object mappers running on any Java version.
051     *     Continued support of preview features once they have been released in
052     *     a stable Java version is not guaranteed.
053     *
054     * @return new discoverer
055     * @since 4.0.0
056     */
057    static FieldDiscoverer<?> record() {
058        return RecordFieldDiscoverer.INSTANCE;
059    }
060
061    /**
062     * Create a new discoverer for object instance fields.
063     *
064     * <p>This discoverer will process any non-static and non-transient field
065     * in the object. Modifying {@code final} fields is unsupported and may stop
066     * working with newer Java versions.</p>
067     *
068     * @param instanceFactory a factory for instance providers
069     * @return new discoverer
070     * @since 4.0.0
071     */
072    static FieldDiscoverer<?> object(final CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> instanceFactory) {
073        return new ObjectFieldDiscoverer(requireNonNull(instanceFactory, "instanceFactory"), null, false);
074    }
075
076    /**
077     * Create a new discoverer for object instance fields.
078     *
079     * <p>This discoverer will process any non-static and non-transient field
080     * in the object. Modifying {@code final} fields is unsupported and may stop
081     * working with newer Java versions.</p>
082     *
083     * @param instanceFactory a factory for instance providers
084     * @param instanceUnavailableErrorMessage a message that will be part of the
085     *     exception thrown when trying to create instances for an
086     *     unsupported type
087     * @return new discoverer
088     * @since 4.1.0
089     */
090    static FieldDiscoverer<?> object(final CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> instanceFactory,
091            final String instanceUnavailableErrorMessage) {
092        requireNonNull(instanceUnavailableErrorMessage, "instanceUnavailableErrorMessage");
093        return new ObjectFieldDiscoverer(requireNonNull(instanceFactory, "instanceFactory"), instanceUnavailableErrorMessage, false);
094    }
095
096    /**
097     * Create a new discoverer for object instance fields.
098     *
099     * <p>This discoverer will process any non-static and non-transient field
100     * in the object. Modifying {@code final} fields is unsupported and may stop
101     * working with newer Java versions.</p>
102     *
103     * <p>This discoverer will only match objects that it can create an instance
104     * of (i. e. where {@code instanceFactory} returns a
105     * non-{@code null} supplier).</p>
106     *
107     * @param instanceFactory a factory for instance providers
108     * @return new discoverer
109     * @since 4.2.0
110     */
111    static FieldDiscoverer<?> instantiableObject(
112        final CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> instanceFactory
113    ) {
114        return new ObjectFieldDiscoverer(requireNonNull(instanceFactory, "instanceFactory"), null, true);
115    }
116
117    /**
118     * Create a new discoverer for object instance fields.
119     *
120     * <p>Only objects with empty constructors can be created.</p>
121     *
122     * @return new discoverer
123     * @see #object(CheckedFunction) for more details on which fields will
124     *      be discovered.
125     * @since 4.0.0
126     */
127    static FieldDiscoverer<?> emptyConstructorObject() {
128        return ObjectFieldDiscoverer.EMPTY_CONSTRUCTOR_INSTANCE;
129    }
130
131    /**
132     * Inspect the {@code target} type for fields to be supplied to
133     * the {@code collector}.
134     *
135     * <p>If the target type is handleable, a non-null value must be returned.
136     * Fields can only be collected from one source at the moment, so if the
137     * instance factory is null any discovered fields will be discarded.</p>
138     *
139     * @param target type to inspect
140     * @param collector collector for discovered fields.
141     * @param <V> object type
142     * @return a factory for handling the construction of object instances, or
143     *      {@code null} if {@code target} is not of a handleable type.
144     * @throws SerializationException if any fields have invalid data
145     * @since 4.0.0
146     */
147    <V> @Nullable InstanceFactory<I> discover(AnnotatedType target, FieldCollector<I, V> collector) throws SerializationException;
148
149    /**
150     * A handler that controls the deserialization process for an object.
151     *
152     * @param <I> intermediate type
153     * @since 4.0.0
154     */
155    interface InstanceFactory<I> {
156
157        /**
158         * Return a new instance of the intermediary type to be populated.
159         *
160         * @return new intermediate container
161         * @since 4.0.0
162         */
163        I begin();
164
165        /**
166         * Return a finalized object based on the provided intermediate.
167         *
168         * @param intermediate intermediate container to hold values
169         * @return final value
170         * @throws SerializationException if unable to construct a
171         * @since 4.0.0
172         */
173        Object complete(I intermediate) throws SerializationException;
174
175        /**
176         * Get whether or not new object instances can be created.
177         *
178         * @return new instance creation
179         * @since 4.0.0
180         */
181        boolean canCreateInstances();
182    }
183
184    /**
185     * A handler for working with mutable objects in the object mapper.
186     *
187     * @param <I> intermediate type
188     * @since 4.0.0
189     */
190    interface MutableInstanceFactory<I> extends InstanceFactory<I> {
191
192        /**
193         * Apply the intermediate data to an existing object.
194         *
195         * @param instance instance to write to
196         * @param intermediate intermediate container
197         * @throws SerializationException if unable to apply info
198         * @since 4.0.0
199         */
200        void complete(Object instance, I intermediate) throws SerializationException;
201    }
202
203    /**
204     * A collector for the necessary metadata for fields.
205     *
206     * @param <I> intermediate type
207     * @param <V> container type
208     * @since 4.0.0
209     */
210    @FunctionalInterface
211    interface FieldCollector<I, V> {
212
213        /**
214         * Accept metadata that defines a specific field.
215         *
216         * @param name name
217         * @param type declared field type, as resolved as possible
218         * @param annotations combined element containing all annotations
219         *                    applicable to the field
220         * @param deserializer a function to populate the intermediate state
221         *                     with a single deserialized field value.
222         * @param serializer a function to extract a value from a completed
223         *                   object instance.
224         * @since 4.0.0
225         */
226        void accept(String name, AnnotatedType type, AnnotatedElement annotations, FieldData.Deserializer<I> deserializer,
227                CheckedFunction<V, @Nullable Object, Exception> serializer);
228    }
229
230}