Class loaders
A ReflectClassLoader keeps its own descriptors and factories, asks an optional parent next, and falls back to the global registry last.
Ask by name
Registered descriptors carry their base types, so the loader answers subtype questions without runtime classes.
- loader.isAssignableFrom("demo.Dog", "demo.Animal")
- true
- loader.getSubTypes("demo.Animal").map(_.simpleName).distinct
- List(Animal, Dog, Cat)
- loader.createInstanceAs[Dog]("demo.Dog").map(_.name)
- Some(Milo)
Every type counts as its own subtype, and a type found both locally and in the global registry can appear twice. Deduplicate by typeName when you list the results.
Local, parent, global
loadClass asks the loader's own entries, then its parent, then the global ReflectRegistry. register publishes the descriptor to the global registry as well.
- child.loadClass("demo.Person").isDefined
- true
- child.createInstanceAs[Person]("demo.Person")
- Some(Person(Ada,37))
- ReflectRegistry.contains("demo.Person")
- true
Because registrations reach the global registry, every loader and the registry itself can see them. Use loaders for lookup order and local factories, not to hide types from each other.
Text next to the types
ReflectClassLoaderWithResources adds a store for named strings, such as a schema or a template that belongs to the registered types.
- loader.getResource("person.schema.json")
- Some({"title":"Person"})