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