This repository has been archived by the owner on Jun 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d44f981
commit 2aa7fee
Showing
4 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
...erated-data/src/main/java/gov/va/api/health/patientgenerateddata/JacksonMapperConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package gov.va.api.health.patientgenerateddata; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import gov.va.api.health.autoconfig.configuration.JacksonConfig; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class JacksonMapperConfig { | ||
|
||
private final MagicReferenceConfig magicReferences; | ||
|
||
@Autowired | ||
public JacksonMapperConfig(MagicReferenceConfig magicReferences) { | ||
this.magicReferences = magicReferences; | ||
} | ||
|
||
@Bean | ||
public ObjectMapper objectMapper() { | ||
ObjectMapper mapper = JacksonConfig.createMapper(); | ||
return magicReferences.configure(mapper); | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
...rated-data/src/main/java/gov/va/api/health/patientgenerateddata/MagicReferenceConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package gov.va.api.health.patientgenerateddata; | ||
|
||
import com.fasterxml.jackson.core.JsonGenerator; | ||
import com.fasterxml.jackson.databind.BeanDescription; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.databind.SerializationConfig; | ||
import com.fasterxml.jackson.databind.SerializerProvider; | ||
import com.fasterxml.jackson.databind.module.SimpleModule; | ||
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; | ||
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; | ||
import gov.va.api.health.fhir.api.IsReference; | ||
import gov.va.api.health.r4.api.elements.Reference; | ||
import java.util.List; | ||
import lombok.SneakyThrows; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class MagicReferenceConfig { | ||
private final String baseUrl; | ||
|
||
private final String r4BasePath; | ||
|
||
@Autowired | ||
public MagicReferenceConfig( | ||
@Value("${public-url}") String baseUrl, @Value("${public-r4-base-path}") String r4BasePath) { | ||
this.baseUrl = baseUrl; | ||
this.r4BasePath = r4BasePath; | ||
} | ||
|
||
/** Configures and returns the mapper to support magic references. */ | ||
public ObjectMapper configure(ObjectMapper mapper) { | ||
mapper.registerModule(new MagicReferenceModule()); | ||
return mapper; | ||
} | ||
|
||
private final class QualifiedReferenceWriter extends BeanPropertyWriter { | ||
|
||
private QualifiedReferenceWriter(BeanPropertyWriter base) { | ||
super(base); | ||
} | ||
|
||
private String qualify(String reference) { | ||
if (StringUtils.isBlank(reference)) { | ||
return null; | ||
} | ||
if (reference.startsWith("http")) { | ||
return reference; | ||
} | ||
if (reference.startsWith("/")) { | ||
return baseUrl + "/" + r4BasePath + reference; | ||
} | ||
return baseUrl + "/" + r4BasePath + "/" + reference; | ||
} | ||
|
||
@Override | ||
@SneakyThrows | ||
public void serializeAsField( | ||
Object shouldBeReference, JsonGenerator gen, SerializerProvider prov) { | ||
if (!(shouldBeReference instanceof IsReference)) { | ||
throw new IllegalArgumentException( | ||
"Qualified Reference writer cannot serialize: " + shouldBeReference); | ||
} | ||
IsReference reference = (IsReference) shouldBeReference; | ||
String qualifiedReference = qualify(reference.reference()); | ||
if (qualifiedReference != null) { | ||
gen.writeStringField(getName(), qualifiedReference); | ||
} | ||
} | ||
} | ||
|
||
private final class MagicReferenceModule extends SimpleModule { | ||
@Override | ||
public void setupModule(SetupContext context) { | ||
super.setupModule(context); | ||
context.addBeanSerializerModifier( | ||
new BeanSerializerModifier() { | ||
private void applyReferenceWriter(List<BeanPropertyWriter> beanProperties) { | ||
for (int i = 0; i < beanProperties.size(); i++) { | ||
BeanPropertyWriter beanPropertyWriter = beanProperties.get(i); | ||
if ("reference".equals(beanPropertyWriter.getName())) { | ||
beanProperties.set(i, new QualifiedReferenceWriter(beanPropertyWriter)); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public List<BeanPropertyWriter> changeProperties( | ||
SerializationConfig serialConfig, | ||
BeanDescription beanDesc, | ||
List<BeanPropertyWriter> beanProperties) { | ||
if (beanDesc.getBeanClass() == Reference.class) { | ||
applyReferenceWriter(beanProperties); | ||
} | ||
return super.changeProperties(serialConfig, beanDesc, beanProperties); | ||
} | ||
}); | ||
} | ||
} | ||
} |
145 changes: 145 additions & 0 deletions
145
...ed-data/src/test/java/gov/va/api/health/patientgenerateddata/JacksonMapperConfigTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package gov.va.api.health.patientgenerateddata; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import com.fasterxml.jackson.annotation.JsonAutoDetect; | ||
import gov.va.api.health.autoconfig.configuration.JacksonConfig; | ||
import gov.va.api.health.r4.api.DataAbsentReason; | ||
import gov.va.api.health.r4.api.elements.Extension; | ||
import gov.va.api.health.r4.api.elements.Reference; | ||
import java.util.List; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
import lombok.Singular; | ||
import lombok.SneakyThrows; | ||
import org.junit.jupiter.api.Test; | ||
|
||
public class JacksonMapperConfigTest { | ||
private static Reference reference(String path) { | ||
return Reference.builder().display("display-value").reference(path).id("id-value").build(); | ||
} | ||
|
||
@Test | ||
@SneakyThrows | ||
public void preExistingDarsArePreserved() { | ||
FugaziReferenceMajig input = | ||
FugaziReferenceMajig.builder() | ||
.ref(reference("https://example.com/api/Practitioner/1234")) | ||
.nope(null) | ||
._nope(DataAbsentReason.of(DataAbsentReason.Reason.error)) | ||
.build(); | ||
FugaziReferenceMajig expected = | ||
FugaziReferenceMajig.builder() | ||
.ref(reference("https://example.com/api/Practitioner/1234")) | ||
.nope(null) | ||
._nope(DataAbsentReason.of(DataAbsentReason.Reason.error)) | ||
.build(); | ||
String serializedJson = | ||
new JacksonMapperConfig(new MagicReferenceConfig("https://example.com", "r4")) | ||
.objectMapper() | ||
.writerWithDefaultPrettyPrinter() | ||
.writeValueAsString(input); | ||
FugaziReferenceMajig actual = | ||
JacksonConfig.createMapper().readValue(serializedJson, FugaziReferenceMajig.class); | ||
assertThat(actual).isEqualTo(expected); | ||
} | ||
|
||
@Test | ||
@SneakyThrows | ||
public void referencesAreQualified() { | ||
FugaziReferenceMajig input = | ||
FugaziReferenceMajig.builder() | ||
.whocares("noone") | ||
.me(true) | ||
.ref(reference("AllergyIntolerance/1234")) | ||
.nope(reference("https://example.com/r4/Location/1234")) | ||
._nope(DataAbsentReason.of(DataAbsentReason.Reason.unsupported)) | ||
.alsoNo(reference("https://example.com/r4/Location/1234")) | ||
.thing(reference(null)) | ||
.thing(reference("")) | ||
.thing(reference("http://qualified.is.not/touched")) | ||
.thing(reference("no/slash")) | ||
.thing(reference("/cool/a/slash")) | ||
.thing(reference("Location")) | ||
.thing(reference("Location/1234")) | ||
.thing(reference("https://example.com/r4/Location/1234")) | ||
.thing(reference("/Organization")) | ||
.thing(reference("Organization/1234")) | ||
.thing(reference("https://example.com/r4/Organization/1234")) | ||
.thing(reference("Practitioner/987")) | ||
.inner( | ||
FugaziReferenceMajig.builder() | ||
.ref( | ||
Reference.builder() | ||
.reference("Practitioner/615f31df-f0c7-5100-ac42-7fb952c630d0") | ||
.display(null) | ||
.build()) | ||
.build()) | ||
.build(); | ||
FugaziReferenceMajig expected = | ||
FugaziReferenceMajig.builder() | ||
.whocares("noone") | ||
.me(true) | ||
.nope(reference("https://example.com/r4/Location/1234")) | ||
._nope(DataAbsentReason.of(DataAbsentReason.Reason.unsupported)) | ||
.alsoNo(reference("https://example.com/r4/Location/1234")) | ||
.ref(reference("https://example.com/r4/AllergyIntolerance/1234")) | ||
.thing(reference(null)) | ||
.thing(reference(null)) | ||
.thing(reference("http://qualified.is.not/touched")) | ||
.thing(reference("https://example.com/r4/no/slash")) | ||
.thing(reference("https://example.com/r4/cool/a/slash")) | ||
.thing(reference("https://example.com/r4/Location")) | ||
.thing(reference("https://example.com/r4/Location/1234")) | ||
.thing(reference("https://example.com/r4/Location/1234")) | ||
.thing(reference("https://example.com/r4/Organization")) | ||
.thing(reference("https://example.com/r4/Organization/1234")) | ||
.thing(reference("https://example.com/r4/Organization/1234")) | ||
.thing(reference("https://example.com/r4/Practitioner/987")) | ||
.inner( | ||
FugaziReferenceMajig.builder() | ||
.ref( | ||
Reference.builder() | ||
.reference( | ||
"https://example.com/r4/Practitioner/615f31df-f0c7-5100-ac42-7fb952c630d0") | ||
.build()) | ||
.build()) | ||
.build(); | ||
String qualifiedJson = | ||
new JacksonMapperConfig(new MagicReferenceConfig("https://example.com", "r4")) | ||
.objectMapper() | ||
.writerWithDefaultPrettyPrinter() | ||
.writeValueAsString(input); | ||
FugaziReferenceMajig actual = | ||
JacksonConfig.createMapper().readValue(qualifiedJson, FugaziReferenceMajig.class); | ||
assertThat(actual).isEqualTo(expected); | ||
} | ||
|
||
@Data | ||
@Builder | ||
@NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
@AllArgsConstructor | ||
@JsonAutoDetect( | ||
fieldVisibility = JsonAutoDetect.Visibility.ANY, | ||
isGetterVisibility = JsonAutoDetect.Visibility.NONE) | ||
static final class FugaziReferenceMajig { | ||
Reference ref; | ||
|
||
Reference nope; | ||
|
||
Extension _nope; | ||
|
||
Reference alsoNo; | ||
|
||
@Singular List<Reference> things; | ||
|
||
JacksonMapperConfigTest.FugaziReferenceMajig inner; | ||
|
||
String whocares; | ||
|
||
Boolean me; | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
patient-generated-data/src/test/resources/application.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
public-r4-base-path=unset | ||
public-url=unset | ||
spring.datasource.url=jdbc:h2:. | ||
ssl.enable-client=false | ||
web-exception-key=test |