Allow contained resources to parse and encode correctly
This commit is contained in:
parent
dfa88a442c
commit
bb86724e12
|
@ -2,3 +2,4 @@
|
|||
/target
|
||||
*.log
|
||||
*.log*
|
||||
nohup.out
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
<action type="fix">
|
||||
Support for Query resources fixed (in parser)
|
||||
</action>
|
||||
<action type="fix">
|
||||
Nested contained resources (e.g. encoding a resource with a contained resource that itself contains a resource)
|
||||
now parse and encode correctly, meaning that all contained resources are placed in the "contained" element
|
||||
of the root resource, and the parser looks in the root resource for all container levels when stitching
|
||||
contained resources back together.
|
||||
</action>
|
||||
</release>
|
||||
</body>
|
||||
</document>
|
||||
|
|
|
@ -46,6 +46,8 @@ public abstract class BaseRuntimeChildDefinition {
|
|||
List<? extends IElement> getValues(Object theTarget);
|
||||
}
|
||||
|
||||
public abstract String getElementName();
|
||||
|
||||
public abstract int getMax();
|
||||
|
||||
public abstract int getMin();
|
||||
|
|
|
@ -147,4 +147,9 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return "extension";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -71,6 +71,13 @@ public class CodeableConceptDt
|
|||
// nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which creates a CodeableConceptDt with one coding repetition, containing
|
||||
* the given system and code
|
||||
*/
|
||||
public CodeableConceptDt(String theSystem, String theCode) {
|
||||
addCoding().setSystem(theSystem).setCode(theCode);
|
||||
}
|
||||
|
||||
@Child(name="coding", type=CodingDt.class, order=0, min=0, max=Child.MAX_UNLIMITED)
|
||||
@Description(
|
||||
|
|
|
@ -201,6 +201,9 @@ public class ResourceReferenceDt extends BaseResourceReference implements ICompo
|
|||
|
||||
@Override
|
||||
public IdDt getResourceId() {
|
||||
if (myReference == null) {
|
||||
return new IdDt();
|
||||
}
|
||||
return new IdDt(myReference.getValue());
|
||||
}
|
||||
|
||||
|
|
|
@ -121,4 +121,18 @@ public class UriDt extends BasePrimitive<URI> {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new UriDt instance which uses the given OID as the content (and prepends "urn:oid:" to the
|
||||
* OID string in the value of the newly created UriDt, per the FHIR specification).
|
||||
*
|
||||
* @param theOid The OID to use (<code>null</code> is acceptable and will result in a UriDt instance with a <code>null</code> value)
|
||||
* @return A new UriDt instance
|
||||
*/
|
||||
public static UriDt fromOid(String theOid) {
|
||||
if (theOid == null) {
|
||||
return new UriDt();
|
||||
}
|
||||
return new UriDt("urn:oid:" + theOid);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.UUID;
|
|||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
|
@ -44,6 +45,11 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
|||
public abstract class BaseParser implements IParser {
|
||||
|
||||
private boolean mySuppressNarratives;
|
||||
private FhirContext myContext;
|
||||
|
||||
public BaseParser(FhirContext theContext) {
|
||||
myContext = theContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagList parseTagList(String theString) {
|
||||
|
@ -116,7 +122,13 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
|
||||
public void containResourcesForEncoding(IResource theResource) {
|
||||
List<ResourceReferenceDt> allElements = theResource.getAllPopulatedChildElementsOfType(ResourceReferenceDt.class);
|
||||
containResourcesForEncoding(theResource, theResource);
|
||||
}
|
||||
|
||||
private long myNextContainedId = 1;
|
||||
|
||||
private void containResourcesForEncoding(IResource theResource, IResource theTarget) {
|
||||
List<ResourceReferenceDt> allElements = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, ResourceReferenceDt.class);
|
||||
|
||||
Set<String> allIds = new HashSet<String>();
|
||||
|
||||
|
@ -124,15 +136,18 @@ public abstract class BaseParser implements IParser {
|
|||
IResource resource = next.getResource();
|
||||
if (resource != null) {
|
||||
if (resource.getId().isEmpty()) {
|
||||
resource.setId(new IdDt(UUID.randomUUID().toString()));
|
||||
resource.setId(new IdDt(myNextContainedId++));
|
||||
// resource.setId(new IdDt(UUID.randomUUID().toString()));
|
||||
}
|
||||
|
||||
if (!allIds.contains(resource.getId().getValue())) {
|
||||
theResource.getContained().getContainedResources().add(resource);
|
||||
theTarget.getContained().getContainedResources().add(resource);
|
||||
allIds.add(resource.getId().getValue());
|
||||
}
|
||||
|
||||
next.setReference("#" + resource.getId().getValue());
|
||||
|
||||
containResourcesForEncoding(resource, theTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
private boolean myPrettyPrint;
|
||||
|
||||
public JsonParser(FhirContext theContext) {
|
||||
super(theContext);
|
||||
myContext = theContext;
|
||||
}
|
||||
|
||||
|
@ -211,7 +212,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
IResource resource = nextEntry.getResource();
|
||||
if (resource != null && !resource.isEmpty()) {
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(resource);
|
||||
encodeResourceToJsonStreamWriter(resDef, resource, eventWriter, "content");
|
||||
encodeResourceToJsonStreamWriter(resDef, resource, eventWriter, "content", false);
|
||||
}
|
||||
|
||||
eventWriter.writeEnd(); // entry object
|
||||
|
@ -299,7 +300,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
theWriter.writeStartArray(theChildName);
|
||||
ContainedDt value = (ContainedDt) theValue;
|
||||
for (IResource next : value.getContainedResources()) {
|
||||
encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null);
|
||||
encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null, true);
|
||||
}
|
||||
theWriter.writeEnd();
|
||||
break;
|
||||
|
@ -465,8 +466,10 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren());
|
||||
}
|
||||
|
||||
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull) throws IOException {
|
||||
super.containResourcesForEncoding(theResource);
|
||||
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theIncludedResource) throws IOException {
|
||||
if (!theIncludedResource) {
|
||||
super.containResourcesForEncoding(theResource);
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||
|
||||
|
@ -499,7 +502,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
JsonGenerator eventWriter = createJsonGenerator(theWriter);
|
||||
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null);
|
||||
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null,false);
|
||||
eventWriter.flush();
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,37 @@ class ParserState<T> {
|
|||
return myState.isPreResource();
|
||||
}
|
||||
|
||||
private void pop() {
|
||||
myState = myState.myStack;
|
||||
myState.wereBack();
|
||||
}
|
||||
|
||||
private void push(BaseState theState) {
|
||||
theState.setStack(myState);
|
||||
myState = theState;
|
||||
}
|
||||
|
||||
private void putPlacerResourceInDeletedEntry(BundleEntry entry) {
|
||||
IdDt id = null;
|
||||
if (entry.getLinkSelf() != null && entry.getLinkSelf().isEmpty() == false) {
|
||||
id = new IdDt(entry.getLinkSelf().getValue());
|
||||
} else {
|
||||
id = entry.getId();
|
||||
}
|
||||
|
||||
IResource resource = entry.getResource();
|
||||
if (resource == null && id != null && isNotBlank(id.getResourceType())) {
|
||||
resource = myContext.getResourceDefinition(id.getResourceType()).newInstance();
|
||||
resource.setId(id);
|
||||
entry.setResource(resource);
|
||||
}
|
||||
|
||||
if (resource != null) {
|
||||
resource.getResourceMetadata().put(ResourceMetadataKeyEnum.DELETED_AT, entry.getDeletedAt());
|
||||
resource.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, id);
|
||||
}
|
||||
}
|
||||
|
||||
public void string(String theData) {
|
||||
myState.string(theData);
|
||||
}
|
||||
|
@ -128,16 +159,6 @@ class ParserState<T> {
|
|||
myState.xmlEvent(theNextEvent);
|
||||
}
|
||||
|
||||
private void pop() {
|
||||
myState = myState.myStack;
|
||||
myState.wereBack();
|
||||
}
|
||||
|
||||
private void push(BaseState theState) {
|
||||
theState.setStack(myState);
|
||||
myState = theState;
|
||||
}
|
||||
|
||||
public static ParserState<Bundle> getPreAtomInstance(FhirContext theContext, Class<? extends IResource> theResourceType, boolean theJsonMode) throws DataFormatException {
|
||||
ParserState<Bundle> retVal = new ParserState<Bundle>(theContext, theJsonMode);
|
||||
retVal.push(retVal.new PreAtomState(theResourceType));
|
||||
|
@ -191,13 +212,10 @@ class ParserState<T> {
|
|||
|
||||
private static final int STATE_LABEL = 2;
|
||||
private static final int STATE_NONE = 0;
|
||||
|
||||
private static final int STATE_SCHEME = 3;
|
||||
|
||||
private static final int STATE_TERM = 1;
|
||||
|
||||
|
||||
private int myCatState = STATE_NONE;
|
||||
|
||||
private Tag myInstance;
|
||||
|
||||
public AtomCategoryState(Tag theEntry) {
|
||||
|
@ -261,32 +279,68 @@ class ParserState<T> {
|
|||
|
||||
}
|
||||
|
||||
private void putPlacerResourceInDeletedEntry(BundleEntry entry) {
|
||||
IdDt id = null;
|
||||
if (entry.getLinkSelf() != null && entry.getLinkSelf().isEmpty() == false) {
|
||||
id = new IdDt(entry.getLinkSelf().getValue());
|
||||
} else {
|
||||
id = entry.getId();
|
||||
public class AtomDeletedEntryState extends AtomEntryState {
|
||||
|
||||
public AtomDeletedEntryState(Bundle theInstance, Class<? extends IResource> theResourceType) {
|
||||
super(theInstance, theResourceType);
|
||||
}
|
||||
|
||||
IResource resource = entry.getResource();
|
||||
if (resource == null && id != null && isNotBlank(id.getResourceType())) {
|
||||
resource = myContext.getResourceDefinition(id.getResourceType()).newInstance();
|
||||
resource.setId(id);
|
||||
entry.setResource(resource);
|
||||
@Override
|
||||
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
||||
if ("ref".equals(theName)) {
|
||||
getEntry().setId(new IdDt(theValue));
|
||||
} else if ("when".equals(theName)) {
|
||||
getEntry().setDeleted(new InstantDt(theValue));
|
||||
}
|
||||
}
|
||||
|
||||
if (resource != null) {
|
||||
resource.getResourceMetadata().put(ResourceMetadataKeyEnum.DELETED_AT, entry.getDeletedAt());
|
||||
resource.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, id);
|
||||
@Override
|
||||
public void endingElement() throws DataFormatException {
|
||||
putPlacerResourceInDeletedEntry(getEntry());
|
||||
super.endingElement();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AtomDeletedJsonWhenState extends BaseState {
|
||||
|
||||
private String myData;
|
||||
private IPrimitiveDatatype<?> myPrimitive;
|
||||
|
||||
public AtomDeletedJsonWhenState(IPrimitiveDatatype<?> thePrimitive) {
|
||||
super(null);
|
||||
Validate.notNull(thePrimitive, "thePrimitive");
|
||||
myPrimitive = thePrimitive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
||||
myData = theValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement() throws DataFormatException {
|
||||
myPrimitive.setValueAsString(myData);
|
||||
pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
||||
throw new DataFormatException("Unexpected nested element in atom tag: " + theLocalPart);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class AtomEntryState extends BaseState {
|
||||
|
||||
private boolean myDeleted;
|
||||
private BundleEntry myEntry;
|
||||
private Class<? extends IResource> myResourceType;
|
||||
private boolean myDeleted;
|
||||
|
||||
public AtomEntryState(Bundle theInstance, Class<? extends IResource> theResourceType) {
|
||||
super(null);
|
||||
|
@ -295,10 +349,6 @@ class ParserState<T> {
|
|||
theInstance.getEntries().add(myEntry);
|
||||
}
|
||||
|
||||
protected BundleEntry getEntry() {
|
||||
return myEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement() throws DataFormatException {
|
||||
populateResourceMetadata();
|
||||
|
@ -340,6 +390,10 @@ class ParserState<T> {
|
|||
// TODO: handle category
|
||||
}
|
||||
|
||||
protected BundleEntry getEntry() {
|
||||
return myEntry;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void populateResourceMetadata() {
|
||||
if (myEntry.getResource() == null) {
|
||||
|
@ -378,29 +432,6 @@ class ParserState<T> {
|
|||
|
||||
}
|
||||
|
||||
public class AtomDeletedEntryState extends AtomEntryState {
|
||||
|
||||
public AtomDeletedEntryState(Bundle theInstance, Class<? extends IResource> theResourceType) {
|
||||
super(theInstance, theResourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
||||
if ("ref".equals(theName)) {
|
||||
getEntry().setId(new IdDt(theValue));
|
||||
} else if ("when".equals(theName)) {
|
||||
getEntry().setDeleted(new InstantDt(theValue));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement() throws DataFormatException {
|
||||
putPlacerResourceInDeletedEntry(getEntry());
|
||||
super.endingElement();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AtomLinkState extends BaseState {
|
||||
|
||||
private BundleEntry myEntry;
|
||||
|
@ -460,77 +491,6 @@ class ParserState<T> {
|
|||
|
||||
}
|
||||
|
||||
private class BinaryResourceState extends BaseState {
|
||||
|
||||
private static final int SUBSTATE_CT = 1;
|
||||
private static final int SUBSTATE_CONTENT = 2;
|
||||
private Binary myInstance;
|
||||
private String myData;
|
||||
private int mySubState = 0;
|
||||
|
||||
public BinaryResourceState(PreResourceState thePreResourceState, Binary theInstance) {
|
||||
super(thePreResourceState);
|
||||
myInstance = theInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
||||
if ("contentType".equals(theName)) {
|
||||
myInstance.setContentType(theValue);
|
||||
} else if (myJsonMode && "value".equals(theName)) {
|
||||
string(theValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement() throws DataFormatException {
|
||||
if (mySubState == SUBSTATE_CT) {
|
||||
myInstance.setContentType(myData);
|
||||
mySubState = 0;
|
||||
myData=null;
|
||||
return;
|
||||
} else if (mySubState == SUBSTATE_CONTENT) {
|
||||
myInstance.setContentAsBase64(myData);
|
||||
mySubState = 0;
|
||||
myData=null;
|
||||
return;
|
||||
} else {
|
||||
if (!myJsonMode) {
|
||||
myInstance.setContentAsBase64(myData);
|
||||
}
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
||||
if (myJsonMode && "contentType".equals(theLocalPart) && mySubState == 0) {
|
||||
mySubState = SUBSTATE_CT;
|
||||
} else if (myJsonMode && "content".equals(theLocalPart) && mySubState == 0) {
|
||||
mySubState = SUBSTATE_CONTENT;
|
||||
} else {
|
||||
throw new DataFormatException("Unexpected nested element in atom tag: " + theLocalPart);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void string(String theData) {
|
||||
if (myData == null) {
|
||||
myData = theData;
|
||||
} else {
|
||||
// this shouldn't generally happen so it's ok that it's
|
||||
// inefficient
|
||||
myData = myData + theData;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AtomPrimitiveState extends BaseState {
|
||||
|
||||
private String myData;
|
||||
|
@ -561,6 +521,11 @@ class ParserState<T> {
|
|||
throw new DataFormatException("Unexpected nested element in atom tag: " + theLocalPart);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void string(String theData) {
|
||||
if (myData == null) {
|
||||
|
@ -572,45 +537,6 @@ class ParserState<T> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AtomDeletedJsonWhenState extends BaseState {
|
||||
|
||||
private String myData;
|
||||
private IPrimitiveDatatype<?> myPrimitive;
|
||||
|
||||
public AtomDeletedJsonWhenState(IPrimitiveDatatype<?> thePrimitive) {
|
||||
super(null);
|
||||
Validate.notNull(thePrimitive, "thePrimitive");
|
||||
myPrimitive = thePrimitive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement() throws DataFormatException {
|
||||
myPrimitive.setValueAsString(myData);
|
||||
pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
||||
throw new DataFormatException("Unexpected nested element in atom tag: " + theLocalPart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
||||
myData = theValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AtomState extends BaseState {
|
||||
|
@ -710,6 +636,10 @@ class ParserState<T> {
|
|||
}
|
||||
}
|
||||
|
||||
protected Object getCurrentElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PreResourceState getPreResourceState() {
|
||||
return myPreResourceState;
|
||||
}
|
||||
|
@ -734,10 +664,77 @@ class ParserState<T> {
|
|||
// ignore
|
||||
}
|
||||
|
||||
protected Object getCurrentElement() {
|
||||
}
|
||||
|
||||
private class BinaryResourceState extends BaseState {
|
||||
|
||||
private static final int SUBSTATE_CONTENT = 2;
|
||||
private static final int SUBSTATE_CT = 1;
|
||||
private String myData;
|
||||
private Binary myInstance;
|
||||
private int mySubState = 0;
|
||||
|
||||
public BinaryResourceState(PreResourceState thePreResourceState, Binary theInstance) {
|
||||
super(thePreResourceState);
|
||||
myInstance = theInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
||||
if ("contentType".equals(theName)) {
|
||||
myInstance.setContentType(theValue);
|
||||
} else if (myJsonMode && "value".equals(theName)) {
|
||||
string(theValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endingElement() throws DataFormatException {
|
||||
if (mySubState == SUBSTATE_CT) {
|
||||
myInstance.setContentType(myData);
|
||||
mySubState = 0;
|
||||
myData=null;
|
||||
return;
|
||||
} else if (mySubState == SUBSTATE_CONTENT) {
|
||||
myInstance.setContentAsBase64(myData);
|
||||
mySubState = 0;
|
||||
myData=null;
|
||||
return;
|
||||
} else {
|
||||
if (!myJsonMode) {
|
||||
myInstance.setContentAsBase64(myData);
|
||||
}
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
||||
if (myJsonMode && "contentType".equals(theLocalPart) && mySubState == 0) {
|
||||
mySubState = SUBSTATE_CT;
|
||||
} else if (myJsonMode && "content".equals(theLocalPart) && mySubState == 0) {
|
||||
mySubState = SUBSTATE_CONTENT;
|
||||
} else {
|
||||
throw new DataFormatException("Unexpected nested element in atom tag: " + theLocalPart);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void string(String theData) {
|
||||
if (myData == null) {
|
||||
myData = theData;
|
||||
} else {
|
||||
// this shouldn't generally happen so it's ok that it's
|
||||
// inefficient
|
||||
myData = myData + theData;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ContainedResourcesState extends PreResourceState {
|
||||
|
@ -952,7 +949,8 @@ class ParserState<T> {
|
|||
return;
|
||||
}
|
||||
case UNDECL_EXT:
|
||||
case RESOURCE: {
|
||||
case RESOURCE:
|
||||
case EXTENSION_DECLARED:{
|
||||
// Throw an exception because this shouldn't happen here
|
||||
break;
|
||||
}
|
||||
|
@ -1031,6 +1029,8 @@ class ParserState<T> {
|
|||
case RESOURCE:
|
||||
case RESOURCE_BLOCK:
|
||||
case UNDECL_EXT:
|
||||
case EXTENSION_DECLARED:
|
||||
case CONTAINED_RESOURCES:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1068,17 +1068,17 @@ class ParserState<T> {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myInstance;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void wereBack() {
|
||||
myObject = (T) myInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class PreResourceState extends BaseState {
|
||||
|
@ -1087,7 +1087,6 @@ class ParserState<T> {
|
|||
private BundleEntry myEntry;
|
||||
private IResource myInstance;
|
||||
private List<ResourceReferenceDt> myResourceReferences = new ArrayList<ResourceReferenceDt>();
|
||||
|
||||
private Class<? extends IResource> myResourceType;
|
||||
|
||||
public PreResourceState(BundleEntry theEntry, Class<? extends IResource> theResourceType) {
|
||||
|
@ -1113,7 +1112,7 @@ class ParserState<T> {
|
|||
public void endingElement() throws DataFormatException {
|
||||
pop();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
||||
BaseRuntimeElementDefinition<?> definition;
|
||||
|
@ -1136,9 +1135,9 @@ class ParserState<T> {
|
|||
}
|
||||
|
||||
if ("Binary".equals(def.getName())) {
|
||||
push(new BinaryResourceState(this, (Binary) myInstance));
|
||||
push(new BinaryResourceState(getRootPreResourceState(), (Binary) myInstance));
|
||||
} else {
|
||||
push(new ElementCompositeState(this, def, myInstance));
|
||||
push(new ElementCompositeState(getRootPreResourceState(), def, myInstance));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1146,10 +1145,23 @@ class ParserState<T> {
|
|||
return myContainedResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IResource getCurrentElement() {
|
||||
return myInstance;
|
||||
}
|
||||
|
||||
public List<ResourceReferenceDt> getResourceReferences() {
|
||||
return myResourceReferences;
|
||||
}
|
||||
|
||||
private PreResourceState getRootPreResourceState() {
|
||||
if (getPreResourceState() != null) {
|
||||
return getPreResourceState();
|
||||
}else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreResource() {
|
||||
return true;
|
||||
|
@ -1178,11 +1190,6 @@ class ParserState<T> {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IResource getCurrentElement() {
|
||||
return myInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class PreTagListState extends BaseState {
|
||||
|
@ -1208,6 +1215,11 @@ class ParserState<T> {
|
|||
push(new TagListState(myTagList));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TagList getCurrentElement() {
|
||||
return myTagList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreResource() {
|
||||
return true;
|
||||
|
@ -1219,11 +1231,6 @@ class ParserState<T> {
|
|||
myObject = (T) myTagList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TagList getCurrentElement() {
|
||||
return myTagList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class PrimitiveState extends BaseState {
|
||||
|
@ -1507,6 +1514,11 @@ class ParserState<T> {
|
|||
super.endingElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myDt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void xmlEvent(XMLEvent theEvent) {
|
||||
if (theEvent.isEndElement()) {
|
||||
|
@ -1529,11 +1541,6 @@ class ParserState<T> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IElement getCurrentElement() {
|
||||
return myDt;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
private XMLOutputFactory myXmlOutputFactory;
|
||||
|
||||
public XmlParser(FhirContext theContext) {
|
||||
super(theContext);
|
||||
myContext = theContext;
|
||||
myXmlInputFactory = XMLInputFactory.newInstance();
|
||||
myXmlOutputFactory = XMLOutputFactory.newInstance();
|
||||
|
@ -543,7 +544,9 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
*
|
||||
*/
|
||||
private void encodeResourceToXmlStreamWriter(IResource theResource, XMLStreamWriter theEventWriter, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
|
||||
super.containResourcesForEncoding(theResource);
|
||||
if (!theIncludedResource) {
|
||||
super.containResourcesForEncoding(theResource);
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||
if (resDef == null) {
|
||||
|
|
|
@ -36,6 +36,7 @@ import ca.uhn.fhir.model.api.IResource;
|
|||
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
|
||||
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
public class FhirTerser {
|
||||
|
||||
|
@ -147,7 +148,13 @@ public class FhirTerser {
|
|||
if (nextValue == null) {
|
||||
continue;
|
||||
}
|
||||
if (nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
BaseRuntimeElementDefinition<?> childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass());
|
||||
if (childElementDef == null) {
|
||||
throw new DataFormatException("Found value of type[" + nextValue.getClass().getSimpleName() + "] which is not valid for field[" + nextChild.getElementName() + "] in " + childDef.getName());
|
||||
}
|
||||
getAllChildElementsOfType(nextValue, childElementDef, theType, theList);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
@ -83,6 +84,44 @@ public class JsonParserTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedContainedResources() {
|
||||
|
||||
Observation A = new Observation();
|
||||
A.getName().setText("A");
|
||||
|
||||
Observation B = new Observation();
|
||||
B.getName().setText("B");
|
||||
A.addRelated().setTarget(new ResourceReferenceDt(B));
|
||||
|
||||
Observation C = new Observation();
|
||||
C.getName().setText("C");
|
||||
B.addRelated().setTarget(new ResourceReferenceDt(C));
|
||||
|
||||
String str = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(A);
|
||||
ourLog.info(str);
|
||||
|
||||
assertThat(str, stringContainsInOrder(Arrays.asList("\"text\":\"B\"", "\"text\":\"C\"", "\"text\":\"A\"")));
|
||||
|
||||
// Only one (outer) contained block
|
||||
int idx0 = str.indexOf("\"contained\"");
|
||||
int idx1 = str.indexOf("\"contained\"",idx0+1);
|
||||
|
||||
assertNotEquals(-1, idx0);
|
||||
assertEquals(-1, idx1);
|
||||
|
||||
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, str);
|
||||
assertEquals("A",obs.getName().getText().getValue());
|
||||
|
||||
Observation obsB = (Observation) obs.getRelatedFirstRep().getTarget().getResource();
|
||||
assertEquals("B",obsB.getName().getText().getValue());
|
||||
|
||||
Observation obsC = (Observation) obsB.getRelatedFirstRep().getTarget().getResource();
|
||||
assertEquals("C",obsC.getName().getText().getValue());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseQuery() {
|
||||
String msg = "{\n" +
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.List;
|
|||
import org.apache.commons.io.IOUtils;
|
||||
import org.custommonkey.xmlunit.Diff;
|
||||
import org.custommonkey.xmlunit.XMLUnit;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hamcrest.core.IsNot;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hamcrest.text.StringContainsInOrder;
|
||||
|
@ -80,6 +81,46 @@ public class XmlParserTest {
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNestedContainedResources() {
|
||||
|
||||
Observation A = new Observation();
|
||||
A.getName().setText("A");
|
||||
|
||||
Observation B = new Observation();
|
||||
B.getName().setText("B");
|
||||
A.addRelated().setTarget(new ResourceReferenceDt(B));
|
||||
|
||||
Observation C = new Observation();
|
||||
C.getName().setText("C");
|
||||
B.addRelated().setTarget(new ResourceReferenceDt(C));
|
||||
|
||||
String str = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(A);
|
||||
ourLog.info(str);
|
||||
|
||||
assertThat(str, stringContainsInOrder(Arrays.asList("<text value=\"B\"/>", "<text value=\"C\"/>", "<text value=\"A\"/>")));
|
||||
assertThat(str, stringContainsInOrder(Arrays.asList("<contained>", "</contained>")));
|
||||
|
||||
// Only one (outer) contained block
|
||||
int idx0 = str.indexOf("<contained>");
|
||||
int idx1 = str.indexOf("<contained>",idx0+1);
|
||||
assertNotEquals(-1, idx0);
|
||||
assertEquals(-1, idx1);
|
||||
|
||||
Observation obs = ourCtx.newXmlParser().parseResource(Observation.class, str);
|
||||
assertEquals("A",obs.getName().getText().getValue());
|
||||
|
||||
Observation obsB = (Observation) obs.getRelatedFirstRep().getTarget().getResource();
|
||||
assertEquals("B",obsB.getName().getText().getValue());
|
||||
|
||||
Observation obsC = (Observation) obsB.getRelatedFirstRep().getTarget().getResource();
|
||||
assertEquals("C",obsC.getName().getText().getValue());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseQuery() {
|
||||
String msg = "<Query xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry including="**/*.java" kind="src" path="target/generated-sources/tinder"/>
|
||||
<classpathentry kind="src" path="target/generated-sources/tinder"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/xml/stream/stax-api/1.0-2/stax-api-1.0-2.jar" sourcepath="M2_REPO/javax/xml/stream/stax-api/1.0-2/stax-api-1.0-2-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar" sourcepath="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0-sources.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
|
|
|
@ -43,6 +43,15 @@ public class ${className}
|
|||
#########################
|
||||
### Type-specific constructors
|
||||
#########################
|
||||
#if ( ${className} == "CodeableConceptDt" )
|
||||
/**
|
||||
* Constructor which creates a CodeableConceptDt with one coding repetition, containing
|
||||
* the given system and code
|
||||
*/
|
||||
public CodeableConceptDt(String theSystem, String theCode) {
|
||||
addCoding().setSystem(theSystem).setCode(theCode);
|
||||
}
|
||||
#end
|
||||
#if ( ${className} == "CodingDt" )
|
||||
/**
|
||||
* Creates a new Coding with the given system and code
|
||||
|
|
Loading…
Reference in New Issue