
ca.uhn.fhir.parser.JsonParser Maven / Gradle / Ivy
package ca.uhn.fhir.parser;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* 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 static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.WordUtils;
import org.hl7.fhir.instance.model.api.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.primitive.*;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.parser.json.GsonStructure;
import ca.uhn.fhir.parser.json.JsonLikeArray;
import ca.uhn.fhir.parser.json.JsonLikeObject;
import ca.uhn.fhir.parser.json.JsonLikeStructure;
import ca.uhn.fhir.parser.json.JsonLikeValue;
import ca.uhn.fhir.parser.json.JsonLikeWriter;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.util.ElementUtil;
/**
* This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use
* {@link FhirContext#newJsonParser()} to get an instance.
*/
public class JsonParser extends BaseParser implements IJsonLikeParser {
private static final Set BUNDLE_TEXTNODE_CHILDREN_DSTU1;
private static final Set BUNDLE_TEXTNODE_CHILDREN_DSTU2;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParser.HeldExtension.class);
static {
HashSet hashSetDstu1 = new HashSet();
hashSetDstu1.add("title");
hashSetDstu1.add("id");
hashSetDstu1.add("updated");
hashSetDstu1.add("published");
hashSetDstu1.add("totalResults");
BUNDLE_TEXTNODE_CHILDREN_DSTU1 = Collections.unmodifiableSet(hashSetDstu1);
HashSet hashSetDstu2 = new HashSet();
hashSetDstu2.add("type");
hashSetDstu2.add("base");
hashSetDstu2.add("total");
BUNDLE_TEXTNODE_CHILDREN_DSTU2 = Collections.unmodifiableSet(hashSetDstu2);
}
private FhirContext myContext;
private boolean myPrettyPrint;
/**
* Do not use this constructor, the recommended way to obtain a new instance of the JSON parser is to invoke
* {@link FhirContext#newJsonParser()}.
*
* @param theParserErrorHandler
*/
public JsonParser(FhirContext theContext, IParserErrorHandler theParserErrorHandler) {
super(theContext, theParserErrorHandler);
myContext = theContext;
}
private boolean addToHeldComments(int valueIdx, List theCommentsToAdd, ArrayList> theListToAddTo) {
if (theCommentsToAdd.size() > 0) {
theListToAddTo.ensureCapacity(valueIdx);
while (theListToAddTo.size() <= valueIdx) {
theListToAddTo.add(null);
}
if (theListToAddTo.get(valueIdx) == null) {
theListToAddTo.set(valueIdx, new ArrayList());
}
theListToAddTo.get(valueIdx).addAll(theCommentsToAdd);
return true;
} else {
return false;
}
}
private boolean addToHeldExtensions(int valueIdx, List extends IBaseExtension, ?>> ext, ArrayList> list, boolean theIsModifier, CompositeChildElement theChildElem) {
if (ext.size() > 0) {
list.ensureCapacity(valueIdx);
while (list.size() <= valueIdx) {
list.add(null);
}
if (list.get(valueIdx) == null) {
list.set(valueIdx, new ArrayList());
}
for (IBaseExtension, ?> next : ext) {
list.get(valueIdx).add(new HeldExtension(next, theIsModifier, theChildElem));
}
return true;
} else {
return false;
}
}
private void addToHeldIds(int theValueIdx, ArrayList theListToAddTo, String theId) {
theListToAddTo.ensureCapacity(theValueIdx);
while (theListToAddTo.size() <= theValueIdx) {
theListToAddTo.add(null);
}
if (theListToAddTo.get(theValueIdx) == null) {
theListToAddTo.set(theValueIdx, theId);
}
}
private void assertObjectOfType(JsonLikeValue theResourceTypeObj, Object theValueType, String thePosition) {
// if (theResourceTypeObj == null) {
// throw new DataFormatException("Invalid JSON content detected, missing required element: '" + thePosition + "'");
// }
//
// if (theResourceTypeObj.getValueType() != theValueType) {
// throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType);
// }
}
private void beginArray(JsonLikeWriter theEventWriter, String arrayName) throws IOException {
theEventWriter.beginArray(arrayName);
}
private void beginObject(JsonLikeWriter theEventWriter, String arrayName) throws IOException {
theEventWriter.beginObject(arrayName);
}
private JsonLikeWriter createJsonWriter(Writer theWriter) {
JsonLikeStructure jsonStructure = new GsonStructure();
JsonLikeWriter retVal = jsonStructure.getJsonLikeWriter(theWriter);
return retVal;
}
@Override
public void doEncodeBundleToWriter(Bundle theBundle, Writer theWriter) throws IOException {
JsonLikeWriter eventWriter = createJsonWriter(theWriter);
doEncodeBundleToJsonLikeWriter(theBundle, eventWriter);
}
public void doEncodeBundleToJsonLikeWriter(Bundle theBundle, JsonLikeWriter theEventWriter) throws IOException {
if (myPrettyPrint) {
theEventWriter.setPrettyPrint(myPrettyPrint);
}
theEventWriter.init();
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
encodeBundleToWriterInDstu2Format(theBundle, theEventWriter);
} else {
encodeBundleToWriterInDstu1Format(theBundle, theEventWriter);
}
theEventWriter.flush();
}
@Override
protected void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException {
JsonLikeWriter eventWriter = createJsonWriter(theWriter);
doEncodeResourceToJsonLikeWriter(theResource, eventWriter);
}
public void doEncodeResourceToJsonLikeWriter(IBaseResource theResource, JsonLikeWriter theEventWriter) throws IOException {
if (myPrettyPrint) {
theEventWriter.setPrettyPrint(myPrettyPrint);
}
theEventWriter.init();
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
encodeResourceToJsonStreamWriter(resDef, theResource, theEventWriter, null, false, false);
theEventWriter.flush();
}
@Override
public T doParseResource(Class theResourceType, Reader theReader) {
JsonLikeStructure jsonStructure = new GsonStructure();
jsonStructure.load(theReader);
T retVal = doParseResource(theResourceType, jsonStructure);
return retVal;
}
public T doParseResource(Class theResourceType, JsonLikeStructure theJsonStructure) {
JsonLikeObject object = theJsonStructure.getRootObject();
JsonLikeValue resourceTypeObj = object.get("resourceType");
if (resourceTypeObj == null || !resourceTypeObj.isString() || isBlank(resourceTypeObj.getAsString())) {
throw new DataFormatException("Invalid JSON content detected, missing required element: 'resourceType'");
}
String resourceType = resourceTypeObj.getAsString();
ParserState extends IBaseResource> state = ParserState.getPreResourceInstance(this, theResourceType, myContext, true, getErrorHandler());
state.enteringNewElement(null, resourceType);
parseChildren(object, state);
state.endingElement();
state.endingElement();
@SuppressWarnings("unchecked")
T retVal = (T) state.getObject();
return retVal;
}
@Override
public void encodeBundleToJsonLikeWriter(Bundle theBundle, JsonLikeWriter theJsonLikeWriter) throws IOException, DataFormatException {
Validate.notNull(theBundle, "theBundle must not be null");
Validate.notNull(theJsonLikeWriter, "theJsonLikeWriter must not be null");
doEncodeBundleToJsonLikeWriter(theBundle, theJsonLikeWriter);
}
private void encodeBundleToWriterInDstu1Format(Bundle theBundle, JsonLikeWriter theEventWriter) throws IOException {
theEventWriter.beginObject();
write(theEventWriter, "resourceType", "Bundle");
writeTagWithTextNode(theEventWriter, "title", theBundle.getTitle());
writeTagWithTextNode(theEventWriter, "id", theBundle.getBundleId());
writeOptionalTagWithTextNode(theEventWriter, "updated", theBundle.getUpdated());
boolean linkStarted = false;
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "self", theBundle.getLinkSelf(), linkStarted);
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "first", theBundle.getLinkFirst(), linkStarted);
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "previous", theBundle.getLinkPrevious(), linkStarted);
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "next", theBundle.getLinkNext(), linkStarted);
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "last", theBundle.getLinkLast(), linkStarted);
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "fhir-base", theBundle.getLinkBase(), linkStarted);
if (linkStarted) {
theEventWriter.endArray();
}
writeCategories(theEventWriter, theBundle.getCategories());
writeOptionalTagWithTextNode(theEventWriter, "totalResults", theBundle.getTotalResults());
writeAuthor(theBundle, theEventWriter);
beginArray(theEventWriter, "entry");
for (BundleEntry nextEntry : theBundle.getEntries()) {
theEventWriter.beginObject();
boolean deleted = nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false;
if (deleted) {
writeTagWithTextNode(theEventWriter, "deleted", nextEntry.getDeletedAt());
}
writeTagWithTextNode(theEventWriter, "title", nextEntry.getTitle());
writeTagWithTextNode(theEventWriter, "id", nextEntry.getId());
linkStarted = false;
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "self", nextEntry.getLinkSelf(), linkStarted);
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "alternate", nextEntry.getLinkAlternate(), linkStarted);
linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "search", nextEntry.getLinkSearch(), linkStarted);
if (linkStarted) {
theEventWriter.endArray();
}
writeOptionalTagWithTextNode(theEventWriter, "updated", nextEntry.getUpdated());
writeOptionalTagWithTextNode(theEventWriter, "published", nextEntry.getPublished());
writeCategories(theEventWriter, nextEntry.getCategories());
writeAuthor(nextEntry, theEventWriter);
IResource resource = nextEntry.getResource();
if (resource != null && !resource.isEmpty() && !deleted) {
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(resource);
encodeResourceToJsonStreamWriter(resDef, resource, theEventWriter, "content", false, true);
}
if (nextEntry.getSummary().isEmpty() == false) {
write(theEventWriter, "summary", nextEntry.getSummary().getValueAsString());
}
theEventWriter.endObject(); // entry object
}
theEventWriter.endArray(); // entry array
theEventWriter.endObject(); // resource object
}
private void encodeBundleToWriterInDstu2Format(Bundle theBundle, JsonLikeWriter theEventWriter) throws IOException {
theEventWriter.beginObject();
write(theEventWriter, "resourceType", "Bundle");
writeOptionalTagWithTextNode(theEventWriter, "id", theBundle.getId().getIdPart());
if (!ElementUtil.isEmpty(theBundle.getId().getVersionIdPart(), theBundle.getUpdated())) {
beginObject(theEventWriter, "meta");
writeOptionalTagWithTextNode(theEventWriter, "versionId", theBundle.getId().getVersionIdPart());
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", theBundle.getUpdated());
theEventWriter.endObject();
}
writeOptionalTagWithTextNode(theEventWriter, "type", theBundle.getType());
writeOptionalTagWithNumberNode(theEventWriter, "total", theBundle.getTotalResults());
boolean linkStarted = false;
linkStarted = writeAtomLinkInDstu2Format(theEventWriter, "next", theBundle.getLinkNext(), linkStarted);
linkStarted = writeAtomLinkInDstu2Format(theEventWriter, "self", theBundle.getLinkSelf(), linkStarted);
linkStarted = writeAtomLinkInDstu2Format(theEventWriter, "first", theBundle.getLinkFirst(), linkStarted);
linkStarted = writeAtomLinkInDstu2Format(theEventWriter, "previous", theBundle.getLinkPrevious(), linkStarted);
linkStarted = writeAtomLinkInDstu2Format(theEventWriter, "last", theBundle.getLinkLast(), linkStarted);
if (linkStarted) {
theEventWriter.endArray();
}
beginArray(theEventWriter, "entry");
for (BundleEntry nextEntry : theBundle.getEntries()) {
theEventWriter.beginObject();
if (nextEntry.getResource() != null && nextEntry.getResource().getId().getBaseUrl() != null) {
writeOptionalTagWithTextNode(theEventWriter, "fullUrl", nextEntry.getResource().getId().getValue());
}
boolean deleted = nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false;
IResource resource = nextEntry.getResource();
if (resource != null && !resource.isEmpty() && !deleted) {
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(resource);
encodeResourceToJsonStreamWriter(resDef, resource, theEventWriter, "resource", false, true);
}
if (nextEntry.getSearchMode().isEmpty() == false || nextEntry.getScore().isEmpty() == false) {
beginObject(theEventWriter, "search");
writeOptionalTagWithTextNode(theEventWriter, "mode", nextEntry.getSearchMode().getValueAsString());
writeOptionalTagWithDecimalNode(theEventWriter, "score", nextEntry.getScore());
theEventWriter.endObject();
// IResource nextResource = nextEntry.getResource();
}
if (nextEntry.getTransactionMethod().isEmpty() == false || nextEntry.getLinkSearch().isEmpty() == false) {
beginObject(theEventWriter, "request");
writeOptionalTagWithTextNode(theEventWriter, "method", nextEntry.getTransactionMethod().getValue());
writeOptionalTagWithTextNode(theEventWriter, "url", nextEntry.getLinkSearch().getValue());
theEventWriter.endObject();
}
if (deleted) {
beginObject(theEventWriter, "deleted");
if (nextEntry.getResource() != null) {
write(theEventWriter, "type", myContext.getResourceDefinition(nextEntry.getResource()).getName());
writeOptionalTagWithTextNode(theEventWriter, "resourceId", nextEntry.getResource().getId().getIdPart());
writeOptionalTagWithTextNode(theEventWriter, "versionId", nextEntry.getResource().getId().getVersionIdPart());
}
writeTagWithTextNode(theEventWriter, "instant", nextEntry.getDeletedAt());
theEventWriter.endObject();
}
// linkStarted = false;
// linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "self", nextEntry.getLinkSelf(), linkStarted);
// linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "alternate", nextEntry.getLinkAlternate(),
// linkStarted);
// linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "search", nextEntry.getLinkSearch(),
// linkStarted);
// if (linkStarted) {
// theEventWriter.writeEnd();
// }
//
// writeOptionalTagWithTextNode(theEventWriter, "updated", nextEntry.getUpdated());
// writeOptionalTagWithTextNode(theEventWriter, "published", nextEntry.getPublished());
//
// writeCategories(theEventWriter, nextEntry.getCategories());
//
// writeAuthor(nextEntry, theEventWriter);
if (nextEntry.getSummary().isEmpty() == false) {
write(theEventWriter, "summary", nextEntry.getSummary().getValueAsString());
}
theEventWriter.endObject(); // entry object
}
theEventWriter.endArray(); // entry array
theEventWriter.endObject(); // resource object
}
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBase theNextValue, BaseRuntimeElementDefinition> theChildDef, String theChildName, boolean theContainedResource, CompositeChildElement theChildElem,
boolean theForceEmpty) throws IOException {
switch (theChildDef.getChildType()) {
case ID_DATATYPE: {
IIdType value = (IIdType) theNextValue;
String encodedValue = "id".equals(theChildName) ? value.getIdPart() : value.getValue();
if (isBlank(encodedValue)) {
break;
}
if (theChildName != null) {
write(theEventWriter, theChildName, encodedValue);
} else {
theEventWriter.write(encodedValue);
}
break;
}
case PRIMITIVE_DATATYPE: {
final IPrimitiveType> value = (IPrimitiveType>) theNextValue;
if (isBlank(value.getValueAsString())) {
if (theForceEmpty) {
theEventWriter.writeNull();
}
break;
}
if (value instanceof IBaseIntegerDatatype) {
if (theChildName != null) {
write(theEventWriter, theChildName, ((IBaseIntegerDatatype) value).getValue());
} else {
theEventWriter.write(((IBaseIntegerDatatype) value).getValue());
}
} else if (value instanceof IBaseDecimalDatatype) {
BigDecimal decimalValue = ((IBaseDecimalDatatype) value).getValue();
decimalValue = new BigDecimal(decimalValue.toString()) {
private static final long serialVersionUID = 1L;
@Override
public String toString() {
return value.getValueAsString();
}
};
if (theChildName != null) {
write(theEventWriter, theChildName, decimalValue);
} else {
theEventWriter.write(decimalValue);
}
} else if (value instanceof IBaseBooleanDatatype) {
if (theChildName != null) {
write(theEventWriter, theChildName, ((IBaseBooleanDatatype) value).getValue());
} else {
Boolean booleanValue = ((IBaseBooleanDatatype) value).getValue();
if (booleanValue != null) {
theEventWriter.write(booleanValue.booleanValue());
}
}
} else {
String valueStr = value.getValueAsString();
if (theChildName != null) {
write(theEventWriter, theChildName, valueStr);
} else {
theEventWriter.write(valueStr);
}
}
break;
}
case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: {
if (theChildName != null) {
theEventWriter.beginObject(theChildName);
} else {
theEventWriter.beginObject();
}
encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theChildElem);
theEventWriter.endObject();
break;
}
case CONTAINED_RESOURCE_LIST:
case CONTAINED_RESOURCES: {
/*
* Disabled per #103 ContainedDt value = (ContainedDt) theNextValue; for (IResource next :
* value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) { continue; }
* encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null, true,
* fixContainedResourceId(next.getId().getValue())); }
*/
List containedResources = getContainedResources().getContainedResources();
if (containedResources.size() > 0) {
beginArray(theEventWriter, theChildName);
for (IBaseResource next : containedResources) {
IIdType resourceId = getContainedResources().getResourceId(next);
encodeResourceToJsonStreamWriter(theResDef, next, theEventWriter, null, true, fixContainedResourceId(resourceId.getValue()));
}
theEventWriter.endArray();
}
break;
}
case PRIMITIVE_XHTML_HL7ORG:
case PRIMITIVE_XHTML: {
if (!isSuppressNarratives()) {
IPrimitiveType> dt = (IPrimitiveType>) theNextValue;
if (theChildName != null) {
write(theEventWriter, theChildName, dt.getValueAsString());
} else {
theEventWriter.write(dt.getValueAsString());
}
} else {
if (theChildName != null) {
// do nothing
} else {
theEventWriter.writeNull();
}
}
break;
}
case RESOURCE:
IBaseResource resource = (IBaseResource) theNextValue;
RuntimeResourceDefinition def = myContext.getResourceDefinition(resource);
encodeResourceToJsonStreamWriter(def, resource, theEventWriter, theChildName, false, true);
break;
case UNDECL_EXT:
default:
throw new IllegalStateException("Should not have this state here: " + theChildDef.getChildType().name());
}
}
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, JsonLikeWriter theEventWriter, boolean theContainedResource, CompositeChildElement theParent) throws IOException {
{
String elementId = getCompositeElementId(theElement);
if (isNotBlank(elementId)) {
write(theEventWriter, "id", elementId);
}
}
boolean haveWrittenExtensions = false;
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theParent)) {
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
if (nextChildElem.getDef().getElementName().equals("extension") || nextChildElem.getDef().getElementName().equals("modifierExtension") || nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
if (!haveWrittenExtensions) {
extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource, nextChildElem);
haveWrittenExtensions = true;
}
continue;
}
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
INarrativeGenerator gen = myContext.getNarrativeGenerator();
if (gen != null) {
INarrative narr;
if (theResource instanceof IResource) {
narr = ((IResource) theResource).getText();
} else if (theResource instanceof IDomainResource) {
narr = ((IDomainResource) theResource).getText();
} else {
narr = null;
}
if (narr != null && narr.isEmpty()) {
gen.generateNarrative(myContext, theResource, narr);
if (narr != null && !narr.isEmpty()) {
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
BaseRuntimeElementDefinition> type = child.getChildByName(childName);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theContainedResource, nextChildElem, false);
continue;
}
}
}
} else if (nextChild instanceof RuntimeChildContainedResources) {
String childName = nextChild.getValidChildNames().iterator().next();
BaseRuntimeElementDefinition> child = nextChild.getChildByName(childName);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theContainedResource, nextChildElem, false);
continue;
}
List extends IBase> values = nextChild.getAccessor().getValues(theElement);
values = super.preProcessValues(nextChild, theResource, values, nextChildElem);
if (values == null || values.isEmpty()) {
continue;
}
String currentChildName = null;
boolean inArray = false;
ArrayList> extensions = new ArrayList>(0);
ArrayList> modifierExtensions = new ArrayList>(0);
ArrayList> comments = new ArrayList>(0);
ArrayList ids = new ArrayList(0);
int valueIdx = 0;
for (IBase nextValue : values) {
if (nextValue == null || nextValue.isEmpty()) {
if (nextValue instanceof BaseContainedDt) {
if (theContainedResource || getContainedResources().isEmpty()) {
continue;
}
} else {
continue;
}
}
BaseParser.ChildNameAndDef childNameAndDef = super.getChildNameAndDef(nextChild, nextValue);
if (childNameAndDef == null) {
continue;
}
String childName = childNameAndDef.getChildName();
BaseRuntimeElementDefinition> childDef = childNameAndDef.getChildDef();
boolean primitive = childDef.getChildType() == ChildTypeEnum.PRIMITIVE_DATATYPE;
if ((childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES || childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCE_LIST) && theContainedResource) {
continue;
}
boolean force = false;
if (primitive) {
if (nextValue instanceof ISupportsUndeclaredExtensions) {
List ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredExtensions();
force |= addToHeldExtensions(valueIdx, ext, extensions, false, nextChildElem);
ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredModifierExtensions();
force |= addToHeldExtensions(valueIdx, ext, modifierExtensions, true, nextChildElem);
} else {
if (nextValue instanceof IBaseHasExtensions) {
IBaseHasExtensions element = (IBaseHasExtensions) nextValue;
List extends IBaseExtension, ?>> ext = element.getExtension();
force |= addToHeldExtensions(valueIdx, ext, extensions, false, nextChildElem);
}
if (nextValue instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
List extends IBaseExtension, ?>> ext = element.getModifierExtension();
force |= addToHeldExtensions(valueIdx, ext, extensions, true, nextChildElem);
}
}
if (nextValue.hasFormatComment()) {
force |= addToHeldComments(valueIdx, nextValue.getFormatCommentsPre(), comments);
force |= addToHeldComments(valueIdx, nextValue.getFormatCommentsPost(), comments);
}
String elementId = getCompositeElementId(nextValue);
if (isNotBlank(elementId)) {
force = true;
addToHeldIds(valueIdx, ids, elementId);
}
}
if (currentChildName == null || !currentChildName.equals(childName)) {
if (inArray) {
theEventWriter.endArray();
}
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) {
beginArray(theEventWriter, childName);
inArray = true;
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem, force);
} else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) {
// suppress narratives from contained resources
} else {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource, nextChildElem, false);
}
currentChildName = childName;
} else {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem, force);
}
valueIdx++;
}
if (inArray) {
theEventWriter.endArray();
}
if (!extensions.isEmpty() || !modifierExtensions.isEmpty() || !comments.isEmpty()) {
if (inArray) {
// If this is a repeatable field, the extensions go in an array too
beginArray(theEventWriter, '_' + currentChildName);
} else {
beginObject(theEventWriter, '_' + currentChildName);
}
for (int i = 0; i < valueIdx; i++) {
boolean haveContent = false;
List heldExts = Collections.emptyList();
List heldModExts = Collections.emptyList();
if (extensions.size() > i && extensions.get(i) != null && extensions.get(i).isEmpty() == false) {
haveContent = true;
heldExts = extensions.get(i);
}
if (modifierExtensions.size() > i && modifierExtensions.get(i) != null && modifierExtensions.get(i).isEmpty() == false) {
haveContent = true;
heldModExts = modifierExtensions.get(i);
}
ArrayList nextComments;
if (comments.size() > i) {
nextComments = comments.get(i);
} else {
nextComments = null;
}
if (nextComments != null && nextComments.isEmpty() == false) {
haveContent = true;
}
String elementId = null;
if (ids.size() > i) {
elementId = ids.get(i);
haveContent |= isNotBlank(elementId);
}
if (!haveContent) {
theEventWriter.writeNull();
} else {
if (inArray) {
theEventWriter.beginObject();
}
if (isNotBlank(elementId)) {
write(theEventWriter, "id", elementId);
}
if (nextComments != null && !nextComments.isEmpty()) {
beginArray(theEventWriter, "fhir_comments");
for (String next : nextComments) {
theEventWriter.write(next);
}
theEventWriter.endArray();
}
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, heldExts, heldModExts);
if (inArray) {
theEventWriter.endObject();
}
}
}
if (inArray) {
theEventWriter.endArray();
} else {
theEventWriter.endObject();
}
}
}
}
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonLikeWriter theEventWriter, boolean theContainedResource, CompositeChildElement theParent) throws IOException, DataFormatException {
writeCommentsPreAndPost(theNextValue, theEventWriter);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theParent);
}
@Override
public void encodeResourceToJsonLikeWriter(IBaseResource theResource, JsonLikeWriter theJsonLikeWriter) throws IOException, DataFormatException {
Validate.notNull(theResource, "theResource can not be null");
Validate.notNull(theJsonLikeWriter, "theJsonLikeWriter can not be null");
if (theResource.getStructureFhirVersionEnum() != myContext.getVersion().getVersion()) {
throw new IllegalArgumentException("This parser is for FHIR version " + myContext.getVersion().getVersion() + " - Can not encode a structure for version " + theResource.getStructureFhirVersionEnum());
}
doEncodeResourceToJsonLikeWriter(theResource, theJsonLikeWriter);
}
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, String theObjectNameOrNull, boolean theContainedResource, boolean theSubResource) throws IOException {
IIdType resourceId = null;
// if (theResource instanceof IResource) {
// IResource res = (IResource) theResource;
// if (StringUtils.isNotBlank(res.getId().getIdPart())) {
// if (theContainedResource) {
// resourceId = res.getId().getIdPart();
// } else if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
// resourceId = res.getId().getIdPart();
// }
// }
// } else if (theResource instanceof IAnyResource) {
// IAnyResource res = (IAnyResource) theResource;
// if (/* theContainedResource && */StringUtils.isNotBlank(res.getIdElement().getIdPart())) {
// resourceId = res.getIdElement().getIdPart();
// }
// }
if (StringUtils.isNotBlank(theResource.getIdElement().getIdPart())) {
resourceId = theResource.getIdElement();
if (theResource.getIdElement().getValue().startsWith("urn:")) {
resourceId = null;
}
if (myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
resourceId = null;
}
}
if (!theContainedResource) {
if (super.shouldEncodeResourceId(theResource) == false) {
resourceId = null;
} else if (!theSubResource && getEncodeForceResourceId() != null) {
resourceId = getEncodeForceResourceId();
}
}
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theContainedResource, resourceId);
}
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, String theObjectNameOrNull, boolean theContainedResource, IIdType theResourceId) throws IOException {
if (!theContainedResource) {
super.containResourcesForEncoding(theResource);
}
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
if (theObjectNameOrNull == null) {
theEventWriter.beginObject();
} else {
beginObject(theEventWriter, theObjectNameOrNull);
}
write(theEventWriter, "resourceType", resDef.getName());
if (theResourceId != null && theResourceId.hasIdPart()) {
write(theEventWriter, "id", theResourceId.getIdPart());
if (theResourceId.hasFormatComment()) {
beginObject(theEventWriter, "_id");
writeCommentsPreAndPost(theResourceId, theEventWriter);
theEventWriter.endObject();
}
}
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1) && theResource instanceof IResource) {
IResource resource = (IResource) theResource;
// Object securityLabelRawObj =
List securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
List extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
profiles = super.getProfileTagsForEncoding(resource, profiles);
TagList tags = getMetaTagsForEncoding(resource);
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
IdDt resourceId = resource.getId();
String versionIdPart = resourceId.getVersionIdPart();
if (isBlank(versionIdPart)) {
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
}
if (super.shouldEncodeResourceMeta(resource) && ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) {
beginObject(theEventWriter, "meta");
writeOptionalTagWithTextNode(theEventWriter, "versionId", versionIdPart);
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", updated);
if (profiles != null && profiles.isEmpty() == false) {
beginArray(theEventWriter, "profile");
for (IIdType profile : profiles) {
if (profile != null && isNotBlank(profile.getValue())) {
theEventWriter.write(profile.getValue());
}
}
theEventWriter.endArray();
}
if (securityLabels.isEmpty() == false) {
beginArray(theEventWriter, "security");
for (BaseCodingDt securityLabel : securityLabels) {
theEventWriter.beginObject();
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, theContainedResource, null);
theEventWriter.endObject();
}
theEventWriter.endArray();
}
if (tags != null && tags.isEmpty() == false) {
beginArray(theEventWriter, "tag");
for (Tag tag : tags) {
if (tag.isEmpty()) {
continue;
}
theEventWriter.beginObject();
writeOptionalTagWithTextNode(theEventWriter, "system", tag.getScheme());
writeOptionalTagWithTextNode(theEventWriter, "code", tag.getTerm());
writeOptionalTagWithTextNode(theEventWriter, "display", tag.getLabel());
theEventWriter.endObject();
}
theEventWriter.endArray();
}
theEventWriter.endObject(); // end meta
}
}
if (theResource instanceof IBaseBinary) {
IBaseBinary bin = (IBaseBinary) theResource;
String contentType = bin.getContentType();
if (isNotBlank(contentType)) {
write(theEventWriter, "contentType", contentType);
}
String contentAsBase64 = bin.getContentAsBase64();
if (isNotBlank(contentAsBase64)) {
write(theEventWriter, "content", contentAsBase64);
}
} else {
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, theContainedResource, new CompositeChildElement(resDef));
}
theEventWriter.endObject();
}
@Override
public void encodeTagListToWriter(TagList theTagList, Writer theWriter) throws IOException {
JsonLikeWriter theEventWriter = createJsonWriter(theWriter);
encodeTagListToJsonLikeWriter(theTagList, theEventWriter);
}
@Override
public void encodeTagListToJsonLikeWriter(TagList theTagList, JsonLikeWriter theEventWriter) throws IOException {
if (myPrettyPrint) {
theEventWriter.setPrettyPrint(myPrettyPrint);
}
theEventWriter.init();
theEventWriter.beginObject();
write(theEventWriter, "resourceType", TagList.ELEMENT_NAME);
beginArray(theEventWriter, TagList.ATTR_CATEGORY);
for (Tag next : theTagList) {
theEventWriter.beginObject();
if (isNotBlank(next.getTerm())) {
write(theEventWriter, Tag.ATTR_TERM, next.getTerm());
}
if (isNotBlank(next.getLabel())) {
write(theEventWriter, Tag.ATTR_LABEL, next.getLabel());
}
if (isNotBlank(next.getScheme())) {
write(theEventWriter, Tag.ATTR_SCHEME, next.getScheme());
}
theEventWriter.endObject();
}
theEventWriter.endArray();
theEventWriter.endObject();
theEventWriter.flush();
}
/**
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object
* called _name): resource extensions, and extension extensions
* @param theChildElem
*/
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonLikeWriter theEventWriter, BaseRuntimeElementDefinition> theElementDef, RuntimeResourceDefinition theResDef, IBaseResource theResource, CompositeChildElement theChildElem) throws IOException {
List extensions = new ArrayList(0);
List modifierExtensions = new ArrayList(0);
// Undeclared extensions
extractUndeclaredExtensions(theElement, extensions, modifierExtensions, theChildElem);
// Declared extensions
if (theElementDef != null) {
extractDeclaredExtensions(theElement, theElementDef, extensions, modifierExtensions, theChildElem);
}
// Write the extensions
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
}
private void extractDeclaredExtensions(IBase theResource, BaseRuntimeElementDefinition> resDef, List extensions, List modifierExtensions, CompositeChildElement theChildElem) {
for (RuntimeChildDeclaredExtensionDefinition nextDef : resDef.getExtensionsNonModifier()) {
for (IBase nextValue : nextDef.getAccessor().getValues(theResource)) {
if (nextValue != null) {
if (nextValue == null || nextValue.isEmpty()) {
continue;
}
extensions.add(new HeldExtension(nextDef, nextValue, theChildElem));
}
}
}
for (RuntimeChildDeclaredExtensionDefinition nextDef : resDef.getExtensionsModifier()) {
for (IBase nextValue : nextDef.getAccessor().getValues(theResource)) {
if (nextValue != null) {
if (nextValue == null || nextValue.isEmpty()) {
continue;
}
modifierExtensions.add(new HeldExtension(nextDef, nextValue, theChildElem));
}
}
}
}
private void extractUndeclaredExtensions(IBase theElement, List extensions, List modifierExtensions, CompositeChildElement theChildElem) {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions element = (ISupportsUndeclaredExtensions) theElement;
List ext = element.getUndeclaredExtensions();
for (ExtensionDt next : ext) {
if (next == null || next.isEmpty()) {
continue;
}
extensions.add(new HeldExtension(next, false, theChildElem));
}
ext = element.getUndeclaredModifierExtensions();
for (ExtensionDt next : ext) {
if (next == null || next.isEmpty()) {
continue;
}
modifierExtensions.add(new HeldExtension(next, true, theChildElem));
}
} else {
if (theElement instanceof IBaseHasExtensions) {
IBaseHasExtensions element = (IBaseHasExtensions) theElement;
List extends IBaseExtension, ?>> ext = element.getExtension();
for (IBaseExtension, ?> next : ext) {
if (next == null || (ElementUtil.isEmpty(next.getValue()) && next.getExtension().isEmpty())) {
continue;
}
extensions.add(new HeldExtension(next, false, theChildElem));
}
}
if (theElement instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) theElement;
List extends IBaseExtension, ?>> ext = element.getModifierExtension();
for (IBaseExtension, ?> next : ext) {
if (next == null || next.isEmpty()) {
continue;
}
modifierExtensions.add(new HeldExtension(next, true, theChildElem));
}
}
}
}
@Override
public EncodingEnum getEncoding() {
return EncodingEnum.JSON;
}
private JsonLikeArray grabJsonArray(JsonLikeObject theObject, String nextName, String thePosition) {
JsonLikeValue object = theObject.get(nextName);
if (object == null || object.isNull()) {
return null;
}
if (!object.isArray()) {
throw new DataFormatException("Syntax error parsing JSON FHIR structure: Expected ARRAY at element '" + thePosition + "', found '" + object.getJsonType() + "'");
}
return object.getAsArray();
}
// private JsonObject parse(Reader theReader) {
//
// PushbackReader pbr = new PushbackReader(theReader);
// JsonObject object;
// try {
// while(true) {
// int nextInt;
// nextInt = pbr.read();
// if (nextInt == -1) {
// throw new DataFormatException("Did not find any content to parse");
// }
// if (nextInt == '{') {
// pbr.unread('{');
// break;
// }
// if (Character.isWhitespace(nextInt)) {
// continue;
// }
// throw new DataFormatException("Content does not appear to be FHIR JSON, first non-whitespace character was: '" + (char)nextInt + "' (must be '{')");
// }
//
// Gson gson = newGson();
//
// object = gson.fromJson(pbr, JsonObject.class);
// } catch (Exception e) {
// throw new DataFormatException("Failed to parse JSON content, error was: " + e.getMessage(), e);
// }
//
// return object;
// }
private void parseAlternates(JsonLikeValue theAlternateVal, ParserState> theState, String theElementName) {
if (theAlternateVal == null || theAlternateVal.isNull()) {
return;
}
if (theAlternateVal.isArray()) {
JsonLikeArray array = theAlternateVal.getAsArray();
if (array.size() > 1) {
throw new DataFormatException("Unexpected array of length " + array.size() + " (expected 0 or 1) for element: " + theElementName);
}
if (array.size() == 0) {
return;
}
parseAlternates(array.get(0), theState, theElementName);
return;
}
JsonLikeObject alternate = theAlternateVal.getAsObject();
for (String nextKey : alternate.keySet()) {
JsonLikeValue nextVal = alternate.get(nextKey);
if ("extension".equals(nextKey)) {
boolean isModifier = false;
JsonLikeArray array = nextVal.getAsArray();
parseExtension(theState, array, isModifier);
} else if ("modifierExtension".equals(nextKey)) {
boolean isModifier = true;
JsonLikeArray array = nextVal.getAsArray();
parseExtension(theState, array, isModifier);
} else if ("id".equals(nextKey)) {
if (nextVal.isString() || nextVal.isNumber()) {
theState.attributeValue("id", nextVal.getAsString());
}
} else if ("fhir_comments".equals(nextKey)) {
parseFhirComments(nextVal, theState);
}
}
}
@Override
public Bundle parseBundle(Class theResourceType, Reader theReader) {
JsonLikeStructure jsonStructure = new GsonStructure();
jsonStructure.load(theReader);
Bundle retVal = parseBundle(theResourceType, jsonStructure);
return retVal;
}
@Override
public Bundle parseBundle(JsonLikeStructure theJsonLikeStructure) throws DataFormatException {
return parseBundle(null, theJsonLikeStructure);
}
@Override
public Bundle parseBundle(Class theResourceType, JsonLikeStructure theJsonStructure) {
JsonLikeObject object = theJsonStructure.getRootObject();
JsonLikeValue resourceTypeObj = object.get("resourceType");
if (resourceTypeObj == null || !resourceTypeObj.isString()) {
throw new DataFormatException("Invalid JSON content detected, missing required element: 'resourceType'");
}
String resourceType = resourceTypeObj.getAsString();
if (!"Bundle".equals(resourceType)) {
throw new DataFormatException("Trying to parse bundle but found resourceType other than 'Bundle'. Found: '" + resourceType + "'");
}
ParserState state = ParserState.getPreAtomInstance(this, myContext, theResourceType, true, getErrorHandler());
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
state.enteringNewElement(null, "Bundle");
} else {
state.enteringNewElement(null, "feed");
}
parseBundleChildren(object, state);
state.endingElement();
state.endingElement();
Bundle retVal = state.getObject();
return retVal;
}
private void parseBundleChildren(JsonLikeObject theObject, ParserState> theState) {
for (String nextName : theObject.keySet()) {
if ("resourceType".equals(nextName)) {
continue;
} else if ("entry".equals(nextName)) {
JsonLikeArray entries = grabJsonArray(theObject, nextName, "entry");
for (int i = 0; i < entries.size(); i++) {
JsonLikeValue jsonValue = entries.get(i);
theState.enteringNewElement(null, "entry");
parseBundleChildren(jsonValue.getAsObject(), theState);
theState.endingElement();
}
continue;
} else if (myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
if ("link".equals(nextName)) {
JsonLikeArray entries = grabJsonArray(theObject, nextName, "link");
for (int i = 0; i < entries.size(); i++) {
JsonLikeValue jsonValue = entries.get(i);
theState.enteringNewElement(null, "link");
JsonLikeObject linkObj = jsonValue.getAsObject();
String rel = linkObj.getString("rel", null);
String href = linkObj.getString("href", null);
theState.attributeValue("rel", rel);
theState.attributeValue("href", href);
theState.endingElement();
}
continue;
} else if (BUNDLE_TEXTNODE_CHILDREN_DSTU1.contains(nextName)) {
theState.enteringNewElement(null, nextName);
JsonLikeValue jsonElement = theObject.get(nextName);
if (jsonElement.isScalar()) {
theState.string(jsonElement.getAsString());
}
theState.endingElement();
continue;
}
} else {
if ("link".equals(nextName)) {
JsonLikeArray entries = grabJsonArray(theObject, nextName, "link");
for (int i = 0; i < entries.size(); i++) {
JsonLikeValue jsonValue = entries.get(i);
theState.enteringNewElement(null, "link");
JsonLikeObject linkObj = jsonValue.getAsObject();
String rel = linkObj.getString("relation", null);
String href = linkObj.getString("url", null);
theState.enteringNewElement(null, "relation");
theState.attributeValue("value", rel);
theState.endingElement();
theState.enteringNewElement(null, "url");
theState.attributeValue("value", href);
theState.endingElement();
theState.endingElement();
}
continue;
} else if (BUNDLE_TEXTNODE_CHILDREN_DSTU2.contains(nextName)) {
theState.enteringNewElement(null, nextName);
// String obj = theObject.getString(nextName, null);
JsonLikeValue obj = theObject.get(nextName);
if (obj == null || obj.isNull()) {
theState.attributeValue("value", null);
} else if (obj.isScalar()) {
theState.attributeValue("value", obj.getAsString());
} else {
throw new DataFormatException("Unexpected JSON object for entry '" + nextName + "'");
}
theState.endingElement();
continue;
}
}
JsonLikeValue nextVal = theObject.get(nextName);
parseChildren(theState, nextName, nextVal, null, null);
}
}
private void parseChildren(JsonLikeObject theObject, ParserState> theState) {
Set keySet = theObject.keySet();
int allUnderscoreNames = 0;
int handledUnderscoreNames = 0;
for (String nextName : keySet) {
if ("resourceType".equals(nextName)) {
continue;
} else if ("extension".equals(nextName)) {
JsonLikeArray array = grabJsonArray(theObject, nextName, "extension");
parseExtension(theState, array, false);
continue;
} else if ("modifierExtension".equals(nextName)) {
JsonLikeArray array = grabJsonArray(theObject, nextName, "modifierExtension");
parseExtension(theState, array, true);
continue;
} else if (nextName.equals("fhir_comments")) {
parseFhirComments(theObject.get(nextName), theState);
continue;
} else if (nextName.charAt(0) == '_') {
allUnderscoreNames++;
continue;
}
JsonLikeValue nextVal = theObject.get(nextName);
String alternateName = '_' + nextName;
JsonLikeValue alternateVal = theObject.get(alternateName);
if (alternateVal != null) {
handledUnderscoreNames++;
}
parseChildren(theState, nextName, nextVal, alternateVal, alternateName);
}
// if (elementId != null) {
// IBase object = (IBase) theState.getObject();
// if (object instanceof IIdentifiableElement) {
// ((IIdentifiableElement) object).setElementSpecificId(elementId);
// } else if (object instanceof IBaseResource) {
// ((IBaseResource) object).getIdElement().setValue(elementId);
// }
// }
/*
* This happens if an element has an extension but no actual value. I.e.
* if a resource has a "_status" element but no corresponding "status"
* element. This could be used to handle a null value with an extension
* for example.
*/
if (allUnderscoreNames > handledUnderscoreNames) {
for (String alternateName : keySet) {
if (alternateName.startsWith("_") && alternateName.length() > 1) {
JsonLikeValue nextValue = theObject.get(alternateName);
if (nextValue != null && nextValue.isObject()) {
String nextName = alternateName.substring(1);
if (theObject.get(nextName) == null) {
theState.enteringNewElement(null, nextName);
parseAlternates(nextValue, theState, alternateName);
theState.endingElement();
}
}
}
}
}
}
private void parseChildren(ParserState> theState, String theName, JsonLikeValue theJsonVal, JsonLikeValue theAlternateVal, String theAlternateName) {
if (theJsonVal.isArray()) {
JsonLikeArray nextArray = theJsonVal.getAsArray();
JsonLikeArray nextAlternateArray = JsonLikeValue.asArray(theAlternateVal); // could be null
for (int i = 0; i < nextArray.size(); i++) {
JsonLikeValue nextObject = nextArray.get(i);
JsonLikeValue nextAlternate = null;
if (nextAlternateArray != null) {
nextAlternate = nextAlternateArray.get(i);
}
parseChildren(theState, theName, nextObject, nextAlternate, theAlternateName);
}
} else if (theJsonVal.isObject()) {
theState.enteringNewElement(null, theName);
parseAlternates(theAlternateVal, theState, theAlternateName);
JsonLikeObject nextObject = theJsonVal.getAsObject();
boolean preResource = false;
if (theState.isPreResource()) {
JsonLikeValue resType = nextObject.get("resourceType");
if (resType == null || !resType.isString()) {
throw new DataFormatException("Missing required element 'resourceType' from JSON resource object, unable to parse");
}
theState.enteringNewElement(null, resType.getAsString());
preResource = true;
}
parseChildren(nextObject, theState);
if (preResource) {
theState.endingElement();
}
theState.endingElement();
} else if (theJsonVal.isNull()) {
theState.enteringNewElement(null, theName);
parseAlternates(theAlternateVal, theState, theAlternateName);
theState.endingElement();
} else {
// must be a SCALAR
theState.enteringNewElement(null, theName);
theState.attributeValue("value", theJsonVal.getAsString());
parseAlternates(theAlternateVal, theState, theAlternateName);
theState.endingElement();
}
}
private void parseExtension(ParserState> theState, JsonLikeArray theValues, boolean theIsModifier) {
for (int i = 0; i < theValues.size(); i++) {
JsonLikeObject nextExtObj = JsonLikeValue.asObject(theValues.get(i));
JsonLikeValue jsonElement = nextExtObj.get("url");
String url;
if (null == jsonElement || !(jsonElement.isScalar())) {
String parentElementName;
if (theIsModifier) {
parentElementName = "modifierExtension";
} else {
parentElementName = "extension";
}
getErrorHandler().missingRequiredElement(new ParseLocation(parentElementName), "url");
url = null;
} else {
url = jsonElement.getAsString();
}
theState.enteringNewElementExtension(null, url, theIsModifier);
for (String next : nextExtObj.keySet()) {
if ("url".equals(next)) {
continue;
} else if ("extension".equals(next)) {
JsonLikeArray jsonVal = JsonLikeValue.asArray(nextExtObj.get(next));
parseExtension(theState, jsonVal, false);
} else if ("modifierExtension".equals(next)) {
JsonLikeArray jsonVal = JsonLikeValue.asArray(nextExtObj.get(next));
parseExtension(theState, jsonVal, true);
} else {
JsonLikeValue jsonVal = nextExtObj.get(next);
parseChildren(theState, next, jsonVal, null, null);
}
}
theState.endingElement();
}
}
private void parseFhirComments(JsonLikeValue theObject, ParserState> theState) {
if (theObject.isArray()) {
JsonLikeArray comments = theObject.getAsArray();
for (int i = 0; i < comments.size(); i++) {
JsonLikeValue nextComment = comments.get(i);
if (nextComment.isString()) {
String commentText = nextComment.getAsString();
if (commentText != null) {
theState.commentPre(commentText);
}
}
}
}
}
@Override
public T parseResource(Class theResourceType, JsonLikeStructure theJsonLikeStructure) throws DataFormatException {
/*****************************************************
* ************************************************* *
* ** NOTE: this duplicates most of the code in ** *
* ** BaseParser.parseResource(Class, Reader). ** *
* ** Unfortunately, there is no way to avoid ** *
* ** this without doing some refactoring of the ** *
* ** BaseParser class. ** *
* ************************************************* *
*****************************************************/
/*
* We do this so that the context can verify that the structure is for
* the correct FHIR version
*/
if (theResourceType != null) {
myContext.getResourceDefinition(theResourceType);
}
// Actually do the parse
T retVal = doParseResource(theResourceType, theJsonLikeStructure);
RuntimeResourceDefinition def = myContext.getResourceDefinition(retVal);
if ("Bundle".equals(def.getName())) {
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
BaseRuntimeElementCompositeDefinition> entryDef = (BaseRuntimeElementCompositeDefinition>) entryChild.getChildByName("entry");
List entries = entryChild.getAccessor().getValues(retVal);
if (entries != null) {
for (IBase nextEntry : entries) {
/**
* If Bundle.entry.fullUrl is populated, set the resource ID to that
*/
// TODO: should emit a warning and maybe notify the error handler if the resource ID doesn't match the
// fullUrl idPart
BaseRuntimeChildDefinition fullUrlChild = entryDef.getChildByName("fullUrl");
if (fullUrlChild == null) {
continue; // TODO: remove this once the data model in tinder plugin catches up to 1.2
}
List fullUrl = fullUrlChild.getAccessor().getValues(nextEntry);
if (fullUrl != null && !fullUrl.isEmpty()) {
IPrimitiveType> value = (IPrimitiveType>) fullUrl.get(0);
if (value.isEmpty() == false) {
List entryResources = entryDef.getChildByName("resource").getAccessor().getValues(nextEntry);
if (entryResources != null && entryResources.size() > 0) {
IBaseResource res = (IBaseResource) entryResources.get(0);
String versionId = res.getIdElement().getVersionIdPart();
res.setId(value.getValueAsString());
if (isNotBlank(versionId) && res.getIdElement().hasVersionIdPart() == false) {
res.setId(res.getIdElement().withVersion(versionId));
}
}
}
}
}
}
}
return retVal;
}
@Override
public IBaseResource parseResource(JsonLikeStructure theJsonLikeStructure) throws DataFormatException {
return parseResource(null, theJsonLikeStructure);
}
@Override
public TagList parseTagList(Reader theReader) {
JsonLikeStructure jsonStructure = new GsonStructure();
jsonStructure.load(theReader);
TagList retVal = parseTagList(jsonStructure);
return retVal;
}
@Override
public TagList parseTagList(JsonLikeStructure theJsonStructure) {
JsonLikeObject object = theJsonStructure.getRootObject();
JsonLikeValue resourceTypeObj = object.get("resourceType");
String resourceType = resourceTypeObj.getAsString();
ParserState state = ParserState.getPreTagListInstance(this, myContext, true, getErrorHandler());
state.enteringNewElement(null, resourceType);
parseChildren(object, state);
state.endingElement();
state.endingElement();
return state.getObject();
}
@Override
public IParser setPrettyPrint(boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;
return this;
}
private void write(JsonLikeWriter theEventWriter, String theChildName, Boolean theValue) throws IOException {
if (theValue != null) {
theEventWriter.write(theChildName, theValue.booleanValue());
}
}
// private void parseExtensionInDstu2Style(boolean theModifier, ParserState> theState, String
// theParentExtensionUrl, String theExtensionUrl, JsonArray theValues) {
// String extUrl = UrlUtil.constructAbsoluteUrl(theParentExtensionUrl, theExtensionUrl);
// theState.enteringNewElementExtension(null, extUrl, theModifier);
//
// for (int extIdx = 0; extIdx < theValues.size(); extIdx++) {
// JsonObject nextExt = theValues.getJsonObject(extIdx);
// for (String nextKey : nextExt.keySet()) {
// // if (nextKey.startsWith("value") && nextKey.length() > 5 &&
// // myContext.getRuntimeChildUndeclaredExtensionDefinition().getChildByName(nextKey) != null) {
// JsonElement jsonVal = nextExt.get(nextKey);
// if (jsonVal.getValueType() == ValueType.ARRAY) {
// /*
// * Extension children which are arrays are sub-extensions. Any other value type should be treated as a value.
// */
// JsonArray arrayValue = (JsonArray) jsonVal;
// parseExtensionInDstu2Style(theModifier, theState, extUrl, nextKey, arrayValue);
// } else {
// parseChildren(theState, nextKey, jsonVal, null, null);
// }
// }
// }
//
// theState.endingElement();
// }
private void write(JsonLikeWriter theEventWriter, String theChildName, BigDecimal theDecimalValue) throws IOException {
theEventWriter.write(theChildName, theDecimalValue);
}
private void write(JsonLikeWriter theEventWriter, String theChildName, Integer theValue) throws IOException {
theEventWriter.write(theChildName, theValue);
}
private boolean writeAtomLinkInDstu1Format(JsonLikeWriter theEventWriter, String theRel, StringDt theLink, boolean theStarted) throws IOException {
boolean retVal = theStarted;
if (isNotBlank(theLink.getValue())) {
if (theStarted == false) {
theEventWriter.beginArray("link");
retVal = true;
}
theEventWriter.beginObject();
write(theEventWriter, "rel", theRel);
write(theEventWriter, "href", theLink.getValue());
theEventWriter.endObject();
}
return retVal;
}
private boolean writeAtomLinkInDstu2Format(JsonLikeWriter theEventWriter, String theRel, StringDt theLink, boolean theStarted) throws IOException {
boolean retVal = theStarted;
if (isNotBlank(theLink.getValue())) {
if (theStarted == false) {
theEventWriter.beginArray("link");
retVal = true;
}
theEventWriter.beginObject();
write(theEventWriter, "relation", theRel);
write(theEventWriter, "url", theLink.getValue());
theEventWriter.endObject();
}
return retVal;
}
private void writeAuthor(BaseBundle theBundle, JsonLikeWriter theEventWriter) throws IOException {
if (StringUtils.isNotBlank(theBundle.getAuthorName().getValue())) {
beginArray(theEventWriter, "author");
theEventWriter.beginObject();
writeTagWithTextNode(theEventWriter, "name", theBundle.getAuthorName());
writeOptionalTagWithTextNode(theEventWriter, "uri", theBundle.getAuthorUri());
theEventWriter.endObject();
theEventWriter.endArray();
}
}
private void writeCategories(JsonLikeWriter theEventWriter, TagList categories) throws IOException {
if (categories != null && categories.size() > 0) {
theEventWriter.beginArray("category");
for (Tag next : categories) {
theEventWriter.beginObject();
write(theEventWriter, "term", defaultString(next.getTerm()));
write(theEventWriter, "label", defaultString(next.getLabel()));
write(theEventWriter, "scheme", defaultString(next.getScheme()));
theEventWriter.endObject();
}
theEventWriter.endArray();
}
}
private void writeCommentsPreAndPost(IBase theNextValue, JsonLikeWriter theEventWriter) throws IOException {
if (theNextValue.hasFormatComment()) {
beginArray(theEventWriter, "fhir_comments");
List pre = theNextValue.getFormatCommentsPre();
if (pre.isEmpty() == false) {
for (String next : pre) {
theEventWriter.write(next);
}
}
List post = theNextValue.getFormatCommentsPost();
if (post.isEmpty() == false) {
for (String next : post) {
theEventWriter.write(next);
}
}
theEventWriter.endArray();
}
}
private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonLikeWriter theEventWriter, RuntimeResourceDefinition resDef, List extensions, List modifierExtensions) throws IOException {
if (extensions.isEmpty() == false) {
beginArray(theEventWriter, "extension");
for (HeldExtension next : extensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.endArray();
}
if (modifierExtensions.isEmpty() == false) {
beginArray(theEventWriter, "modifierExtension");
for (HeldExtension next : modifierExtensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.endArray();
}
}
private void writeOptionalTagWithDecimalNode(JsonLikeWriter theEventWriter, String theElementName, DecimalDt theValue) throws IOException {
if (theValue != null && theValue.isEmpty() == false) {
write(theEventWriter, theElementName, theValue.getValue());
}
}
private void writeOptionalTagWithNumberNode(JsonLikeWriter theEventWriter, String theElementName, IntegerDt theValue) throws IOException {
if (theValue != null && theValue.isEmpty() == false) {
write(theEventWriter, theElementName, theValue.getValue().intValue());
}
}
private void writeOptionalTagWithTextNode(JsonLikeWriter theEventWriter, String theElementName, IPrimitiveDatatype> thePrimitive) throws IOException {
if (thePrimitive == null) {
return;
}
String str = thePrimitive.getValueAsString();
writeOptionalTagWithTextNode(theEventWriter, theElementName, str);
}
private void writeOptionalTagWithTextNode(JsonLikeWriter theEventWriter, String theElementName, String theValue) throws IOException {
if (StringUtils.isNotBlank(theValue)) {
write(theEventWriter, theElementName, theValue);
}
}
private void writeTagWithTextNode(JsonLikeWriter theEventWriter, String theElementName, IPrimitiveDatatype> theIdDt) throws IOException {
if (theIdDt != null && !theIdDt.isEmpty()) {
write(theEventWriter, theElementName, theIdDt.getValueAsString());
} else {
theEventWriter.writeNull(theElementName);
}
}
private void writeTagWithTextNode(JsonLikeWriter theEventWriter, String theElementName, StringDt theStringDt) throws IOException {
if (StringUtils.isNotBlank(theStringDt.getValue())) {
write(theEventWriter, theElementName, theStringDt.getValue());
}
// else {
// theEventWriter.writeNull(theElementName);
// }
}
public static Gson newGson() {
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
return gson;
}
private static void write(JsonLikeWriter theWriter, String theName, String theValue) throws IOException {
theWriter.write(theName, theValue);
}
private class HeldExtension implements Comparable {
private CompositeChildElement myChildElem;
private RuntimeChildDeclaredExtensionDefinition myDef;
private boolean myModifier;
private IBaseExtension, ?> myUndeclaredExtension;
private IBase myValue;
public HeldExtension(IBaseExtension, ?> theUndeclaredExtension, boolean theModifier, CompositeChildElement theChildElem) {
assert theUndeclaredExtension != null;
myUndeclaredExtension = theUndeclaredExtension;
myModifier = theModifier;
myChildElem = theChildElem;
}
public HeldExtension(RuntimeChildDeclaredExtensionDefinition theDef, IBase theValue, CompositeChildElement theChildElem) {
assert theDef != null;
assert theValue != null;
myDef = theDef;
myValue = theValue;
myChildElem = theChildElem;
}
@Override
public int compareTo(HeldExtension theArg0) {
String url1 = myDef != null ? myDef.getExtensionUrl() : myUndeclaredExtension.getUrl();
String url2 = theArg0.myDef != null ? theArg0.myDef.getExtensionUrl() : theArg0.myUndeclaredExtension.getUrl();
url1 = defaultString(url1);
url2 = defaultString(url2);
return url1.compareTo(url2);
}
public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter) throws IOException {
if (myUndeclaredExtension != null) {
writeUndeclaredExtension(theResDef, theResource, theEventWriter, myUndeclaredExtension);
} else {
theEventWriter.beginObject();
writeCommentsPreAndPost(myValue, theEventWriter);
JsonParser.write(theEventWriter, "url", myDef.getExtensionUrl());
/*
* This makes sure that even if the extension contains a reference to a contained
* resource which has a HAPI-assigned ID we'll still encode that ID.
*
* See #327
*/
List extends IBase> preProcessedValue = preProcessValues(myDef, theResource, Collections.singletonList(myValue), myChildElem);
myValue = preProcessedValue.get(0);
BaseRuntimeElementDefinition> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass());
if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) {
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, myChildElem);
} else {
String childName = myDef.getChildNameByDatatype(myValue.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false, null, false);
}
theEventWriter.endObject();
}
}
private void writeUndeclaredExtension(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBaseExtension, ?> ext) throws IOException {
IBase value = ext.getValue();
String extensionUrl = ext.getUrl();
theEventWriter.beginObject();
writeCommentsPreAndPost(myUndeclaredExtension, theEventWriter);
String elementId = getCompositeElementId(ext);
if (isNotBlank(elementId)) {
JsonParser.write(theEventWriter, "id", getCompositeElementId(ext));
}
JsonParser.write(theEventWriter, "url", extensionUrl);
boolean noValue = value == null || value.isEmpty();
if (noValue && ext.getExtension().isEmpty()) {
ourLog.debug("Extension with URL[{}] has no value", extensionUrl);
} else if (noValue) {
if (myModifier) {
beginArray(theEventWriter, "modifierExtension");
} else {
beginArray(theEventWriter, "extension");
}
for (Object next : ext.getExtension()) {
writeUndeclaredExtension(theResDef, theResource, theEventWriter, (IBaseExtension, ?>) next);
}
theEventWriter.endArray();
} else {
/*
* Pre-process value - This is called in case the value is a reference
* since we might modify the text
*/
value = JsonParser.super.preProcessValues(myDef, theResource, Collections.singletonList(value), myChildElem).get(0);
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(value.getClass());
if (childName == null) {
childName = "value" + WordUtils.capitalize(myContext.getElementDefinition(value.getClass()).getName());
}
BaseRuntimeElementDefinition> childDef = extDef.getChildElementDefinitionByDatatype(value.getClass());
if (childDef == null) {
throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + value.getClass().getCanonicalName());
}
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true, null, false);
}
// theEventWriter.name(myUndeclaredExtension.get);
theEventWriter.endObject();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy