Converter for Lazy<->?
In addition to the primitive and wrapper value converters, one of the most common cases for refactorings will probably be the change to and from a Lazy reference.
So BinaryValueSetters for
- Lazy->?
- ?->Lazy
are necessary.
I have implemented the two methods BinaryValueTranslators#removeLazyReference BinaryValueTranslators#wrapWithLazyReference
However, this topic is not trivial:
- The mapping can't be done automatically/implicitely.
- The removing translator even can't work at all at the moment. It throws an UnsupportedOperationException("Architecture does not support a new loading during loading."). The wrapping translator works if registered explicitely.
Rationale:
About removing not being able to work at the moment:
A Lazy reference causes a new loading process to be executed. Without that loading process, the referenced instance is usually null and only the objectId value is present. Value translators are executed during an ongoing loading process, more precisly during the instance updating ("filling with data") phase. It is currently not possible to start a new loading process in the instance updating phase. The order is: 1.) loop on requesting binary records for missing objectIds and iterate their loadable references for further missing objectIds until no more objectId is missing. 2.) create ("empty") instances if required 3.) update/fill all instances with data 4.) complete (special completing update for structures like hash collections that need filled instances to work correctly)
ValueTranslators are called in # 3. ObjectId resolving happens in # 1. This would cause a new loading process to be started during an ongoing loading process, which might cause inconsistencies. Maybe it would work, but that would require a lot of thorough analysis and testing. For a "removeLazyReference" translation to work without such a "nested loading", the lazy reference to be removed would have to be handled as an eager reference in phase # 1 to ensure its referenced instance to be present in # 3. Or the whole process would have to be made significantly more complex (e.g. several consecutive iterations of those phases).
Either solution is not trivial to implement and must be further discussed and prioritized.
About not being automatical:
The value translator lookup works on concrete classes for old/source and new/target type. E.g.: get a translator from Float to float. Or Float to Integer. Or String to char[]. Registering a translator generically can only work on generic types, i.e. general JDK and library types. The two translators could be registered specifically for Lazy -> Object and Object -> Lazy, but that would not cover any other type (Float, Integer, String, etc.) not to mention application-specific types (like Person, Address, etc.). Additionally, since generics type parameters are not included in type descriptions (yet), there can't be a distinction between, for example, Lazy<String> and Lazy<Integer>. The only per-type registration could be for Lazy itself, regardless of its reference type.
As a consequence, those value translators (actually ANY value translator that does not have both of its types as general JDK/library types) can only be reasonably set by the user for an explicit case, e.g. a certain field of a certain type with a certain type version (typeId).
An example for explicitely registering a translator for a custom specified case is the following:
EmbeddedStorageManager storage = EmbeddedStorage
.Foundation()
.onConnectionFoundation(cf -> cf
.setTranslatorKeyBuilders(X.Enum((st, sm, tt, tm) -> derive a unique key))
.setCustomTranslatorLookup(X.Table(the unique key, BinaryValueTranslators::wrapWithLazyReference))
)
.start()
;
Extending the current, specific lookup logic with a polymorph fallback lookup (e.g. "if Lazy -> T yields no result, try a Lazy -> Object lookup") could work. However, that would introduce ambiguities, i.e. sooner or later wrong behavior in certan cases and it would still not solve the Lazy's missing type parameter information. This, too, would require further extensive analysis and discussion.
A simple solution could be, to "somehow" mark Lazy References to be eager. An eagerly loaded lazy reference could easily be removed and replaced by its actual reference.
However, then the problem would be, how to determine which lazy references must be marked. A list of objectIds referenced in the BinaryHandlerLazy? Does the user then have to determine all the objectIds manually? That would be very tedious.
Sadly, a simple "all Lazy references of parent entities matching condition x" is not so simple to implement.
This would just shift the problem to some other place ...