Each factory allows conversion between two versions of FHIR, specified by `VERSION A` and `VERSION B`. The syntax of each version is described briefly in the following section.
If you are developing or debugging conversion routines, you will likely need to access the individual Resource, DataType, and Primitive conversion classes.
These are located in the following packages:
* org.hl7.fhir.convertors.conv10_30
* org.hl7.fhir.convertors.conv10_40
* org.hl7.fhir.convertors.conv10_50
* org.hl7.fhir.convertors.conv14_30
* org.hl7.fhir.convertors.conv14_40
* org.hl7.fhir.convertors.conv14_50
* org.hl7.fhir.convertors.conv30_40
* org.hl7.fhir.convertors.conv30_50
* org.hl7.fhir.convertors.conv40_50
* org.hl7.fhir.convertors.conv43_50
These classes follow the convention:
`(NAME)` + `(VERSION A)` + `_` + `(VERSION B)`
Where `NAME` is the proper name of the resource or datatype being converted, and `VERSION A` and `VERSION B` indicate the two versions of FHIR that the code will convert the given resource or datatype between (See [Conversion Version Syntax](#-conversion-version-syntax) for version details).
So, in the repository, you may come across a file name `AllergyIntolerance40_50`. This would indicate that the code in this file is related to the conversion of the AllergyIntolerance resource between versions [r4](http://hl7.org/fhir/r4/allergyintolerance.html) and [r5](https://hl7.org/fhir/r5/allergyintolerance.html)
Note that these classes are not intended to be used directly. When actually converting resources, the provided conversion factory classes are intended to be used as the entry point. For example, to convert a dstu3 AllergyIntolerance resource, the above conversion would not use `AllergyIntolerance40_50` directly, but would instead call: `VersionConvertorFactory_40_50.convertResource(dstu3AllergyIntolerance)`. `VersionConvertorFactory_40_50` would call `AllergyIntolerance40_50` internally to convert `r4AllergyIntolerance`.
Conversion classes are implemented using some simple, repeatable patterns. `AllegeryIntolerance40_50` will be used as an example of this. Each conversion class for a resource will have two entry points, allowing for conversions to be done to and from the two versions in the convertor.
```java
public static org.hl7.fhir.r5.model.AllergyIntolerance convertAllergyIntolerance(org.hl7.fhir.r4.model.AllergyIntolerance src);
public static org.hl7.fhir.r4.model.AllergyIntolerance convertAllergyIntolerance(org.hl7.fhir.r5.model.AllergyIntolerance src)
```
Initially, a target resource is created in the appropriate method. Upon the completion of the conversion, this target resource is returned. In our case, the target resource is
version 50, or r5.
```java
public static org.hl7.fhir.r5.model.AllergyIntolerance convertAllergyIntolerance(org.hl7.fhir.r4.model.AllergyIntolerance src){
//...
org.hl7.fhir.r5.model.AllergyIntolerance tgt = new org.hl7.fhir.r5.model.AllergyIntolerance();
//...
}
```
After the target resource is created, the elements of the source resource need to be converted to the target version, and added to the target resource. Many elements can be copied automatically using the static methods provided in the `ConversionContext` and `VersionConvertor` classes. These classes follow the convention:
An example usage is in the copying of [DomainResource](https://build.fhir.org/domainresource.html) elements (`text`, `contained`, `extension`, and `modifierExtension`). In FHIR, all listed Resources except Bundle, Parameters and Binary extend DomainResource. Copying DomainResource elements is done using the following code:
A special case exists for the conversion of extensions. As mentioned above, the `copyDomainResource(src, tgt)` method is used to copy the extensions from one resource to another. This applies a default conversion process to all extensions (see [Using conversion advisors](#using-conversion-advisors) for details).
However, in some conversion cases, an extension may exist that can be converted into a resource element. An example of this is the `acceptUnknown` element in the dstu3 [CapabilityStatement](http://hl7.org/fhir/STU3/capabilitystatement-definitions.html#CapabilityStatement.acceptUnknown) resource. This element does not exist in versions r4 and up, so is converted into an extension with the url `http://hl7.org/fhir/3.0/StructureDefinition/extension-CapabilityStatement.acceptUnknown`. Should this extension exist in a resource being converted to a CapabilityStatement in dstu3, the convertor needs to convert this extension to an element, and to indicate to the copyDomainResource method that the extension should not be copied.
First, since the copyDomainResource occurs early in the conversion process, we need to indicate all the ignored URLs using the vararg parameter `extensionUrlsToIgnore`:
After all necessary elements are converted, the conversion is complete, and the target resource is returned.
## Extending Conversion Functionality
As the FHIR specification has evolved over time, the versions of FHIR have built on top of one another, adding new fields within existing resources, changing the name of existing resources, or adding entirely new resources altogether. As a result of this conversions are inherently lossy operations.
A quick example of this would be [ValueSet Expression](https://www.hl7.org/fhir/extension-valueset-expression.html) extension type. This exists in the r4 version of the specification, but no such type exists in dstu2.
If we were to convert a R4 resource, such as a questionnaire, that contained an extension of this type from r4 -> dstu2, without any special intervention, the extension would be ignored, and the data would be lost in the conversion process.
When you call the base conversion factory methods `convertType(...)` or `convertResource(...)`, the library does a predefined conversion, using the standard conversion (which could be a lossy one, or one that makes assumptions).
These defaults/assumptions are defined in the convertor advisor classes. Each pair of versions has a BaseAdvisor, which is used by default when you call the factory methods. For example, here is the advisor class which handles conversions between dstu2 and r5:
You can see in the `ignoreType` implementation above that we check if we are converting a DataType of the `Expression` class. The `Expression` DataType did not exist in dstu2, and is ignored when doing this particular conversion.
As mentioned above, we provide a stock set of implied conversion rules that are used by default. However, there may be cases where you need to add specific behavior to your conversion. Within the `BaseAdvisor` class, there exist a number of overrideable methods that can be used to modify the outcome of any given conversion:
Through overriding these methods and implementing your own custom advisor, you can customize the output of any given conversion operation to suit your specific use-case.
Our stock advisor just ignores this extension when converting from r5 to dstu2. However, if we wanted, we could create our own conversion advisor, as follows:
Here, we first check to see if the extension is of type `org.hl7.fhir.r5.model.Expression` and has a value set in the `useAdvisorForExtension` method, then in the `handleExtension` method, we manually create a `StringType` extension, and copy the value from the r5 `Expression` into it. This results in no data being lost, and a the new custom conversion behavior for our particular use-case.