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.annotate; 020import static io.leangen.geantyref.GenericTypeReflector.isSuperType; 021import static java.util.Objects.requireNonNull; 022import static org.spongepowered.configurate.util.Types.requireCompleteParameters; 023 024import io.leangen.geantyref.GenericTypeReflector; 025import io.leangen.geantyref.TypeToken; 026import org.checkerframework.checker.nullness.qual.Nullable; 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 private 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>) get(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(Type type) { 147 type = GenericTypeReflector.toCanonicalBoxed(annotate(requireNonNull(type, "type"))).getType(); 148 @Nullable TypeSerializer<?> serial = this.typeMatches.computeIfAbsent(type, param -> { 149 for (RegisteredSerializer ent : this.serializers) { 150 if (ent.predicate.test(param)) { 151 return ent.serializer; 152 } 153 } 154 return null; 155 }); 156 157 if (serial == null && this.parent != null) { 158 serial = this.parent.get(type); 159 } 160 return serial; 161 } 162 163 /** 164 * Create a new builder to begin building a collection of type serializers 165 * that inherits from this collection. 166 * 167 * @return the new builder 168 * @since 4.0.0 169 */ 170 public Builder childBuilder() { 171 return new Builder(this); 172 } 173 174 @Override 175 public String toString() { 176 return "TypeSerializerCollection{" 177 + "parent=" + this.parent 178 + ", serializers=" + this.serializers 179 + '}'; 180 } 181 182 @Override public boolean equals(final Object other) { 183 if (this == other) { 184 return true; 185 } 186 if (!(other instanceof TypeSerializerCollection)) { 187 return false; 188 } 189 final TypeSerializerCollection that = (TypeSerializerCollection) other; 190 return Objects.equals(this.parent, that.parent) 191 && this.serializers.equals(that.serializers); 192 } 193 194 @Override 195 public int hashCode() { 196 return Objects.hash(this.parent, this.serializers); 197 } 198 199 /** 200 * Create a builder for a new type serializer collection without a 201 * parent set. 202 * 203 * <p>If <em>any</em> of the standard serializers provided by Configurate 204 * are desired, either the default collection or a collection inheriting 205 * from the default collection should be applied. 206 * 207 * @return the builder 208 * @since 4.0.0 209 */ 210 public static Builder builder() { 211 return new Builder(null); 212 } 213 214 /** 215 * Get a collection containing all of Configurate's built-in 216 * type serializers. 217 * 218 * @return the collection 219 * @since 4.0.0 220 */ 221 public static TypeSerializerCollection defaults() { 222 return DEFAULTS; 223 } 224 225 /** 226 * A builder to construct new serializer collections. 227 * 228 * <p>Serializers added to a builder will be prioritized based on 229 * registration order, so if multiple serializers could match a single type, 230 * the first-registered one will be used.</p> 231 * 232 * @since 4.0.0 233 */ 234 public static class Builder { 235 private final @Nullable TypeSerializerCollection parent; 236 private final List<RegisteredSerializer> serializers = new ArrayList<>(); 237 238 Builder(final @Nullable TypeSerializerCollection parent) { 239 this.parent = parent; 240 } 241 242 /** 243 * Register a type serializer for a given type. 244 * 245 * <p>Serializers registered will match all subclasses of the provided 246 * type, as well as unwrapped primitive equivalents of the type. 247 * 248 * @param type the type to accept 249 * @param serializer the serializer that will be serialized with 250 * @param <T> the type to generify around 251 * @return this builder 252 * @since 4.0.0 253 */ 254 public <T> Builder register(final TypeToken<T> type, final TypeSerializer<? super T> serializer) { 255 return register0(type.getType(), serializer); 256 } 257 258 /** 259 * Register a type serializer for a given type. 260 * 261 * <p>Serializers registered will match all subclasses of the provided 262 * type, as well as unboxed primitive equivalents of the type. 263 * 264 * @param type the type to accept 265 * @param serializer the serializer that will be serialized with 266 * @param <T> the type to generify around 267 * @return this builder 268 * @since 4.0.0 269 */ 270 public <T> Builder register(final Class<T> type, final TypeSerializer<? super T> serializer) { 271 return register0(type, serializer); 272 } 273 274 /** 275 * Register a type serializer matching against a given predicate. 276 * 277 * @param test the predicate to match types against 278 * @param serializer the serializer to serialize matching types with 279 * @param <T> the type parameter 280 * @return this builder 281 * @since 4.0.0 282 */ 283 public <T> Builder register(final Predicate<Type> test, final TypeSerializer<? super T> serializer) { 284 requireNonNull(test, "test"); 285 requireNonNull(serializer, "serializer"); 286 this.serializers.add(new RegisteredSerializer(test, serializer)); 287 return this; 288 } 289 290 /** 291 * Register a scalar serializer with its own attached type token. 292 * 293 * <p>Serializers registered will match all subclasses of the provided 294 * type, as well as unboxed primitive equivalents of the type.</p> 295 * 296 * @param serializer serializer to register 297 * @param <T> value type 298 * @return this builder 299 * @since 4.0.0 300 */ 301 public <T> Builder register(final ScalarSerializer<T> serializer) { 302 requireNonNull(serializer, "serializer"); 303 return register(serializer.type(), serializer); 304 } 305 306 private Builder register0(final Type type, final TypeSerializer<?> serializer) { 307 requireNonNull(type, "type"); 308 requireNonNull(serializer, "serializer"); 309 this.serializers.add(new RegisteredSerializer(test -> { 310 // Test direct type 311 if (GenericTypeReflector.isSuperType(type, test)) { 312 return true; 313 } 314 315 // And upper bounds 316 if (test instanceof WildcardType) { 317 final Type[] upperBounds = ((WildcardType) test).getUpperBounds(); 318 if (upperBounds.length == 1) { 319 return isSuperType(type, upperBounds[0]); 320 } 321 } 322 return false; 323 }, serializer)); 324 return this; 325 } 326 327 /** 328 * Register an <em>exact</em> type serializer for a given type. 329 * 330 * <p>Serializers will only match exact object types. For example, a 331 * serializer registered for {@code List<String>} would not match when 332 * {@code ArrayList<String>} is queried.</p> 333 * 334 * @param type the type to accept 335 * @param serializer the serializer that will be serialized with 336 * @param <T> the type to generify around 337 * @return this builder 338 * @since 4.0.0 339 */ 340 public <T> Builder registerExact(final TypeToken<T> type, final TypeSerializer<? super T> serializer) { 341 return registerExact0(type.getType(), serializer); 342 } 343 344 /** 345 * Register an <em>exact</em> type serializer for a given type. 346 * 347 * <p>Serializers will only match exact object types. For example, a 348 * serializer registered for {@code List<String>} would not match when 349 * {@code ArrayList<String>} is queried.</p> 350 * 351 * @param type the type to accept 352 * @param serializer the serializer that will be serialized with 353 * @param <T> the type to generify around 354 * @return this builder 355 * @since 4.0.0 356 */ 357 public <T> Builder registerExact(final Class<T> type, final TypeSerializer<? super T> serializer) { 358 return registerExact0(type, serializer); 359 } 360 361 /** 362 * Register a scalar serializer with its own attached type token. 363 * 364 * <p>Serializers will only match exact object types. For example, a 365 * serializer registered for {@code List<String>} would not match when 366 * {@code ArrayList<String>} is queried.</p> 367 * 368 * @param serializer serializer to register 369 * @param <T> value type 370 * @return this builder 371 * @since 4.0.0 372 */ 373 public <T> Builder registerExact(final ScalarSerializer<T> serializer) { 374 requireNonNull(serializer, "serializer"); 375 return registerExact(serializer.type(), serializer); 376 } 377 378 private Builder registerExact0(final Type type, final TypeSerializer<?> serializer) { 379 requireNonNull(type, "type"); 380 requireNonNull(serializer, "serializer"); 381 this.serializers.add(new RegisteredSerializer(test -> test.equals(type), serializer)); 382 return this; 383 } 384 385 /** 386 * Register all serializers from {@code other} into this collection. 387 * 388 * <p>Creating a child collection should be preferred, but when merging 389 * multiple sets of serializers together, directly adding other 390 * collections may be the best choice.</p> 391 * 392 * @param other source collection 393 * @return this builder 394 * @since 4.0.0 395 */ 396 public Builder registerAll(final TypeSerializerCollection other) { 397 this.serializers.addAll(requireNonNull(other, "other").serializers); 398 return this; 399 } 400 401 /** 402 * Register a customized object mapper to handle 403 * {@link ConfigSerializable}-annotated objects. 404 * 405 * @param factory factory to retrieve object mappers from 406 * @return this builder 407 * @since 4.0.0 408 */ 409 public Builder registerAnnotatedObjects(final ObjectMapper.Factory factory) { 410 return register(Builder::isAnnotatedTarget, factory.asTypeSerializer()); 411 } 412 413 /** 414 * A predicate to restrict the type serializer created by 415 * {@link ObjectMapper.Factory#asTypeSerializer()} to annotated types. 416 * 417 * @return whether a type is annotated with {@link ConfigSerializable} 418 * @since 4.0.0 419 */ 420 static boolean isAnnotatedTarget(final Type type) { 421 return GenericTypeReflector.annotate(type).isAnnotationPresent(ConfigSerializable.class); 422 } 423 424 /** 425 * Create a new type serializer collection. 426 * 427 * @return a newly created collection 428 * @since 4.0.0 429 */ 430 public TypeSerializerCollection build() { 431 return new TypeSerializerCollection(this.parent, this.serializers); 432 } 433 } 434 435 private static final class RegisteredSerializer { 436 437 private final Predicate<Type> predicate; 438 private final TypeSerializer<?> serializer; 439 440 private RegisteredSerializer(final Predicate<Type> predicate, final TypeSerializer<?> serializer) { 441 this.predicate = predicate; 442 this.serializer = serializer; 443 } 444 445 } 446 447}