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 static io.leangen.geantyref.GenericTypeReflector.isSuperType;
020import static java.util.Objects.requireNonNull;
021import static org.spongepowered.configurate.util.Types.requireCompleteParameters;
022
023import io.leangen.geantyref.GenericTypeReflector;
024import io.leangen.geantyref.TypeToken;
025import org.checkerframework.checker.nullness.qual.Nullable;
026import org.spongepowered.configurate.ConfigurationNode;
027import org.spongepowered.configurate.objectmapping.ConfigSerializable;
028import org.spongepowered.configurate.objectmapping.ObjectMapper;
029import org.spongepowered.configurate.util.UnmodifiableCollections;
030
031import java.lang.reflect.AnnotatedType;
032import java.lang.reflect.Type;
033import java.lang.reflect.WildcardType;
034import java.util.ArrayList;
035import java.util.List;
036import java.util.Map;
037import java.util.Objects;
038import java.util.concurrent.ConcurrentHashMap;
039import java.util.function.Predicate;
040
041/**
042 * A calculated collection of {@link TypeSerializer}s.
043 *
044 * @since 4.0.0
045 */
046public final class TypeSerializerCollection {
047
048    private static final TypeSerializerCollection DEFAULTS;
049
050    static {
051        DEFAULTS = TypeSerializerCollection.builder()
052                .registerExact(Scalars.STRING)
053                .registerExact(Scalars.BOOLEAN)
054                .register(MapSerializer.TYPE, new MapSerializer())
055                .register(ListSerializer.TYPE, new ListSerializer())
056                .registerExact(Scalars.BYTE)
057                .registerExact(Scalars.SHORT)
058                .registerExact(Scalars.INTEGER)
059                .registerExact(Scalars.LONG)
060                .registerExact(Scalars.FLOAT)
061                .registerExact(Scalars.DOUBLE)
062                .registerAnnotatedObjects(ObjectMapper.factory())
063                .register(Scalars.ENUM)
064                .registerExact(Scalars.CHAR)
065                .registerExact(Scalars.URI)
066                .registerExact(Scalars.URL)
067                .registerExact(Scalars.UUID)
068                .registerExact(Scalars.PATTERN)
069                .register(ArraySerializer.Objects::accepts, new ArraySerializer.Objects())
070                .registerExact(ArraySerializer.Booleans.TYPE, new ArraySerializer.Booleans())
071                .registerExact(ArraySerializer.Bytes.TYPE, new ArraySerializer.Bytes())
072                .registerExact(ArraySerializer.Chars.TYPE, new ArraySerializer.Chars())
073                .registerExact(ArraySerializer.Shorts.TYPE, new ArraySerializer.Shorts())
074                .registerExact(ArraySerializer.Ints.TYPE, new ArraySerializer.Ints())
075                .registerExact(ArraySerializer.Longs.TYPE, new ArraySerializer.Longs())
076                .registerExact(ArraySerializer.Floats.TYPE, new ArraySerializer.Floats())
077                .registerExact(ArraySerializer.Doubles.TYPE, new ArraySerializer.Doubles())
078                .register(SetSerializer::accepts, new SetSerializer())
079                .register(ConfigurationNodeSerializer.TYPE, new ConfigurationNodeSerializer())
080                .register(PathSerializer.TYPE, PathSerializer.INSTANCE)
081                .registerExact(FileSerializer.TYPE, FileSerializer.INSTANCE)
082                .register(OptionalSerializer.TYPE, OptionalSerializer.INSTANCE)
083                .registerExact(OptionalSerializer.OfInt.TYPE, OptionalSerializer.OfInt.INSTANCE)
084                .registerExact(OptionalSerializer.OfLong.TYPE, OptionalSerializer.OfLong.INSTANCE)
085                .registerExact(OptionalSerializer.OfDouble.TYPE, OptionalSerializer.OfDouble.INSTANCE)
086                .build();
087    }
088
089    private final @Nullable TypeSerializerCollection parent;
090    final List<RegisteredSerializer> serializers;
091    private final Map<Type, TypeSerializer<?>> typeMatches = new ConcurrentHashMap<>();
092    private final Map<AnnotatedType, TypeSerializer<?>> annotatedTypeMatches = new ConcurrentHashMap<>();
093
094    private TypeSerializerCollection(final @Nullable TypeSerializerCollection parent, final List<RegisteredSerializer> serializers) {
095        this.parent = parent;
096        this.serializers = UnmodifiableCollections.copyOf(serializers);
097    }
098
099    /**
100     * Resolve a type serializer.
101     *
102     * <p>First, all registered serializers from this collection are queried in
103     * registration order, then if a parent collection is set, that collection
104     * is queried.</p>
105     *
106     * @param token the type a serializer is required for
107     * @param <T> the type to serialize
108     * @return a serializer if any is present, or null if no applicable
109     *          serializer is found
110     * @since 4.0.0
111     */
112    @SuppressWarnings("unchecked")
113    public <T> @Nullable TypeSerializer<T> get(final TypeToken<T> token) {
114        requireNonNull(token, "type");
115        return (TypeSerializer<T>) this.get0(token.getAnnotatedType());
116    }
117
118    /**
119     * Resolve a type serializer.
120     *
121     * <p>First, all registered serializers from this collection are queried in
122     * registration order, then if a parent collection is set, that collection
123     * is queried.</p>
124     *
125     * <p>This method will fail when provided a raw parameterized type</p>
126     *
127     * @param token the type a serializer is required for
128     * @param <T> the type to serialize
129     * @return a serializer if any is present, or null if no applicable
130     *          serializer is found
131     * @since 4.0.0
132     */
133    @SuppressWarnings("unchecked")
134    public <T> @Nullable TypeSerializer<T> get(final Class<T> token) {
135        requireNonNull(token, "type");
136        requireCompleteParameters(token);
137
138        return (TypeSerializer<T>) this.get((Type) token);
139    }
140
141    /**
142     * Resolve a type serializer.
143     *
144     * <p>First, all registered serializers from this collection are queried
145     * then if a parent collection is set, that collection is queried.
146     *
147     * @param type the type a serializer is required for
148     * @return a serializer if any is present, or null if no applicable
149     *          serializer is found
150     * @since 4.0.0
151     */
152    public @Nullable TypeSerializer<?> get(final Type type) {
153        return this.get0(GenericTypeReflector.box(type));
154    }
155
156    /**
157     * Resolve a type serializer with annotation information.
158     *
159     * <p>First, all registered serializers from this collection are queried
160     * then if a parent collection is set, that collection is queried.</p>
161     *
162     * <p>The returned serializer may not necessarily use the provided
163     * annotation information.</p>
164     *
165     * @param type the type a serializer is required for
166     * @return a serializer if any is present, or null if no applicable
167     *          serializer is found
168     * @since 4.2.0
169     */
170    public @Nullable TypeSerializer<?> get(final AnnotatedType type) {
171        return this.get0(GenericTypeReflector.toCanonicalBoxed(type));
172    }
173
174    private @Nullable TypeSerializer<?> get0(final AnnotatedType canonical) {
175        @Nullable TypeSerializer<?> serial = this.annotatedTypeMatches.computeIfAbsent(canonical, param -> {
176            for (final RegisteredSerializer ent : this.serializers) {
177                if (ent.matches(param)) {
178                    return ent.serializer();
179                }
180            }
181            return NoOp.INSTANCE;
182        });
183
184        if (serial == NoOp.INSTANCE) {
185            serial = null;
186        }
187
188        if (serial == null && this.parent != null) {
189            serial = this.parent.get0(canonical);
190        }
191        return serial;
192    }
193
194    private @Nullable TypeSerializer<?> get0(final Type canonical) {
195        @Nullable TypeSerializer<?> serial = this.typeMatches.computeIfAbsent(canonical, param -> {
196            for (final RegisteredSerializer ent : this.serializers) {
197                if (ent.matches(param)) {
198                    return ent.serializer();
199                }
200            }
201            return NoOp.INSTANCE;
202        });
203
204        if (serial == NoOp.INSTANCE) {
205            serial = null;
206        }
207
208        if (serial == null && this.parent != null) {
209            serial = this.parent.get0(canonical);
210        }
211        return serial;
212    }
213
214    /**
215     * Create a new builder to begin building a collection of type serializers
216     * that inherits from this collection.
217     *
218     * @return the new builder
219     * @since 4.0.0
220     */
221    public Builder childBuilder() {
222        return new Builder(this);
223    }
224
225    @Override
226    public String toString() {
227        return "TypeSerializerCollection{"
228                + "parent=" + this.parent
229                + ", serializers=" + this.serializers
230                + '}';
231    }
232
233    @Override public boolean equals(final Object other) {
234        if (this == other) {
235            return true;
236        }
237        if (!(other instanceof TypeSerializerCollection)) {
238            return false;
239        }
240        final TypeSerializerCollection that = (TypeSerializerCollection) other;
241        return Objects.equals(this.parent, that.parent)
242                && this.serializers.equals(that.serializers);
243    }
244
245    @Override
246    public int hashCode() {
247        return Objects.hash(this.parent, this.serializers);
248    }
249
250    /**
251     * Create a builder for a new type serializer collection without a
252     * parent set.
253     *
254     * <p>If <em>any</em> of the standard serializers provided by Configurate
255     * are desired, either the default collection or a collection inheriting
256     * from the default collection should be applied.
257     *
258     * @return the builder
259     * @since 4.0.0
260     */
261    public static Builder builder() {
262        return new Builder(null);
263    }
264
265    /**
266     * Get a collection containing all of Configurate's built-in
267     * type serializers.
268     *
269     * @return the collection
270     * @since 4.0.0
271     */
272    public static TypeSerializerCollection defaults() {
273        return DEFAULTS;
274    }
275
276    /**
277     * A builder to construct new serializer collections.
278     *
279     * <p>Serializers added to a builder will be prioritized based on
280     * registration order, so if multiple serializers could match a single type,
281     * the first-registered one will be used.</p>
282     *
283     * @since 4.0.0
284     */
285    public static class Builder {
286        private final @Nullable TypeSerializerCollection parent;
287        private final List<RegisteredSerializer> serializers = new ArrayList<>();
288
289        Builder(final @Nullable TypeSerializerCollection parent) {
290            this.parent = parent;
291        }
292
293        /**
294         * Register a type serializer for a given type.
295         *
296         * <p>Serializers registered will match all subclasses of the provided
297         * type, as well as unwrapped primitive equivalents of the type.
298         *
299         * @param type the type to accept
300         * @param serializer the serializer that will be serialized with
301         * @param <T> the type to generify around
302         * @return this builder
303         * @since 4.0.0
304         */
305        public <T> Builder register(final TypeToken<T> type, final TypeSerializer<? super T> serializer) {
306            return this.register0(type.getType(), serializer);
307        }
308
309        /**
310         * Register a type serializer for a given type.
311         *
312         * <p>Serializers registered will match all subclasses of the provided
313         * type, as well as unboxed primitive equivalents of the type.
314         *
315         * @param type the type to accept
316         * @param serializer the serializer that will be serialized with
317         * @param <T> the type to generify around
318         * @return this builder
319         * @since 4.0.0
320         */
321        public <T> Builder register(final Class<T> type, final TypeSerializer<? super T> serializer) {
322            return this.register0(type, serializer);
323        }
324
325        /**
326         * Register a type serializer matching against a given predicate.
327         *
328         * @param test the predicate to match types against
329         * @param serializer the serializer to serialize matching types with
330         * @param <T> the type parameter
331         * @return this builder
332         * @since 4.0.0
333         */
334        public <T> Builder register(final Predicate<Type> test, final TypeSerializer<? super T> serializer) {
335            requireNonNull(test, "test");
336            requireNonNull(serializer, "serializer");
337            this.serializers.add(new TypeRegistration(test, serializer));
338            return this;
339        }
340
341        /**
342         * Register a scalar serializer with its own attached type token.
343         *
344         * <p>Serializers registered will match all subclasses of the provided
345         * type, as well as unboxed primitive equivalents of the type.</p>
346         *
347         * @param serializer serializer to register
348         * @param <T> value type
349         * @return this builder
350         * @since 4.0.0
351         */
352        public <T> Builder register(final ScalarSerializer<T> serializer) {
353            requireNonNull(serializer, "serializer");
354            return this.register(serializer.type(), serializer);
355        }
356
357        /**
358         * Register a type serializer matching against a given predicate,
359         * with type annotation information.
360         *
361         * @param test the predicate to match annotated types against
362         * @param serializer the serializer to serialize matching types with
363         * @param <T> the type parameter
364         * @return this builder
365         * @see TypeSerializer.Annotated
366         * @since 4.2.0
367         */
368        public <T> Builder registerAnnotated(final Predicate<AnnotatedType> test, final TypeSerializer<? super T> serializer) {
369            requireNonNull(test, "test");
370            requireNonNull(serializer, "serializer");
371            this.serializers.add(new AnnotatedTypeRegistration(test, serializer));
372            return this;
373        }
374
375        private Builder register0(final Type type, final TypeSerializer<?> serializer) {
376            requireNonNull(type, "type");
377            requireNonNull(serializer, "serializer");
378            this.serializers.add(new TypeRegistration(test -> {
379                // Test direct type
380                if (GenericTypeReflector.isSuperType(type, test)) {
381                    return true;
382                }
383
384                // And upper bounds
385                if (test instanceof WildcardType) {
386                    final Type[] upperBounds = ((WildcardType) test).getUpperBounds();
387                    if (upperBounds.length == 1) {
388                        return isSuperType(type, upperBounds[0]);
389                    }
390                }
391                return false;
392            }, serializer));
393            return this;
394        }
395
396        /**
397         * Register an <em>exact</em> type serializer for a given type.
398         *
399         * <p>Serializers will only match exact object types. For example, a
400         * serializer registered for {@code List<String>} would not match when
401         * {@code ArrayList<String>} is queried.</p>
402         *
403         * @param type the type to accept
404         * @param serializer the serializer that will be serialized with
405         * @param <T> the type to generify around
406         * @return this builder
407         * @since 4.0.0
408         */
409        public <T> Builder registerExact(final TypeToken<T> type, final TypeSerializer<? super T> serializer) {
410            return this.registerExact0(type.getType(), serializer);
411        }
412
413        /**
414         * Register an <em>exact</em> type serializer for a given type.
415         *
416         * <p>Serializers will only match exact object types. For example, a
417         * serializer registered for {@code List<String>} would not match when
418         * {@code ArrayList<String>} is queried.</p>
419         *
420         * @param type the type to accept
421         * @param serializer the serializer that will be serialized with
422         * @param <T> the type to generify around
423         * @return this builder
424         * @since 4.0.0
425         */
426        public <T> Builder registerExact(final Class<T> type, final TypeSerializer<? super T> serializer) {
427            return this.registerExact0(type, serializer);
428        }
429
430        /**
431         * Register a scalar serializer with its own attached type token.
432         *
433         * <p>Serializers will only match exact object types. For example, a
434         * serializer registered for {@code List<String>} would not match when
435         * {@code ArrayList<String>} is queried.</p>
436         *
437         * @param serializer serializer to register
438         * @param <T> value type
439         * @return this builder
440         * @since 4.0.0
441         */
442        public <T> Builder registerExact(final ScalarSerializer<T> serializer) {
443            requireNonNull(serializer, "serializer");
444            return this.registerExact(serializer.type(), serializer);
445        }
446
447        private Builder registerExact0(final Type type, final TypeSerializer<?> serializer) {
448            requireNonNull(type, "type");
449            requireNonNull(serializer, "serializer");
450            this.serializers.add(new TypeRegistration(test -> test.equals(type), serializer));
451            return this;
452        }
453
454        /**
455         * Register all serializers from {@code other} into this collection.
456         *
457         * <p>Creating a child collection should be preferred, but when merging
458         * multiple sets of serializers together, directly adding other
459         * collections may be the best choice.</p>
460         *
461         * @param other source collection
462         * @return this builder
463         * @since 4.0.0
464         */
465        public Builder registerAll(final TypeSerializerCollection other) {
466            this.serializers.addAll(requireNonNull(other, "other").serializers);
467            return this;
468        }
469
470        /**
471         * Register a customized object mapper to handle
472         * {@link ConfigSerializable}-annotated objects.
473         *
474         * @param factory factory to retrieve object mappers from
475         * @return this builder
476         * @since 4.0.0
477         */
478        public Builder registerAnnotatedObjects(final ObjectMapper.Factory factory) {
479            return this.register(Builder::isAnnotatedTarget, factory.asTypeSerializer());
480        }
481
482        /**
483         * A predicate to restrict the type serializer created by
484         * {@link ObjectMapper.Factory#asTypeSerializer()} to annotated types.
485         *
486         * @return whether a type is annotated with {@link ConfigSerializable}
487         * @since 4.0.0
488         */
489        static boolean isAnnotatedTarget(final Type type) {
490            return GenericTypeReflector.annotate(type).isAnnotationPresent(ConfigSerializable.class);
491        }
492
493        /**
494         * Create a new type serializer collection.
495         *
496         * @return a newly created collection
497         * @since 4.0.0
498         */
499        public TypeSerializerCollection build() {
500            return new TypeSerializerCollection(this.parent, this.serializers);
501        }
502    }
503
504    /**
505     * A serializer registration.
506     *
507     * @since 4.2.0
508     */
509    interface RegisteredSerializer {
510
511        boolean matches(Type test);
512
513        boolean matches(AnnotatedType annotated);
514
515        TypeSerializer<?> serializer();
516
517    }
518
519    static final class TypeRegistration implements RegisteredSerializer {
520
521        private final Predicate<Type> predicate;
522        private final TypeSerializer<?> serializer;
523
524        TypeRegistration(final Predicate<Type> predicate, final TypeSerializer<?> serializer) {
525            this.predicate = predicate;
526            this.serializer = serializer;
527        }
528
529        @Override
530        public boolean matches(final Type test) {
531            return this.predicate.test(test);
532        }
533
534        @Override
535        public boolean matches(final AnnotatedType annotated) {
536            return this.predicate.test(annotated.getType());
537        }
538
539        @Override
540        public TypeSerializer<?> serializer() {
541            return this.serializer;
542        }
543
544    }
545
546    static final class AnnotatedTypeRegistration implements RegisteredSerializer {
547
548        private final Predicate<AnnotatedType> predicate;
549        private final TypeSerializer<?> serializer;
550
551        AnnotatedTypeRegistration(final Predicate<AnnotatedType> predicate, final TypeSerializer<?> serializer) {
552            this.predicate = predicate;
553            this.serializer = serializer;
554        }
555
556        @Override
557        public boolean matches(final Type test) {
558            return this.predicate.test(GenericTypeReflector.annotate(test));
559        }
560
561        @Override
562        public boolean matches(final AnnotatedType annotated) {
563            return this.predicate.test(annotated);
564        }
565
566        @Override
567        public TypeSerializer<?> serializer() {
568            return this.serializer;
569        }
570
571    }
572
573    static final class NoOp implements TypeSerializer<Void> {
574
575        static final NoOp INSTANCE = new NoOp();
576
577        private NoOp() {
578        }
579
580        @Override
581        public Void deserialize(final Type type, final ConfigurationNode node) throws SerializationException {
582            throw new UnsupportedOperationException("this is a placeholder for null, should not be called directly");
583        }
584
585        @Override
586        public void serialize(final Type type, final @Nullable Void obj, final ConfigurationNode node) throws SerializationException {
587            throw new UnsupportedOperationException("this is a placeholder for null, should not be called directly");
588        }
589    }
590
591}