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}