Hi all,
Background
The appModelContext
, holds reference to patientPrograms
at-least on the patient clinicianfacing dashboard context. As part of work on AF-59, we want to consume the available patientPrograms
property. However, the patientPrograms
was serialized to a SimpleObject
format and in the process de-serializing it back(java), conversion of the associated concepts fails: See in unit test below
@Test
public void testConceptConverter() {
// Setup
List<Concept> concepts = Context.getConceptService().getAllConcepts();
List<SimpleObject> serialisedData = (List<SimpleObject>) ConversionUtil.convertToRepresentation(concepts, Representation.DEFAULT);
List<Concept> deserialisedData = new ArrayList<Concept>();
// Replay
for (SimpleObject obj : serialisedData) {
// Fails here
// The converter seems to treat concept.name property as a String, hence will fail to find the `ConceptName` converter to process the name
deserialisedData.add((Concept) ConversionUtil.convert(obj, Concept.class));
}
}
View on github here.
The Issue
Canāt de-serialize a concept from itās SimpleObject
Representation to java using the available utility method: ConversionUtil.convert(...)
(converter handler under the hood). The above test fails with this error.
Bug Explained
The conversion utility method that serializes a concept works based on the DelegatingResourceDescription depending on the Representation, like you can see, it contains a name
property which is a SimpleObject
and not a string value(see here ). Thatās how we end-up with the nameās property value as an object(Simple object map of name properties) and not a string value.This becomes an issue when de-serialising, the converter
looks at the setter method of the property itās currently processing to determine the target datatype we are converting to, for the case of the name
property, it will try to converting it to the String
type/class; Since the name
value is an instance of a map
, it will look for a converter of type String
which of course doesnāt exist hence the failing(see here)
Possible Fix
We need to have an end to end compatibility of these two operations ie. Serializing a Resource to its Representation and de-serializing it back by the same API.
-
I would put a String value, (Either the nameās āuuidā or āactual name valueā or āsomething betterā) here.
-
Support more than one property setter depending on the candidate methodās(this could be one of the setters of the same property) signature(Using reflection, we can inspect a methodās parameters and compare it with the current property value of instance we are processing)
See pseudo code below:
/**
* Sets the name property to be the fully specified name of the Concept in the current locale
*
* <p>
* This will be invoked if property value is an instanceof String
*
* @param instance
* @param name
*/
@PropertySetter("name")
public static void setFullySpecifiedName(Concept instance, String name) {
ConceptName fullySpecifiedName = new ConceptName(name, Context.getLocale());
instance.setFullySpecifiedName(fullySpecifiedName);
}
/**
* This would be invoked if the property value is an instanceof a Map
*
* @param instance
* @param name
*/
@PropertySetter("name")
public static void setFullySpecifiedName(Concept instance, ConceptName name) {
instance.setFullySpecifiedName(name);
}
ā> 2 may introduce a slightly major change in the way @PropertySetter
annotations are processed while 1 is minor and simpler.
NB: This is the same issue that happens for other properties like concept.answers
.
Thoughts??
/cc: @mksd, @mogoodrich, @dkayiwa