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.serialize;
018
019import io.leangen.geantyref.GenericTypeReflector;
020import org.checkerframework.checker.nullness.qual.Nullable;
021import org.spongepowered.configurate.ConfigurationNode;
022import org.spongepowered.configurate.ConfigurationOptions;
023import org.spongepowered.configurate.util.CheckedFunction;
024
025import java.lang.reflect.AnnotatedType;
026import java.lang.reflect.Type;
027import java.util.function.BiFunction;
028import java.util.function.Predicate;
029
030/**
031 * Represents an object which can serialize and deserialize objects of a
032 * given type.
033 *
034 * <p>The type serializer interface has methods both for working with
035 * annotated types, and discarding annotated type information. If annotation
036 * information is desired, the {@link Annotated} interface overrides the
037 * standard TypeSerializer interface to prefer annotated type information.</p>
038 *
039 * @param <T> the type
040 * @since 4.0.0
041 */
042public interface TypeSerializer<T> {
043
044    /**
045     * Given the provided functions, create a new serializer for a scalar value.
046     *
047     * <p>The returned serializer must fulfill all the requirements of a {@link ScalarSerializer}
048     *
049     * @param type the type of value returned by the serializer
050     * @param serializer the serialization function, implementing {@link ScalarSerializer#serialize(Object, Predicate)}
051     * @param deserializer the deserialization function, implementing {@link ScalarSerializer#deserialize(Type, Object)}
052     * @param <T> the type of value to deserialize
053     * @return a new and unregistered type serializer
054     * @since 4.0.0
055     */
056    static <T> ScalarSerializer<T> of(final Type type, final BiFunction<T, Predicate<Class<?>>, Object> serializer,
057                                      final CheckedFunction<Object, T, SerializationException> deserializer) {
058        return new FunctionScalarSerializer<>(type, deserializer, serializer);
059    }
060
061    /**
062     * Given the provided functions, create a new serializer for a scalar value.
063     *
064     * <p>The returned serializer must fulfill all the requirements of
065     * a {@link ScalarSerializer}
066     *
067     * @param type the type of value. Must not be a parameterized type
068     * @param serializer the serialization function, implementing {@link ScalarSerializer#serialize(Object, Predicate)}
069     * @param deserializer the deserialization function, implementing {@link ScalarSerializer#deserialize(Type, Object)}
070     * @param <T> the type of value to deserialize
071     * @return a new and unregistered type serializer
072     * @see #of(Type, BiFunction, CheckedFunction) for the version of this
073     *      function that takes a parameterized type
074     * @since 4.0.0
075     */
076    static <T> ScalarSerializer<T> of(final Class<T> type,
077            final BiFunction<T, Predicate<Class<?>>, Object> serializer, final CheckedFunction<Object, T, SerializationException> deserializer) {
078        if (type.getTypeParameters().length > 0) {
079            throw new IllegalArgumentException("Parameterized types must be specified using TypeTokens, not raw classes");
080        }
081
082        return new FunctionScalarSerializer<T>(type, deserializer, serializer);
083    }
084
085    /**
086     * Deserialize an object (of the correct type) from the given
087     * configuration node.
088     *
089     * @param type the annotated type of return value required
090     * @param node the node containing serialized data
091     * @return an object
092     * @throws SerializationException if the presented data is invalid
093     * @since 4.2.0
094     */
095    default T deserialize(final AnnotatedType type, final ConfigurationNode node) throws SerializationException {
096        return this.deserialize(type.getType(), node);
097    }
098
099    /**
100     * Deserialize an object (of the correct type) from the given configuration
101     * node.
102     *
103     * @param type the type of return value required
104     * @param node the node containing serialized data
105     * @return an object
106     * @throws SerializationException if the presented data is invalid
107     * @since 4.0.0
108     */
109    T deserialize(Type type, ConfigurationNode node) throws SerializationException;
110
111    /**
112     * Serialize an object to the given configuration node.
113     *
114     * @param type the annotated type of the input object
115     * @param obj the object to be serialized
116     * @param node the node to write to
117     * @throws SerializationException if the object cannot be serialized
118     * @since 4.2.0
119     */
120    default void serialize(final AnnotatedType type, final @Nullable T obj, final ConfigurationNode node) throws SerializationException {
121        this.serialize(type.getType(), obj, node);
122    }
123
124    /**
125     * Serialize an object to the given configuration node.
126     *
127     * @param type the type of the input object
128     * @param obj the object to be serialized
129     * @param node the node to write to
130     * @throws SerializationException if the object cannot be serialized
131     * @since 4.0.0
132     */
133    void serialize(Type type, @Nullable T obj, ConfigurationNode node) throws SerializationException;
134
135    /**
136     * Create an empty value of the appropriate type.
137     *
138     * <p>This method is for the most part designed to create empty collection
139     * types, though it may be useful for scalars in limited cases.</p>
140     *
141     * @param specificType specific subtype to create an empty value of
142     * @param options options used from the loading node
143     * @return new empty value
144     * @since 4.0.0
145     */
146    default @Nullable T emptyValue(final Type specificType, final ConfigurationOptions options) {
147        return null;
148    }
149
150    /**
151     * Create an empty value of the appropriate type.
152     *
153     * <p>This method is for the most part designed to create empty
154     * collection types, though it may be useful for scalars
155     * in limited cases.</p>
156     *
157     * @param specificType specific annotated subtype to create an empty
158     *     value of
159     * @param options options used from the loading node
160     * @return new empty value
161     * @since 4.2.0
162     */
163    default @Nullable T emptyValue(final AnnotatedType specificType, final ConfigurationOptions options) {
164        return this.emptyValue(specificType.getType(), options);
165    }
166
167    /**
168     * A type serializer that prefers type use annotation metadata to
169     * deserialize the type.
170     *
171     *
172     * @param <V> the value type
173     * @since 4.2.0
174     */
175    interface Annotated<V> extends TypeSerializer<V> {
176
177        @Override
178        V deserialize(AnnotatedType type, ConfigurationNode node) throws SerializationException;
179
180        @Override
181        default V deserialize(final Type type, final ConfigurationNode node) throws SerializationException {
182            return this.deserialize(GenericTypeReflector.annotate(type), node);
183        }
184
185        @Override
186        void serialize(AnnotatedType type, @Nullable V obj, ConfigurationNode node) throws SerializationException;
187
188        @Override
189        default void serialize(final Type type, final @Nullable V obj, final ConfigurationNode node) throws SerializationException {
190            this.serialize(GenericTypeReflector.annotate(type), obj, node);
191        }
192
193        @Override
194        default @Nullable V emptyValue(final AnnotatedType specificType, final ConfigurationOptions options) {
195            return null;
196        }
197
198        @Override
199        default @Nullable V emptyValue(final Type specificType, final ConfigurationOptions options) {
200            return this.emptyValue(GenericTypeReflector.annotate(specificType), options);
201        }
202
203    }
204
205}