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 */
037public interface FieldDiscoverer<I> {
038
039    /**
040     * Create a new field discoverer that will handle record classes.
041     *
042     * @return new discoverer
043     * @since 4.0.0
044     */
045    static FieldDiscoverer<?> record() {
046        return RecordFieldDiscoverer.INSTANCE;
047    }
048
049    /**
050     * Create a new discoverer for object instance fields.
051     *
052     * <p>This discoverer will process any non-static and non-transient field
053     * in the object.</p>
054     *
055     * @param instanceFactory a factory for instance providers
056     * @return new discoverer
057     * @since 4.0.0
058     */
059    static FieldDiscoverer<?> object(final CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> instanceFactory) {
060        return new ObjectFieldDiscoverer(requireNonNull(instanceFactory, "instanceFactory"));
061    }
062
063    /**
064     * Create a new discoverer for object instance fields.
065     *
066     * <p>Only objects with empty constructors can be created.</p>
067     *
068     * @return new discoverer
069     * @see #object(CheckedFunction) for more details on which fields will
070     *      be discovered.
071     * @since 4.0.0
072     */
073    static FieldDiscoverer<?> emptyConstructorObject() {
074        return ObjectFieldDiscoverer.EMPTY_CONSTRUCTOR_INSTANCE;
075    }
076
077    /**
078     * Inspect the {@code target} type for fields to be supplied to
079     * the {@code collector}.
080     *
081     * <p>If the target type is handleable, a non-null value must be returned.
082     * Fields can only be collected from one source at the moment, so if the
083     * instance factory is null any discovered fields will be discarded.</p>
084     *
085     * @param target type to inspect
086     * @param collector collector for discovered fields.
087     * @param <V> object type
088     * @return a factory for handling the construction of object instances, or
089     *      {@code null} if {@code target} is not of a handleable type.
090     * @throws SerializationException if any fields have invalid data
091     * @since 4.0.0
092     */
093    <V> @Nullable InstanceFactory<I> discover(AnnotatedType target, FieldCollector<I, V> collector) throws SerializationException;
094
095    /**
096     * A handler that controls the deserialization process for an object.
097     *
098     * @param <I> intermediate type
099     * @since 4.0.0
100     */
101    interface InstanceFactory<I> {
102
103        /**
104         * Return a new instance of the intermediary type to be populated.
105         *
106         * @return new intermediate container
107         * @since 4.0.0
108         */
109        I begin();
110
111        /**
112         * Return a finalized object based on the provided intermediate.
113         *
114         * @param intermediate intermediate container to hold values
115         * @return final value
116         * @throws SerializationException if unable to construct a
117         * @since 4.0.0
118         */
119        Object complete(I intermediate) throws SerializationException;
120
121        /**
122         * Get whether or not new object instances can be created.
123         *
124         * @return new instance creation
125         * @since 4.0.0
126         */
127        boolean canCreateInstances();
128    }
129
130    /**
131     * A handler for working with mutable objects in the object mapper.
132     *
133     * @param <I> intermediate type
134     * @since 4.0.0
135     */
136    interface MutableInstanceFactory<I> extends InstanceFactory<I> {
137
138        /**
139         * Apply the intermediate data to an existing object.
140         *
141         * @param instance instance to write to
142         * @param intermediate intermediate container
143         * @throws SerializationException if unable to apply info
144         * @since 4.0.0
145         */
146        void complete(Object instance, I intermediate) throws SerializationException;
147    }
148
149    /**
150     * A collector for the necessary metadata for fields.
151     *
152     * @param <I> intermediate type
153     * @param <V> container type
154     * @since 4.0.0
155     */
156    @FunctionalInterface
157    interface FieldCollector<I, V> {
158
159        /**
160         * Accept metadata that defines a specific field.
161         *
162         * @param name name
163         * @param type declared field type, as resolved as possible
164         * @param annotations combined element containing all annotations
165         *                    applicable to the field
166         * @param deserializer a function to populate the intermediate state
167         *                     with a single deserialized field value.
168         * @param serializer a function to extract a value from a completed
169         *                   object instance.
170         * @since 4.0.0
171         */
172        void accept(String name, AnnotatedType type, AnnotatedElement annotations, FieldData.Deserializer<I> deserializer,
173                CheckedFunction<V, @Nullable Object, Exception> serializer);
174    }
175
176}