- Pods
- AF-BedSheet 1.0.4
- API
- ValueEncoders
- Src
sourceafBedSheet::ValueEncoders.fan
using afIoc::ConcurrentState
using afIoc::StrategyRegistry
using afIoc::TypeCoercer
** Holds a list of `ValueEncoder`s.
**
** pre>
** @Contribute { serviceType=ValueEncoders# }
** static Void contributeValueEncoders(MappedConfig conf) {
** conf[MyEntity#] = conf.autobuild(MyEntityEncoder#)
** }
** <pre
**
** @uses a MappedConfig of 'Type:ValueEncoder'
const mixin ValueEncoders {
** Converts the given 'value' to Str via a contributed `ValueEncoder`. If no 'ValueEncoder' is
** found, 'toStr()' is used.
abstract Str toClient(Type valType, Obj value)
** Converts the given 'clientValue' into the given 'valType' via a contributed `ValueEncoder`.
** If no 'ValueEncoder' is found the value is [coerced]`afIoc::TypeCoercer`.
abstract Obj toValue(Type valType, Str clientValue)
}
internal const class ValueEncodersImpl : ValueEncoders {
private const ConcurrentState conState := ConcurrentState(ValueEncodersState#)
private const StrategyRegistry valueEncoderStrategy
internal new make(Type:ValueEncoder valueEncoders) {
this.valueEncoderStrategy = StrategyRegistry(valueEncoders)
}
override Str toClient(Type valType, Obj value) {
// check the basics first!
if (value is Str)
return value
valEnc := get(valType)
if (valEnc != null)
try {
return valEnc.toClient(value)
} catch (Err cause) {
throw ValueEncodingErr(BsMsgs.valueEncodingBuggered(value, Str#), cause)
}
return value.toStr
}
override Obj toValue(Type valType, Str clientValue) {
// check the basics first!
if (valType.fits(Str#))
return clientValue
valEnc := get(valType)
if (valEnc != null)
try {
return get(valType).toValue(clientValue)
} catch (Err cause) {
throw ValueEncodingErr(BsMsgs.valueEncodingBuggered(clientValue, valType), cause)
}
if (getState() { it.typeCoercer.canCoerce(Str#, valType) } == false)
throw ValueEncodingErr(BsMsgs.valueEncodingNotFound(valType))
try {
return getState() { it.typeCoercer.coerce(clientValue, valType) }
} catch (Err cause) {
throw ValueEncodingErr(BsMsgs.valueEncodingBuggered(clientValue, valType), cause)
}
}
private ValueEncoder? get(Type valueType) {
valueEncoderStrategy.findBestFit(valueType, false)
}
private Obj? getState(|ValueEncodersState -> Obj| state) {
conState.getState(state)
}
}
internal class ValueEncodersState {
TypeCoercer typeCoercer := TypeCoercer()
}