Issue 3530 terserutil contained failure (#3532)

* License headers

* begin with failing test

* fixed

* changelog

* add jira tag

* review feedback
This commit is contained in:
Ken Stevens 2022-04-12 20:16:23 -04:00 committed by GitHub
parent f361aa5998
commit 9d2a317446
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 278 additions and 79 deletions

View File

@ -180,7 +180,7 @@ public final class TerserUtil {
continue;
}
IBase newFieldValue = newElement(childDefinition, theFromFieldValue, null);
IBase newFieldValue = newElement(terser, childDefinition, theFromFieldValue, null);
terser.cloneInto(theFromFieldValue, newFieldValue, true);
try {
@ -316,7 +316,8 @@ public final class TerserUtil {
/**
* Clears the specified field on the resource provided
* @param theFhirContext Context holding resource definition
*
* @param theFhirContext Context holding resource definition
* @param theResource
* @param theFieldName
*/
@ -529,19 +530,28 @@ public final class TerserUtil {
* Creates a new element taking into consideration elements with choice that are not directly retrievable by element
* name
*
*
* @param theFhirTerser
* @param theChildDefinition Child to create a new instance for
* @param theFromFieldValue The base parent field
* @param theConstructorParam Optional constructor param
* @return Returns the new element with the given value if configured
*/
private static IBase newElement(BaseRuntimeChildDefinition theChildDefinition, IBase theFromFieldValue, Object theConstructorParam) {
private static IBase newElement(FhirTerser theFhirTerser, BaseRuntimeChildDefinition theChildDefinition, IBase theFromFieldValue, Object theConstructorParam) {
BaseRuntimeElementDefinition runtimeElementDefinition;
if (theChildDefinition instanceof RuntimeChildChoiceDefinition) {
runtimeElementDefinition = theChildDefinition.getChildElementDefinitionByDatatype(theFromFieldValue.getClass());
} else {
runtimeElementDefinition = theChildDefinition.getChildByName(theChildDefinition.getElementName());
}
return (theConstructorParam == null) ? runtimeElementDefinition.newInstance() : runtimeElementDefinition.newInstance(theConstructorParam);
if ("contained".equals(runtimeElementDefinition.getName())) {
IBaseResource sourceResource = (IBaseResource) theFromFieldValue;
return theFhirTerser.clone(sourceResource);
} else if (theConstructorParam == null) {
return runtimeElementDefinition.newInstance();
} else {
return runtimeElementDefinition.newInstance(theConstructorParam);
}
}
private static void mergeFields(FhirTerser theTerser, IBaseResource theTo, BaseRuntimeChildDefinition childDefinition, List<IBase> theFromFieldValues, List<IBase> theToFieldValues) {
@ -550,7 +560,7 @@ public final class TerserUtil {
continue;
}
IBase newFieldValue = newElement(childDefinition, theFromFieldValue, null);
IBase newFieldValue = newElement(theTerser, childDefinition, theFromFieldValue, null);
if (theFromFieldValue instanceof IPrimitiveType) {
try {
Method copyMethod = getMethod(theFromFieldValue, "copy");

View File

@ -0,0 +1,4 @@
type: fix
issue: 3530
jira: SMILE-4109
title: "TerserUtil.mergeAllFields() threw an exception when cloning contained resources. This has been corrected."

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.mdm.util;
/*-
* #%L
* HAPI FHIR JPA Server - Master Data Management
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.mdm.util.MessageHelper;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.batch2.impl;
/*-
* #%L
* HAPI FHIR JPA Server - Batch2 Task Processor
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.batch2.api.IJobDataSink;
import ca.uhn.fhir.model.api.IModelJson;
import org.slf4j.Logger;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.batch2.impl;
/*-
* #%L
* HAPI FHIR JPA Server - Batch2 Task Processor
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.batch2.model.JobWorkNotification;
import ca.uhn.fhir.batch2.model.JobWorkNotificationJsonMessage;
import ca.uhn.fhir.jpa.subscription.channel.api.IChannelProducer;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.batch2.impl;
/*-
* #%L
* HAPI FHIR JPA Server - Batch2 Task Processor
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.batch2.impl;
/*-
* #%L
* HAPI FHIR JPA Server - Batch2 Task Processor
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.batch2.api.JobExecutionFailedException;
import ca.uhn.fhir.batch2.api.VoidModel;
import ca.uhn.fhir.batch2.model.WorkChunkData;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.batch2.impl;
/*-
* #%L
* HAPI FHIR JPA Server - Batch2 Task Processor
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.batch2.api.IJobPersistence;
import ca.uhn.fhir.batch2.model.JobDefinitionStep;
import ca.uhn.fhir.batch2.model.JobWorkNotification;

View File

@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.binstore;
/*-
* #%L
* HAPI FHIR JPA Server
* HAPI FHIR Storage api
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
@ -20,10 +20,10 @@ package ca.uhn.fhir.jpa.binstore;
* #L%
*/
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.binary.svc.BaseBinaryStorageSvcImpl;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.binary.api.StoredDetails;
import ca.uhn.fhir.jpa.binary.svc.BaseBinaryStorageSvcImpl;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -41,7 +41,16 @@ import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Date;
public class FilesystemBinaryStorageSvcImpl extends BaseBinaryStorageSvcImpl {

View File

@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.binstore;
/*-
* #%L
* HAPI FHIR JPA Server
* HAPI FHIR Storage api
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
@ -20,9 +20,9 @@ package ca.uhn.fhir.jpa.binstore;
* #L%
*/
import ca.uhn.fhir.jpa.binary.svc.BaseBinaryStorageSvcImpl;
import ca.uhn.fhir.jpa.binary.api.IBinaryStorageSvc;
import ca.uhn.fhir.jpa.binary.api.StoredDetails;
import ca.uhn.fhir.jpa.binary.svc.BaseBinaryStorageSvcImpl;
import com.google.common.hash.HashingInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.CountingInputStream;

View File

@ -9,6 +9,7 @@ import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.HumanName;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.PrimitiveType;
import org.junit.jupiter.api.Test;
@ -17,78 +18,99 @@ import java.util.Date;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class TerserUtilTest {
private FhirContext ourFhirContext = FhirContext.forR4();
private static final String SAMPLE_PERSON = "{\n" +
" \"resourceType\": \"Patient\",\n" +
" \"extension\": [\n" +
" {\n" +
" \"url\": \"http://hl7.org/fhir/us/core/StructureDefinition/us-core-race\",\n" +
" \"valueCoding\": {\n" +
" \"system\": \"MyInternalRace\",\n" +
" \"code\": \"X\",\n" +
" \"display\": \"Eks\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"url\": \"http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity'\",\n" +
" \"valueCoding\": {\n" +
" \"system\": \"MyInternalEthnicity\",\n" +
" \"display\": \"NNN\"\n" +
" }\n" +
" }\n" +
" ],\n" +
" \"identifier\": [\n" +
" {\n" +
" \"system\": \"http://example.org/member_id\",\n" +
" \"value\": \"123123\"\n" +
" },\n" +
" {\n" +
" \"system\": \"http://example.org/medicaid_id\",\n" +
" \"value\": \"12312323123Z\"\n" +
" },\n" +
" {\n" +
" \"system\": \"http://example.org/CDNS_id\",\n" +
" \"value\": \"123123123E\"\n" +
" },\n" +
" {\n" +
" \"system\": \"http://example.org/SSN\"\n" +
" }\n" +
" ],\n" +
" \"active\": true,\n" +
" \"name\": [\n" +
" {\n" +
" \"family\": \"TestFamily\",\n" +
" \"given\": [\n" +
" \"Given\"\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"telecom\": [\n" +
" {\n" +
" \"system\": \"email\",\n" +
" \"value\": \"email@email.io\"\n" +
" },\n" +
" {\n" +
" \"system\": \"phone\",\n" +
" \"value\": \"123123231\"\n" +
" },\n" +
" {\n" +
" \"system\": \"phone\",\n" +
" \"value\": \"1231232312\"\n" +
" },\n" +
" {\n" +
" \"system\": \"phone\",\n" +
" \"value\": \"1231232314\"\n" +
" }\n" +
" ],\n" +
" \"gender\": \"male\",\n" +
" \"birthDate\": \"1900-01-01\",\n" +
" \"deceasedBoolean\": true\n" +
" }";
private static final String SAMPLE_PERSON =
"""
{
"resourceType": "Patient",
"extension": [
{
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
"valueCoding": {
"system": "MyInternalRace",
"code": "X",
"display": "Eks"
}
},
{
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity'",
"valueCoding": {
"system": "MyInternalEthnicity",
"display": "NNN"
}
}
],
"identifier": [
{
"system": "http://example.org/member_id",
"value": "123123"
},
{
"system": "http://example.org/medicaid_id",
"value": "12312323123Z"
},
{
"system": "http://example.org/CDNS_id",
"value": "123123123E"
},
{
"system": "http://example.org/SSN"
}
],
"active": true,
"name": [
{
"family": "TestFamily",
"given": [
"Given"
]
}
],
"telecom": [
{
"system": "email",
"value": "email@email.io"
},
{
"system": "phone",
"value": "123123231"
},
{
"system": "phone",
"value": "1231232312"
},
{
"system": "phone",
"value": "1231232314"
}
],
"gender": "male",
"birthDate": "1900-01-01",
"deceasedBoolean": true,
"contained": [
{
"id": "1",
"identifier": [
{
"system": "urn:hssc:srhs:contact:organizationId",
"value": "1000"
}
],
"name": "BUILDERS FIRST SOURCE",
"resourceType": "Organization"
}
]
}
""";
@Test
void testCloneEidIntoResource() {
@ -130,6 +152,20 @@ class TerserUtilTest {
assertEquals(2, p2.getExtension().size());
}
@Test
void testCloneContainedResource() {
Patient p1 = ourFhirContext.newJsonParser().parseResource(Patient.class, SAMPLE_PERSON);
Patient p2 = new Patient();
TerserUtil.mergeAllFields(ourFhirContext, p1, p2);
Organization org1 = (Organization) p1.getContained().get(0);
Organization org2 = (Organization) p2.getContained().get(0);
assertNotEquals(org1, org2);
assertEquals("BUILDERS FIRST SOURCE", org1.getName());
assertEquals("BUILDERS FIRST SOURCE", org2.getName());
}
@Test
void testCloneEidIntoResourceViaHelper() {
TerserUtilHelper p1Helper = TerserUtilHelper.newHelper(ourFhirContext, "Patient");

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.test.utilities;
/*-
* #%L
* HAPI FHIR Test Utilities
* %%
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import org.junit.jupiter.api.extension.AfterEachCallback;