From b587dfeda9e40ae68875fa964007893e7321389f Mon Sep 17 00:00:00 2001 From: Falkreon Date: Fri, 26 Jul 2024 07:42:43 -0500 Subject: [PATCH] Match ObjectReader factory functions more generously --- .../jankson/api/io/ObjectReaderFactory.java | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/main/java/blue/endless/jankson/api/io/ObjectReaderFactory.java b/src/main/java/blue/endless/jankson/api/io/ObjectReaderFactory.java index b363dbd..a0e77ef 100644 --- a/src/main/java/blue/endless/jankson/api/io/ObjectReaderFactory.java +++ b/src/main/java/blue/endless/jankson/api/io/ObjectReaderFactory.java @@ -31,6 +31,7 @@ import java.util.function.Function; import blue.endless.jankson.api.document.ValueElement; +import blue.endless.jankson.impl.TypeMagic; import blue.endless.jankson.impl.io.objectreader.ObjectStructuredDataReader; /** @@ -39,7 +40,23 @@ * readers externally. */ public class ObjectReaderFactory { - private Map> functionMap = new HashMap<>(); + private final Map> functionMap = new HashMap<>(); + /** If true, only match exact types given **/ + private boolean precise = false; + + /** + * When precise is true, only exact matches will be used to generate readers. When precise is + * false, exact matches are preferred, but if an exact match cannot be found, a serializer or + * reader factory function for a superclass will be selected if available. + * + *

Note that fuzzy matching of classes requires a full traversal of the registrations, so the + * more registrations there are, the larger the speed gain precise mode will have. + * + * @param value true to put this factory in precise mode, false to match loosely. Defaults to false. + */ + public void setPrecise(boolean value) { + this.precise = value; + } /** * Registers a "classic" serializer for the specified type. @@ -110,9 +127,18 @@ public StructuredDataReader getReader(Type type, final Object objectOfType) { } Function function = functionMap.get(type); - return (function == null) ? - ObjectStructuredDataReader.of(objectOfType, this) : - function.apply(objectOfType); + if (function != null) return function.apply(objectOfType); + + if (!precise) { + Class targetClass = TypeMagic.getErasedClass(type); + for(Map.Entry> entry : functionMap.entrySet()) { + Class curClass = TypeMagic.getErasedClass(entry.getKey()); + if (curClass.isAssignableFrom(targetClass)) return entry.getValue().apply(objectOfType); + entry.getKey().getClass().isAssignableFrom(type.getClass()); + } + } + + return ObjectStructuredDataReader.of(objectOfType, this); } /** @@ -124,4 +150,12 @@ public StructuredDataReader getReader(Type type, final Object objectOfType) { public StructuredDataReader getReader(Object object) { return getReader(object.getClass(), object); } + + public ObjectReaderFactory copy() { + ObjectReaderFactory result = new ObjectReaderFactory(); + result.functionMap.putAll(this.functionMap); + result.precise = this.precise; + + return result; + } }