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 io.leangen.geantyref.TypeToken;
020import org.spongepowered.configurate.ConfigurationNode;
021import org.spongepowered.configurate.objectmapping.meta.Constraint;
022import org.spongepowered.configurate.objectmapping.meta.NodeResolver;
023import org.spongepowered.configurate.objectmapping.meta.PostProcessor;
024import org.spongepowered.configurate.objectmapping.meta.Processor;
025import org.spongepowered.configurate.serialize.SerializationException;
026import org.spongepowered.configurate.serialize.TypeSerializer;
027import org.spongepowered.configurate.serialize.TypeSerializerCollection;
028import org.spongepowered.configurate.util.NamingScheme;
029
030import java.lang.annotation.Annotation;
031import java.lang.reflect.Type;
032import java.util.List;
033
034/**
035 * A mapper that converts between configuration nodes and Java objects.
036 *
037 * <p>Object mappers are created through a {@link Factory}, either the default
038 * one or one created with additional options. See that class's
039 * documentation for details.</p>
040 *
041 * <p>The object mapper can be accessed directly, through its {@link #factory()},
042 * or through a {@link ConfigurationNode}'s
043 * {@link ConfigurationNode#get(TypeToken)} method. To use a custom factory
044 * instance through a node, a custom TypeSerializer has to be registered to the
045 * {@link TypeSerializerCollection} used
046 * by the node.</p>
047 *
048 * @param <V> mapped type
049 * @since 4.0.0
050 */
051public interface ObjectMapper<V> {
052
053    /**
054     * Get the default object mapper factory instance.
055     *
056     * <p>This factory has the following characteristics:</p>
057     * <ul>
058     *     <li>can resolve fields in empty-constructor objects and Records</li>
059     *     <li>will try to resolve any field in objects</li>
060     *     <li>supports {@link org.spongepowered.configurate.objectmapping.meta.NodeKey} and
061     *     {@link org.spongepowered.configurate.objectmapping.meta.Setting} annotations
062     *     for customizing node resolution</li>
063     *     <li>uses the {@link org.spongepowered.configurate.util.NamingSchemes#LOWER_CASE_DASHED}
064     *     naming scheme for other nodes</li>
065     *     <li>supports unlocalized {@link org.spongepowered.configurate.objectmapping.meta.Matches},
066     *     and {@link org.spongepowered.configurate.objectmapping.meta.Required}
067     *     constraints</li>
068     *     <li>processes {@link org.spongepowered.configurate.objectmapping.meta.Comment}
069     *     annotations</li>
070     * </ul>
071     *
072     * @return default factory
073     * @since 4.0.0
074     */
075    static Factory factory() {
076        return ObjectMapperFactoryImpl.INSTANCE;
077    }
078
079    /**
080     * Create an empty builder.
081     *
082     * <p>This applies none of the standard formats, processors, constraints or
083     * resolvers. Unless you want to do something particularly specialized,
084     * you should probably be using {@link #factoryBuilder()}.</p>
085     *
086     * @return new empty builder
087     * @since 4.0.0
088     */
089    static Factory.Builder emptyFactoryBuilder() {
090        return new ObjectMapperFactoryImpl.Builder();
091    }
092
093    /**
094     * Create a builder populated with default settings.
095     *
096     * <p>This builder is prepared to allow overriding any of the default
097     * object mapper features.</p>
098     *
099     * @return new builder
100     * @see #factory() for a description of the default settings
101     * @since 4.0.0
102     */
103    static Factory.Builder factoryBuilder() {
104        return ObjectMapperFactoryImpl.defaultBuilder();
105    }
106
107    /**
108     * Create a new object instance.
109     *
110     * @param source object source
111     * @return new instance
112     * @throws SerializationException if any invalid data is present. Loading is
113     *      done in stages, so any deserialization errors will occur before
114     *      anything is written to objects.
115     * @since 4.0.0
116     */
117    V load(ConfigurationNode source) throws SerializationException;
118
119    /**
120     * Write data from the provided object to the target.
121     *
122     * @param value value type
123     * @param target destination
124     * @throws SerializationException if unable to fully save
125     * @since 4.0.0
126     */
127    void save(V value, ConfigurationNode target) throws SerializationException;
128
129    /**
130     * Get the parameters that will be handled by this mapper.
131     *
132     * @return immutable list of fields
133     * @since 4.0.0
134     */
135    List<? extends FieldData<?, V>> fields();
136
137    /**
138     * The generic type of object that this mapper instance handles.
139     *
140     * @return object type
141     * @since 4.0.0
142     */
143    Type mappedType();
144
145    /**
146     * Get whether or not this mapper is capable of creating new instances of
147     * its mapped type.
148     *
149     * <p>If this returns {@code false}, {@link #load(ConfigurationNode)} will
150     * always fail.</p>
151     *
152     * @return if the mapped type can be instantiated.
153     * @since 4.0.0
154     */
155    boolean canCreateInstances();
156
157    /**
158     * An object mapper capable of loading data into an existing object.
159     *
160     * @param <V> value type
161     * @since 4.0.0
162     */
163    interface Mutable<V> extends ObjectMapper<V> {
164
165        /**
166         * Load data from {@code node} into an existing instance.
167         *
168         * @param value existing instance
169         * @param node node to load from
170         * @throws SerializationException if unable to deserialize data
171         * @since 4.0.0
172         */
173        void load(V value, ConfigurationNode node) throws SerializationException;
174
175    }
176
177    /**
178     * Provider for object mappers.
179     *
180     * @since 4.0.0
181     */
182    interface Factory {
183
184        /**
185         * Get an object mapper for the provided type.
186         *
187         * <p>The provided type cannot be a <em>raw type</em>.</p>
188         *
189         * @param type token holding the mapped type
190         * @param <V> mapped type
191         * @return a mapper for the provided type
192         * @throws SerializationException if the type does not correspond to a
193         *     mappable object
194         * @since 4.0.0
195         */
196        @SuppressWarnings("unchecked")
197        default <V> ObjectMapper<V> get(final TypeToken<V> type) throws SerializationException {
198            return (ObjectMapper<V>) get(type.getType());
199        }
200
201        /**
202         * Get an object mapper for the unparameterized type {@code clazz}.
203         *
204         * <p>The provided type cannot be a <em>raw type</em>.</p>
205         *
206         * @param clazz class of the mapped type
207         * @param <V> mapped type
208         * @return a mapper for the provided type
209         * @throws SerializationException if the type does not correspond to a
210         *     mappable object
211         * @since 4.0.0
212         */
213        @SuppressWarnings("unchecked")
214        default <V> ObjectMapper<V> get(final Class<V> clazz) throws SerializationException {
215            return (ObjectMapper<V>) get((Type) clazz);
216        }
217
218        /**
219         * Get the object mapper for the provided type.
220         *
221         * <p>The provided type cannot be a <em>raw type</em>.</p>
222         *
223         * @param type object type.
224         * @return a mapper for the provided type
225         * @throws SerializationException if the type does not correspond to a
226         *     mappable object
227         * @since 4.0.0
228         */
229        ObjectMapper<?> get(Type type) throws SerializationException;
230
231        /**
232         * Creates a {@link TypeSerializer} that uses this factory.
233         *
234         * <p>The serializer will accept any object type that could otherwise be
235         * handled by this factory. To match a standard configuration,
236         * register this serializer with {@link TypeSerializerCollection.Builder#registerAnnotatedObjects(Factory)}
237         * to enforce the presence of {@link ConfigSerializable} annotations.</p>
238         *
239         * @return a type serializer
240         * @since 4.0.0
241         */
242        TypeSerializer<Object> asTypeSerializer();
243
244        /**
245         * A builder for a configured factory producing object mappers.
246         *
247         * <p>In general, with multiple applicable resolvers, the one registered
248         * last will take priority.</p>
249         *
250         * @since 4.0.0
251         */
252        interface Builder {
253
254            /**
255             * Set the naming scheme to use as a default for field names.
256             *
257             * <p>This can be overridden by other
258             * {@link NodeResolver NodeResolvers} for specific nodes.</p>
259             *
260             * @param scheme naming scheme
261             * @return this builder
262             * @since 4.0.0
263             */
264            Builder defaultNamingScheme(NamingScheme scheme);
265
266            /**
267             * Add a resolver that will locate a node for a field.
268             *
269             * @param resolver the resolver
270             * @return this builder
271             * @since 4.0.0
272             */
273            Builder addNodeResolver(NodeResolver.Factory resolver);
274
275            /**
276             * Add a discoverer for a type of object.
277             *
278             * <p>Field discoverers will be tried in order until one can
279             * produce the appropriate metadata.</p>
280             *
281             * @param discoverer field discoverer
282             * @return this builder
283             * @since 4.0.0
284             */
285            Builder addDiscoverer(FieldDiscoverer<?> discoverer);
286
287            /**
288             * Register a {@link Processor} that will process fields after write.
289             *
290             * <p>Processors registered without a specific data type should be
291             * able to operate on any value type.</p>
292             *
293             * @param definition annotation providing data
294             * @param factory factory for callback function
295             * @param <A> annotation type
296             * @return this builder
297             * @since 4.0.0
298             */
299            default <A extends Annotation> Builder addProcessor(final Class<A> definition, final Processor.Factory<A, Object> factory) {
300                return addProcessor(definition, Object.class, factory);
301            }
302
303            /**
304             * Register a {@link Processor} that will process fields after write.
305             *
306             * <p>All value types will be tested against types normalized to
307             * their boxed variants.</p>
308             *
309             * @param definition annotation providing data
310             * @param valueType value types the processor will handle
311             * @param factory factory for callback function
312             * @param <A> annotation type
313             * @param <T> data type
314             * @return this builder
315             * @since 4.0.0
316             */
317            <A extends Annotation, T> Builder addProcessor(Class<A> definition, Class<T> valueType, Processor.Factory<A, T> factory);
318
319            /**
320             * Register a {@link Constraint} that will be used to validate fields.
321             *
322             * <p>Constraints registered without a specific data type will be
323             * able to operate on any value type.</p>
324             *
325             * @param definition annotations providing data
326             * @param factory factory for callback function
327             * @param <A> annotation type
328             * @return this builder
329             * @since 4.0.0
330             */
331            default <A extends Annotation> Builder addConstraint(final Class<A> definition, final Constraint.Factory<A, Object> factory) {
332                return addConstraint(definition, Object.class, factory);
333            }
334
335            /**
336             * Register a {@link Constraint} that will be used to validate fields.
337             *
338             * <p>All value types will be tested against types normalized to
339             * their boxed variants.</p>
340             *
341             * @param definition annotations providing data
342             * @param valueType value types the processor will handle
343             * @param factory factory for callback function
344             * @param <A> annotation type
345             * @param <T> data type
346             * @return this builder
347             * @since 4.0.0
348             */
349            <A extends Annotation, T> Builder addConstraint(Class<A> definition, Class<T> valueType, Constraint.Factory<A, T> factory);
350
351            /**
352             * Register an object post-processor with this object mapper.
353             *
354             * <p>All post-processors will be called, even if one
355             * throws an exception.</p>
356             *
357             * @param factory the factory optionally producing a
358             *     post processor function
359             * @return this builder
360             * @since 4.2.0
361             */
362            Builder addPostProcessor(PostProcessor.Factory factory);
363
364            /**
365             * Create a new factory using the current configuration.
366             *
367             * @return new factory instance
368             * @since 4.0.0
369             */
370            Factory build();
371
372        }
373
374    }
375
376}