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}