First, a bit of history.
Back in the Naked Objects days we defined ValueSemanticsProvider as an interface that provides the metadata about built-in and potentially custom value types as well. This interface is defined as:
public interface ValueSemanticsProvider<T> { Parser<T> getParser(); EncoderDecoder<T> getEncoderDecoder(); DefaultsProvider<T> getDefaultsProvider(); boolean isImmutable(); boolean isEqualByContent(); }
This dates from the days when the framework pretty much did everything: the UI was its own widget set, persistence was also home-grown, and there was also client/server support:
- the Parser class was used in the UI to read from widgets into the target value type
- the EncoderDecoder was used to serialize the state of the value, either to the persistence store or also for networking (client/server support)
- the DefaultsProvider was also used in core (and apparent in the UI) to initialize values to a known state - eg a date would default to today's date, rather than null, say.
This class does still exist pretty much unchanged, though its exact purpose is no longer quite so clear cut, primarily because we now have 3rd party libraries for the UI and persistence, and we have dropped the client/server stuff:
- Wicket has its own IConverter interface (org.apache.wicket.util.convert.IConverter) which takes the role of Parser.
- The RO viewer does its own conversions from input JSON (as defined in the RO spec - need to look up the references), and I'm pretty sure doesn't leverage VSPs at all.
- DataNucleus has its own SPIs, namely org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping and org.datanucleus.store.rdbms.mapping.column.ColumnMapping; an implementation of both is required. We provide these for Blob and Clob
- Details of the SPI are here: http://www.datanucleus.org:15080/products/accessplatform_5_0/extensions/extensions.html#type
- Our plugin.xml for Blob and Clob is here : https://github.com/apache/isis/blob/master/persistence/jdo/datanucleus-5/src/main/resources/plugin.xml
- NB: DN will simply use Java serialization if the value being persisted supports it. This is probably what is going on for Markup and AsciiDoc.
Put together, I am pretty sure that Parser, EncoderDecoder and DefaultsProvider are no longer used anywhere. And the immutable and equalByContent possibly never were used, they were more "for future use".
The current state
In the meantime, as v1.x has evolved, there have been a number of new features that ideally need to be flexible enough to support custom value types
- With isis-core-schema and its ValueType enum, we have a built-in list of value types that we support, but because this is an enum, there's no way to add in new value types (except by releasing a new version of the framework with an updated enum).
- For Joerg's new RO client, he could use some additional mime/types for values such as Markup and AsciiDoc that are basically just text/html .
- We've thought for a long time about being able to teach the viewers about new value types, so that they can transparently handle them.
Realistically, I think this is going to be "horses for courses": each third party library (viewer or persistence) will have its own way of teaching it about the value type.
Proposal: Use VSP for simple value types (single fields)
But what we might be able to do is define some common semantics in an updated version of the VSP interface, and then have an Isis-provided implementation of the appropriate SPI that can leverage this additional metadata.
For example, considering the Wicket viewer - my suspicion is that its IConverter can do a lot of the work (and we already implement this for some of our built-ins). We could therefore have a ConverterThatUsesValueSemanticsProvider which uses the VSP to do the conversion etc. Perhaps this will require keeping Parser and EncoderDecoder as our own internal SPIs, and then bridge across to them.
Similarly, for DN, for the SPIs to be implemented (JavaTypeMapping and ColumnMapping), we could perhaps have JavaTypeMappingThatUsesValueSemanticsProvider and ColumnMappingThatUsesValueSemanticsProvider.
For the RO viewer, which is home grown (as per the RO spec), we would need to invent some sort of SPI. I imagine that this SPI would require mime types to be part of the mix.
As and when we integrate other viewers (eg Vaadin) or persistence stores (eg EclipseLink/Hibernate), then they will undoubtedly have their own SPIs similarly. So again, it should be SomeSpiThatUsesValueSemanticsProvider.
Proposal: don't bother for Value types with multiple fields
The above general purpose idea will suffice for simple value types, basically wrappers around a single string or number, but something more sophisticated will be required for values that constitute multiple fields, such as an Interval (from, to) or a Coordinate (x,y) or an ImaginaryNumber (real, complex).
For the Wicket viewer, presumably the input of these values would require two separate fields, and might be rendered as two fields or perhaps as a single field (eg "5+3i" for a complex number)
For DN, I see that SingleFieldMultiMapping inherits from JavaTypeMapping, so I hope that a value could be stored into separate columns, but again some more metadata will be required.
My suspicion is that this will become really difficult to accomplish in a fully generic way. Therefore, for more complex value types we should simply structure the extensions module to have the appropriate submodules for those integrations that exist.
In other words, if I look at the valuetypes/coordinate directory, for example, it would look something like:
valuetypes/coordinate/
applib/ - defines the value type itself
wicket/ - module to link to if using the value type in Wicket
restful/ - module to link to if using the value type in any actions or properties of domain objects exposed via the RO viewer
vaadin/ - module to link to if using the value type in Vaadin
datanucleus/ - if using JDO/DN
hibernate/ - if using JPA/hibernate
schema/ - if wanting to use the value type in schema (still not sure about this one, and that ValueType enum)
1 Comment
Daniel Keir Haywood
Some discussion from #slack channel:
12:31
sticking with the complex number example, I think all we need for a generic solution is to support a typed Tuple, where the types are those the schema provides 12:32
Maybe so ... though it makes sense to me to tackle the lower hanging fruit of single scalars first. After that, perhaps the way to generalize into a typed Tuple will be obvious.
12:32
a complex number would then map onto a Tuple<BigDecimal, BigDecimal>
12:33
we could also render such tuples in a generic way
12:34
Well, we would want some control over the rendering. It could be that they are all just shown as a single scalar string, with the Parser class (or similar) responsible for returning that string
12:34
eg "2+3i" or "[30.23, 40.54]" or "20/1/2009 to 23/1/2009"
12:35
Perhaps that's the more common use case than rendering the constituent parts of the value type separately
12:35
or simple as 2 big_decimals, which we already know how to render (somehow grouped together with a tilte or so)
12:36
Well, maybe, but there's no obvious answer that fits all cases. And so the VSP will end up being quite a complicated thing if we want to fully generify this in all cases.
12:37
(eg consider a value type that is for a graph structure, say)
12:39
I agree, yet I do have at least 2 custom types where this tuple approach would perfectly fit
12:40
So, we should get there bit-by-bit, tackling progressively more complicated value types. If we can find a sensible generic approach, that's great, but I'd rather get there gradually
12:41
yep