const classafBeanUtils::TypeLookup

sys::Obj
  afBeanUtils::TypeLookup

@Js

Looks up values via a type inheritance search.

Example, if a TypeLookup was created with Obj#, Num# and Int#, the inheritance and matching types would look like:

Type  findParent()  findChildren()

Obj   Obj           Obj, Num, Int
 | 
Num   Num           Num, Int
 |
Int   Int           Int

Note that findParent() and findChildren() return the value associated with the type, not the type itself. They also match the given type if TypeLookup was created with it, hence findParent() above matches itself.

While the above results are quite obvious, TypeLookup is more useful when passed a type it doesn't know about:

findParent(Float#)    // --> Num#
findChildren(Float#)  // --> Err

When searching the type hierarchy for a closest match (see findParent() ), note that TypeLookup also searches mixins.

Example usages can be found in:

  • IoC: All known implementations of a mixin are looked up via findChildren()
  • BedSheet: Strategies for handling Err types are looked up via findParent()

If performance is required, then use Concurrent to create a TypeLookup that caches the lookups. Full code for a CachingTypeLookup is given below:

using afBeanUtils
using afConcurrent

** A 'TypeLookup' that caches the lookup results.
internal const class CachingTypeLookup : TypeLookup {
    private const AtomicMap parentCache   := AtomicMap()
    private const AtomicMap childrenCache := AtomicMap()

    new make(Type:Obj? values) : super(values) { }
    
    ** Cache the lookup results
    override Obj? findParent(Type type, Bool checked := true) {
        nonNullable := type.toNonNullable
        return parentCache.getOrAdd(nonNullable) { doFindParent(nonNullable, checked) } 
    }
    
    ** Cache the lookup results
    override Obj?[] findChildren(Type type, Bool checked := true) {
        nonNullable := type.toNonNullable
        return childrenCache.getOrAdd(nonNullable) { doFindChildren(nonNullable, checked) } 
    }

    ** Clears the lookup cache 
    Void clear() {
        parentCache.clear
        childrenCache.clear
    }
}
findChildren

Source

virtual Obj?[] findChildren(Type type, Bool checked := true)

Returns the values of the children of the given type. Note an exact match is performed first. Example:

strategy := StrategyRegistry( [Obj#:1, Num#:2, Int#:3] )
strategy.findChildren(Obj#)     // --> [1, 2, 3]
strategy.findChildren(Num#)     // --> [2, 3]
strategy.findChildren(Float#)   // --> Err

If no children are found and checked is false, an empty list is returned.

findExact

Source

Obj? findExact(Type exact, Bool checked := true)

Returns the value that matches the given type. This is just standard Map behaviour.

If no match is found and checked is false, null is returned.

findParent

Source

virtual Obj? findParent(Type type, Bool checked := true)

Returns the value of the closest parent of the given type. Note an exact match is performed first. Example:

strategy := StrategyRegistry( [Obj#:1, Num#:2, Int#:3] )
strategy.findClosestParent(Obj#)     // --> 1
strategy.findClosestParent(Num#)     // --> 2
strategy.findClosestParent(Float#)   // --> 2
strategy.findClosestParent(Wotever#) // --> Err

If no parent is found and checked is false, null is returned.

make

Source

new make(Type:Obj? values)

Creates a TypeLookup with the given map. All types are coerced to non-nullable types. An ArgErr is thrown if a duplicate is found in the process.

types

Source

Type[] types()

Returns a list of all the types this lookup is configured for. (Handy for debug / error messages.)