1
0
mirror of https://github.com/pcvolkmer/etl-processor.git synced 2025-07-17 21:02:54 +00:00

fix: serialization issue with fhir consent and embedding research consent

This commit is contained in:
Jakub Lidke
2025-07-09 19:08:42 +02:00
parent 357abe2b05
commit 3a2f37c34c
8 changed files with 40 additions and 41 deletions

View File

@ -8,7 +8,6 @@ import java.util.Date;
import java.util.Optional; import java.util.Optional;
import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
@ -185,7 +184,7 @@ public class GicsConsentService implements ICheckConsent {
throw new IllegalStateException( throw new IllegalStateException(
"consent data request failed - stopping processing! - try again or fix other problems first."); "consent data request failed - stopping processing! - try again or fix other problems first.");
} }
IBaseResource iBaseResource = fhirContext.newXmlParser() var iBaseResource = fhirContext.newJsonParser()
.parseResource(consentDataSerialized); .parseResource(consentDataSerialized);
if (iBaseResource instanceof OperationOutcome) { if (iBaseResource instanceof OperationOutcome) {
// log error - very likely a configuration error // log error - very likely a configuration error

View File

@ -1,20 +1,18 @@
package dev.dnpm.etl.processor.config package dev.dnpm.etl.processor.config
import ca.uhn.fhir.context.FhirContext
import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.JsonNode
import org.hl7.fhir.instance.model.api.IBaseResource import org.hl7.fhir.r4.model.Consent
class IBaseResourceDeserializer : JsonDeserializer<IBaseResource>() { class ConsentResourceDeserializer : JsonDeserializer<Consent>() {
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): IBaseResource { override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Consent {
val fhirContext = FhirContext.forR4()
val jsonNode = p?.readValueAsTree<JsonNode>() val jsonNode = p?.readValueAsTree<JsonNode>()
val json = jsonNode?.toString() val json = jsonNode?.toString()
return fhirContext.newJsonParser().parseResource(json) as IBaseResource return JacksonConfig.fhirContext().newJsonParser().parseResource(json) as Consent
} }
} }

View File

@ -0,0 +1,15 @@
package dev.dnpm.etl.processor.config
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import org.hl7.fhir.r4.model.Consent
class ConsentResourceSerializer : JsonSerializer<Consent>() {
override fun serialize(
value: Consent, gen: JsonGenerator, serializers: SerializerProvider
) {
val json = JacksonConfig.fhirContext().newJsonParser().encodeResourceToString(value)
gen.writeRawValue(json)
}
}

View File

@ -2,11 +2,11 @@ package dev.dnpm.etl.processor.config
import com.fasterxml.jackson.databind.module.SimpleModule import com.fasterxml.jackson.databind.module.SimpleModule
import org.hl7.fhir.instance.model.api.IBaseResource import org.hl7.fhir.r4.model.Consent
class FhirResourceModule : SimpleModule() { class FhirResourceModule : SimpleModule() {
init { init {
addSerializer(IBaseResource::class.java, IBaseResourceSerializer()) addSerializer(Consent::class.java, ConsentResourceSerializer())
addDeserializer(IBaseResource::class.java, IBaseResourceDeserializer()) addDeserializer(Consent::class.java, ConsentResourceDeserializer())
} }
} }

View File

@ -1,19 +0,0 @@
package dev.dnpm.etl.processor.config
import ca.uhn.fhir.context.FhirContext
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import org.hl7.fhir.instance.model.api.IBaseResource
class IBaseResourceSerializer : JsonSerializer<IBaseResource>() {
override fun serialize(
value: IBaseResource,
gen: JsonGenerator,
serializers: SerializerProvider
) {
val fhirContext = FhirContext.forR4()
val json = fhirContext.newJsonParser().encodeResourceToString(value)
gen.writeRawValue(json)
}
}

View File

@ -1,5 +1,6 @@
package dev.dnpm.etl.processor.config package dev.dnpm.etl.processor.config
import ca.uhn.fhir.context.FhirContext
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
@ -9,11 +10,18 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
@Configuration @Configuration
class JacksonConfig { class JacksonConfig {
companion object {
var fhirContext: FhirContext = FhirContext.forR4()
@JvmStatic
fun fhirContext(): FhirContext {
return fhirContext
}
}
@Bean @Bean
fun objectMapper(): ObjectMapper = fun objectMapper(): ObjectMapper = ObjectMapper().registerModule(FhirResourceModule())
ObjectMapper() .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).registerModule(
.registerModule(FhirResourceModule()) JavaTimeModule()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).registerModule( )
JavaTimeModule()
);
} }

View File

@ -177,7 +177,7 @@ class GPasConnectionCheckService(
fun check() { fun check() {
result = try { result = try {
val uri = UriComponentsBuilder.fromUriString( val uri = UriComponentsBuilder.fromUriString(
gPasConfigProperties.uri?.replace("/\$\$pseudonymizeAllowCreate", "/metadata").toString() gPasConfigProperties.uri?.replace("/\$pseudonymizeAllowCreate", "/metadata").toString()
).build().toUri() ).build().toUri()
val headers = HttpHeaders() val headers = HttpHeaders()

View File

@ -42,7 +42,6 @@ import dev.pcvolkmer.mv64e.mtb.MvhMetadata
import dev.pcvolkmer.mv64e.mtb.Provision import dev.pcvolkmer.mv64e.mtb.Provision
import org.apache.commons.codec.binary.Base32 import org.apache.commons.codec.binary.Base32
import org.apache.commons.codec.digest.DigestUtils import org.apache.commons.codec.digest.DigestUtils
import org.hl7.fhir.instance.model.api.IBaseResource
import org.hl7.fhir.r4.model.Bundle import org.hl7.fhir.r4.model.Bundle
import org.hl7.fhir.r4.model.Consent import org.hl7.fhir.r4.model.Consent
import org.slf4j.Logger import org.slf4j.Logger
@ -53,7 +52,6 @@ import java.io.IOException
import java.lang.RuntimeException import java.lang.RuntimeException
import java.time.Clock import java.time.Clock
import java.time.Instant import java.time.Instant
import java.time.ZoneId
import java.util.* import java.util.*
@Service @Service
@ -107,7 +105,7 @@ class RequestProcessor(
initMetaDataAtMtbFile(mtbFile) initMetaDataAtMtbFile(mtbFile)
val personIdentifierValue = extractPatientIdentifier(mtbFile) val personIdentifierValue = extractPatientIdentifier(mtbFile)
val requestDate = Date.from(Instant.now(Clock.system(ZoneId.of("ECT")))) val requestDate = Date.from(Instant.now(Clock.systemUTC()))
// 1. Broad consent Entry exists? // 1. Broad consent Entry exists?
// 1.1. -> yes and research consent is given -> send mtb file // 1.1. -> yes and research consent is given -> send mtb file
@ -192,7 +190,7 @@ class RequestProcessor(
mtbFile: Mtb, broadConsent: Bundle mtbFile: Mtb, broadConsent: Bundle
) { ) {
broadConsent.entry.forEach { it -> broadConsent.entry.forEach { it ->
mtbFile.metadata.researchConsents.add(mapOf(it.resource.id to it as IBaseResource)) mtbFile.metadata.researchConsents.add(mapOf(it.resource.id to it.resource as Consent))
} }
} }