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
Weād also have to figure out exactly what the above method should do⦠assumedy look for any names within the concept with that uuid and update if found, and then add otherwise?