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 ninja.leaping.configurate.objectmapping.serialize; 018 019import com.google.common.reflect.TypeToken; 020 021import java.util.Map; 022import java.util.concurrent.ConcurrentHashMap; 023import java.util.concurrent.CopyOnWriteArrayList; 024import java.util.function.Function; 025import java.util.function.Predicate; 026 027import static java.util.Objects.requireNonNull; 028 029/** 030 * A calculated collection of {@link TypeSerializer}s 031 */ 032public class TypeSerializerCollection { 033 private final TypeSerializerCollection parent; 034 private final SerializerList serializers = new SerializerList(); 035 private final Map<TypeToken<?>, TypeSerializer<?>> typeMatches = new ConcurrentHashMap<>(); 036 037 TypeSerializerCollection(TypeSerializerCollection parent) { 038 this.parent = parent; 039 } 040 041 /** 042 * Gets the default {@link TypeSerializer}s. While this collection is mutable, starting with 043 * Configurate 4.0 type serializer collections will be immutable, so mutability should not be 044 * relied on. Instead, a new child of this collection should be used to register any custom 045 * serializers. 046 * 047 * @return The default serializers 048 */ 049 public static TypeSerializerCollection defaults() { 050 return TypeSerializers.DEFAULT_SERIALIZERS; 051 } 052 053 public static TypeSerializerCollection create() { 054 return defaults().newChild(); 055 } 056 057 @SuppressWarnings("unchecked") 058 public <T> TypeSerializer<T> get(TypeToken<T> type) { 059 type = requireNonNull(type).wrap(); 060 061 TypeSerializer<?> serial = typeMatches.computeIfAbsent(type, serializers); 062 if (serial == null && parent != null) { 063 serial = parent.get(type); 064 } 065 066 return (TypeSerializer) serial; 067 } 068 069 /** 070 * Register a type serializer for a given type. Serializers registered will match all subclasses 071 * of the provided type, as well as unwrapped primitive equivalents of the type. 072 * 073 * @param type The type to accept 074 * @param serializer The serializer that will be serialized with 075 * @param <T> The type to generify around 076 * @return this 077 * @deprecated Use #register(TypeToken, TypeSerializer) instead 078 */ 079 @Deprecated 080 public <T> TypeSerializerCollection registerType(TypeToken<T> type, TypeSerializer<? super T> serializer) { 081 return register(type, serializer); 082 083 } 084 085 /** 086 * Register a type serializer for a given type. Serializers registered will match all subclasses 087 * of the provided type, as well as unwrapped primitive equivalents of the type. 088 * 089 * @param type The type to accept 090 * @param serializer The serializer that will be serialized with 091 * @param <T> The type to generify around 092 * @return this 093 */ 094 public <T> TypeSerializerCollection register(TypeToken<T> type, TypeSerializer<? super T> serializer) { 095 serializers.add(new RegisteredSerializer(requireNonNull(type, "type"), requireNonNull(serializer))); 096 typeMatches.clear(); 097 return this; 098 } 099 100 /** 101 * Register a type serializer matching against a given predicate. 102 * 103 * @param test The predicate to match types against 104 * @param serializer The serializer to serialize matching types with 105 * @param <T> The type parameter 106 * @return this 107 * @deprecated Use {@link #register(Predicate, TypeSerializer)} instead 108 */ 109 @Deprecated 110 public <T> TypeSerializerCollection registerPredicate(Predicate<TypeToken<T>> test, TypeSerializer<? super T> serializer) { 111 return register(test, serializer); 112 } 113 114 /** 115 * Register a type serializer matching against a given predicate. 116 * 117 * @param test The predicate to match types against 118 * @param serializer The serializer to serialize matching types with 119 * @param <T> The type parameter 120 * @return this 121 */ 122 @SuppressWarnings("unchecked") 123 public <T> TypeSerializerCollection register(Predicate<TypeToken<T>> test, TypeSerializer<? super T> serializer) { 124 serializers.add(new RegisteredSerializer((Predicate) requireNonNull(test, "test"), requireNonNull(serializer, "serializer"))); 125 typeMatches.clear(); 126 return this; 127 } 128 129 /** 130 * Register a scalar serializer under its appropriate type. Serializers registered will match all subclasses 131 * 132 * @param serializer The serializer that will be serialized with 133 * @param <T> The type to generify around 134 * @return this 135 */ 136 public <T> TypeSerializerCollection register(ScalarSerializer<T> serializer) { 137 return register(serializer.type(), serializer); 138 } 139 140 public TypeSerializerCollection newChild() { 141 return new TypeSerializerCollection(this); 142 } 143 144 private static final class SerializerList extends CopyOnWriteArrayList<RegisteredSerializer> implements Function<TypeToken<?>, TypeSerializer<?>> { 145 146 @Override 147 public TypeSerializer<?> apply(TypeToken<?> type) { 148 for (RegisteredSerializer ent : this) { 149 if (ent.predicate.test(type)) { 150 return ent.serializer; 151 } 152 } 153 return null; 154 } 155 } 156 157}