Implement Jackson parser/serializer (#1733)

* [dev] Integration of a Jackson serializer and deserializer - first stage

* [fix] Fixed some serializing issues
[improve] Improved the processing, removed the loggers

* [clean] Removed the JacksonSerializer class, replaced all the Gson classes with Jackson classes

* [clean] Small cleanup

* [improve] Throw a ConfigurationException if the JsonGenerator cannot be created

* [improve] Use the ObjectMapper's `readTree` instead of `readValue`

* [dev] Latest fixes and improvements

* [dev] Use the Jackson serializer

* [clean] Removed the ObjectMapper configuration, for now

* [fix] Use the GsonStructure also for the parsing of a FHIR resource

* [clean] Removed the LinkedList usage

* Work on preparing for merge of #1673

* Resolve build errors

* Work on parser integration

* Tests passing

* Resolve fixme

* CLeanup

* Fix dependency

Co-authored-by: Bogdan Solga <bogdan.solga@gmail.com>
This commit is contained in:
James Agnew 2020-03-17 17:27:26 -04:00 committed by GitHub
parent 4583cb9939
commit bde7c356fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1381 additions and 1434 deletions

View File

@ -20,8 +20,8 @@
<!-- JSON --> <!-- JSON -->
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>gson</artifactId> <artifactId>jackson-databind</artifactId>
</dependency> </dependency>
<!-- XML --> <!-- XML -->

View File

@ -22,20 +22,29 @@ package ca.uhn.fhir.parser;
import ca.uhn.fhir.context.*; import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum; import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.base.composite.BaseCodingDt; import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt; import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.narrative.INarrativeGenerator; import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.parser.json.*; 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.JsonLikeValue.ScalarType; import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType; import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
import ca.uhn.fhir.parser.json.JsonLikeWriter;
import ca.uhn.fhir.parser.json.jackson.JacksonStructure;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.util.ElementUtil; import ca.uhn.fhir.util.ElementUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.text.WordUtils; import org.apache.commons.text.WordUtils;
@ -45,11 +54,17 @@ import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.*; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum.ID_DATATYPE; import static ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum.ID_DATATYPE;
import static ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum.PRIMITIVE_DATATYPE; import static ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum.PRIMITIVE_DATATYPE;
import static org.apache.commons.lang3.StringUtils.*; import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/** /**
* This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use * This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use
@ -147,10 +162,9 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
theEventWriter.beginObject(arrayName); theEventWriter.beginObject(arrayName);
} }
private JsonLikeWriter createJsonWriter(Writer theWriter) { private JsonLikeWriter createJsonWriter(Writer theWriter) throws IOException {
JsonLikeStructure jsonStructure = new GsonStructure(); JsonLikeStructure jsonStructure = new JacksonStructure();
JsonLikeWriter retVal = jsonStructure.getJsonLikeWriter(theWriter); return jsonStructure.getJsonLikeWriter(theWriter);
return retVal;
} }
public void doEncodeResourceToJsonLikeWriter(IBaseResource theResource, JsonLikeWriter theEventWriter, EncodeContext theEncodeContext) throws IOException { public void doEncodeResourceToJsonLikeWriter(IBaseResource theResource, JsonLikeWriter theEventWriter, EncodeContext theEncodeContext) throws IOException {
@ -168,11 +182,12 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
protected void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter, EncodeContext theEncodeContext) throws IOException { protected void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter, EncodeContext theEncodeContext) throws IOException {
JsonLikeWriter eventWriter = createJsonWriter(theWriter); JsonLikeWriter eventWriter = createJsonWriter(theWriter);
doEncodeResourceToJsonLikeWriter(theResource, eventWriter, theEncodeContext); doEncodeResourceToJsonLikeWriter(theResource, eventWriter, theEncodeContext);
eventWriter.close();
} }
@Override @Override
public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) { public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) {
JsonLikeStructure jsonStructure = new GsonStructure(); JsonLikeStructure jsonStructure = new JacksonStructure();
jsonStructure.load(theReader); jsonStructure.load(theReader);
T retVal = doParseResource(theResourceType, jsonStructure); T retVal = doParseResource(theResourceType, jsonStructure);
@ -418,10 +433,10 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
String currentChildName = null; String currentChildName = null;
boolean inArray = false; boolean inArray = false;
ArrayList<ArrayList<HeldExtension>> extensions = new ArrayList<ArrayList<HeldExtension>>(0); ArrayList<ArrayList<HeldExtension>> extensions = new ArrayList<>(0);
ArrayList<ArrayList<HeldExtension>> modifierExtensions = new ArrayList<ArrayList<HeldExtension>>(0); ArrayList<ArrayList<HeldExtension>> modifierExtensions = new ArrayList<>(0);
ArrayList<ArrayList<String>> comments = new ArrayList<ArrayList<String>>(0); ArrayList<ArrayList<String>> comments = new ArrayList<>(0);
ArrayList<String> ids = new ArrayList<String>(0); ArrayList<String> ids = new ArrayList<>(0);
int valueIdx = 0; int valueIdx = 0;
for (IBase nextValue : values) { for (IBase nextValue : values) {
@ -1107,7 +1122,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
} else { } else {
// must be a SCALAR // must be a SCALAR
theState.enteringNewElement(null, theName); theState.enteringNewElement(null, theName);
theState.attributeValue("value", theJsonVal.getAsString()); String asString = theJsonVal.getAsString();
theState.attributeValue("value", asString);
parseAlternates(theAlternateVal, theState, theAlternateName, theAlternateName); parseAlternates(theAlternateVal, theState, theAlternateName, theAlternateName);
theState.endingElement(); theState.endingElement();
} }
@ -1376,11 +1392,6 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
} }
} }
public static Gson newGson() {
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
return gson;
}
private static void write(JsonLikeWriter theWriter, String theName, String theValue) throws IOException { private static void write(JsonLikeWriter theWriter, String theName, String theValue) throws IOException {
theWriter.write(theName, theValue); theWriter.write(theName, theValue);
} }

View File

@ -1,379 +0,0 @@
package ca.uhn.fhir.parser.json;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2020 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 java.io.PushbackReader;
import java.io.Reader;
import java.io.Writer;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import ca.uhn.fhir.parser.DataFormatException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
public class GsonStructure implements JsonLikeStructure {
private enum ROOT_TYPE {OBJECT, ARRAY};
private ROOT_TYPE rootType = null;
private JsonElement nativeRoot = null;
private JsonLikeValue jsonLikeRoot = null;
private GsonWriter jsonLikeWriter = null;
public GsonStructure() {
super();
}
public void setNativeObject (JsonObject json) {
this.rootType = ROOT_TYPE.OBJECT;
this.nativeRoot = json;
}
public void setNativeArray (JsonArray json) {
this.rootType = ROOT_TYPE.ARRAY;
this.nativeRoot = json;
}
@Override
public JsonLikeStructure getInstance() {
return new GsonStructure();
}
@Override
public void load(Reader theReader) throws DataFormatException {
this.load(theReader, false);
}
@Override
public void load(Reader theReader, boolean allowArray) throws DataFormatException {
PushbackReader pbr = new PushbackReader(theReader);
int nextInt;
try {
while(true) {
nextInt = pbr.read();
if (nextInt == -1) {
throw new DataFormatException("Did not find any content to parse");
}
if (nextInt == '{') {
pbr.unread(nextInt);
break;
}
if (Character.isWhitespace(nextInt)) {
continue;
}
if (allowArray) {
if (nextInt == '[') {
pbr.unread(nextInt);
break;
}
throw new DataFormatException("Content does not appear to be FHIR JSON, first non-whitespace character was: '" + (char)nextInt + "' (must be '{' or '[')");
}
throw new DataFormatException("Content does not appear to be FHIR JSON, first non-whitespace character was: '" + (char)nextInt + "' (must be '{')");
}
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
if (nextInt == '{') {
JsonObject root = gson.fromJson(pbr, JsonObject.class);
setNativeObject(root);
} else if (nextInt == '[') {
JsonArray root = gson.fromJson(pbr, JsonArray.class);
setNativeArray(root);
}
} catch (JsonSyntaxException e) {
if (e.getMessage().startsWith("Unexpected char 39")) {
throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage() + " - This may indicate that single quotes are being used as JSON escapes where double quotes are required", e);
}
throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage(), e);
} catch (Exception e) {
throw new DataFormatException("Failed to parse JSON content, error was: " + e.getMessage(), e);
}
}
@Override
public JsonLikeWriter getJsonLikeWriter (Writer writer) {
if (null == jsonLikeWriter) {
jsonLikeWriter = new GsonWriter(writer);
}
return jsonLikeWriter;
}
@Override
public JsonLikeWriter getJsonLikeWriter () {
if (null == jsonLikeWriter) {
jsonLikeWriter = new GsonWriter();
}
return jsonLikeWriter;
}
@Override
public JsonLikeObject getRootObject() throws DataFormatException {
if (rootType == ROOT_TYPE.OBJECT) {
if (null == jsonLikeRoot) {
jsonLikeRoot = new GsonJsonObject((JsonObject)nativeRoot);
}
return jsonLikeRoot.getAsObject();
}
throw new DataFormatException("Content must be a valid JSON Object. It must start with '{'.");
}
@Override
public JsonLikeArray getRootArray() throws DataFormatException {
if (rootType == ROOT_TYPE.ARRAY) {
if (null == jsonLikeRoot) {
jsonLikeRoot = new GsonJsonArray((JsonArray)nativeRoot);
}
return jsonLikeRoot.getAsArray();
}
throw new DataFormatException("Content must be a valid JSON Array. It must start with '['.");
}
private static class GsonJsonObject extends JsonLikeObject {
private JsonObject nativeObject;
private Set<String> keySet = null;
private Map<String,JsonLikeValue> jsonLikeMap = new LinkedHashMap<String,JsonLikeValue>();
public GsonJsonObject (JsonObject json) {
this.nativeObject = json;
}
@Override
public Object getValue() {
return null;
}
@Override
public Set<String> keySet() {
if (null == keySet) {
Set<Entry<String, JsonElement>> entrySet = nativeObject.entrySet();
keySet = new EntryOrderedSet<String>(entrySet.size());
for (Entry<String,?> entry : entrySet) {
keySet.add(entry.getKey());
}
}
return keySet;
}
@Override
public JsonLikeValue get(String key) {
JsonLikeValue result = null;
if (jsonLikeMap.containsKey(key)) {
result = jsonLikeMap.get(key);
} else {
JsonElement child = nativeObject.get(key);
if (child != null) {
result = new GsonJsonValue(child);
}
jsonLikeMap.put(key, result);
}
return result;
}
}
private static class GsonJsonArray extends JsonLikeArray {
private JsonArray nativeArray;
private Map<Integer,JsonLikeValue> jsonLikeMap = new LinkedHashMap<Integer,JsonLikeValue>();
public GsonJsonArray (JsonArray json) {
this.nativeArray = json;
}
@Override
public Object getValue() {
return null;
}
@Override
public int size() {
return nativeArray.size();
}
@Override
public JsonLikeValue get(int index) {
Integer key = Integer.valueOf(index);
JsonLikeValue result = null;
if (jsonLikeMap.containsKey(key)) {
result = jsonLikeMap.get(key);
} else {
JsonElement child = nativeArray.get(index);
if (child != null) {
result = new GsonJsonValue(child);
}
jsonLikeMap.put(key, result);
}
return result;
}
}
private static class GsonJsonValue extends JsonLikeValue {
private JsonElement nativeValue;
private JsonLikeObject jsonLikeObject = null;
private JsonLikeArray jsonLikeArray = null;
public GsonJsonValue (JsonElement json) {
this.nativeValue = json;
}
@Override
public Object getValue() {
if (nativeValue != null && nativeValue.isJsonPrimitive()) {
if (((JsonPrimitive)nativeValue).isNumber()) {
return nativeValue.getAsNumber();
}
if (((JsonPrimitive)nativeValue).isBoolean()) {
return Boolean.valueOf(nativeValue.getAsBoolean());
}
return nativeValue.getAsString();
}
return null;
}
@Override
public ValueType getJsonType() {
if (null == nativeValue || nativeValue.isJsonNull()) {
return ValueType.NULL;
}
if (nativeValue.isJsonObject()) {
return ValueType.OBJECT;
}
if (nativeValue.isJsonArray()) {
return ValueType.ARRAY;
}
if (nativeValue.isJsonPrimitive()) {
return ValueType.SCALAR;
}
return null;
}
@Override
public ScalarType getDataType() {
if (nativeValue != null && nativeValue.isJsonPrimitive()) {
if (((JsonPrimitive)nativeValue).isNumber()) {
return ScalarType.NUMBER;
}
if (((JsonPrimitive)nativeValue).isString()) {
return ScalarType.STRING;
}
if (((JsonPrimitive)nativeValue).isBoolean()) {
return ScalarType.BOOLEAN;
}
}
return null;
}
@Override
public JsonLikeArray getAsArray() {
if (nativeValue != null && nativeValue.isJsonArray()) {
if (null == jsonLikeArray) {
jsonLikeArray = new GsonJsonArray((JsonArray)nativeValue);
}
}
return jsonLikeArray;
}
@Override
public JsonLikeObject getAsObject() {
if (nativeValue != null && nativeValue.isJsonObject()) {
if (null == jsonLikeObject) {
jsonLikeObject = new GsonJsonObject((JsonObject)nativeValue);
}
}
return jsonLikeObject;
}
@Override
public Number getAsNumber() {
return nativeValue != null ? nativeValue.getAsNumber() : null;
}
@Override
public String getAsString() {
return nativeValue != null ? nativeValue.getAsString() : null;
}
@Override
public boolean getAsBoolean() {
if (nativeValue != null && nativeValue.isJsonPrimitive() && ((JsonPrimitive)nativeValue).isBoolean()) {
return nativeValue.getAsBoolean();
}
return super.getAsBoolean();
}
}
private static class EntryOrderedSet<T> extends AbstractSet<T> {
private transient ArrayList<T> data = null;
public EntryOrderedSet (int initialCapacity) {
data = new ArrayList<T>(initialCapacity);
}
@SuppressWarnings("unused")
public EntryOrderedSet () {
data = new ArrayList<T>();
}
@Override
public int size() {
return data.size();
}
@Override
public boolean contains(Object o) {
return data.contains(o);
}
@SuppressWarnings("unused") // not really.. just not here
public T get(int index) {
return data.get(index);
}
@Override
public boolean add(T element) {
if (data.contains(element)) {
return false;
}
return data.add(element);
}
@Override
public boolean remove(Object o) {
return data.remove(o);
}
@Override
public void clear() {
data.clear();
}
@Override
public Iterator<T> iterator() {
return data.iterator();
}
}
}

View File

@ -1,263 +0,0 @@
package ca.uhn.fhir.parser.json;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2020 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 java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Stack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.stream.JsonWriter;
public class GsonWriter extends JsonLikeWriter {
private static final Logger log = LoggerFactory.getLogger(GsonWriter.class);
private JsonWriter eventWriter;
private enum BlockType {
NONE, OBJECT, ARRAY
}
private BlockType blockType = BlockType.NONE;
private Stack<BlockType> blockStack = new Stack<BlockType>();
public GsonWriter () {
super();
}
public GsonWriter (Writer writer) {
setWriter(writer);
}
@Override
public JsonLikeWriter init() throws IOException {
eventWriter = new JsonWriter(getWriter());
eventWriter.setSerializeNulls(true);
if (isPrettyPrint()) {
eventWriter.setIndent(" ");
}
blockType = BlockType.NONE;
blockStack.clear();
return this;
}
@Override
public JsonLikeWriter flush() throws IOException {
if (blockType != BlockType.NONE) {
log.error("JsonLikeStreamWriter.flush() called but JSON document is not finished");
}
eventWriter.flush();
getWriter().flush();
return this;
}
@Override
public void close() throws IOException {
eventWriter.close();
getWriter().close();
}
@Override
public JsonLikeWriter beginObject() throws IOException {
blockStack.push(blockType);
blockType = BlockType.OBJECT;
eventWriter.beginObject();
return this;
}
@Override
public JsonLikeWriter beginArray() throws IOException {
blockStack.push(blockType);
blockType = BlockType.ARRAY;
eventWriter.beginArray();
return this;
}
@Override
public JsonLikeWriter beginObject(String name) throws IOException {
blockStack.push(blockType);
blockType = BlockType.OBJECT;
eventWriter.name(name);
eventWriter.beginObject();
return this;
}
@Override
public JsonLikeWriter beginArray(String name) throws IOException {
blockStack.push(blockType);
blockType = BlockType.ARRAY;
eventWriter.name(name);
eventWriter.beginArray();
return this;
}
@Override
public JsonLikeWriter write(String value) throws IOException {
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(BigInteger value) throws IOException {
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(BigDecimal value) throws IOException {
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(long value) throws IOException {
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(double value) throws IOException {
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(Boolean value) throws IOException {
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(boolean value) throws IOException {
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter writeNull() throws IOException {
eventWriter.nullValue();
return this;
}
@Override
public JsonLikeWriter write(String name, String value) throws IOException {
eventWriter.name(name);
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(String name, BigInteger value) throws IOException {
eventWriter.name(name);
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(String name, BigDecimal value) throws IOException {
eventWriter.name(name);
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(String name, long value) throws IOException {
eventWriter.name(name);
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(String name, double value) throws IOException {
eventWriter.name(name);
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(String name, Boolean value) throws IOException {
eventWriter.name(name);
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter write(String name, boolean value) throws IOException {
eventWriter.name(name);
eventWriter.value(value);
return this;
}
@Override
public JsonLikeWriter writeNull(String name) throws IOException {
eventWriter.name(name);
eventWriter.nullValue();
return this;
}
@Override
public JsonLikeWriter endObject() throws IOException {
if (blockType == BlockType.NONE) {
log.error("JsonLikeStreamWriter.endObject(); called with no active JSON document");
} else {
if (blockType != BlockType.OBJECT) {
log.error("JsonLikeStreamWriter.endObject(); called outside a JSON object. (Use endArray() instead?)");
eventWriter.endArray();
} else {
eventWriter.endObject();
}
blockType = blockStack.pop();
}
return this;
}
@Override
public JsonLikeWriter endArray() throws IOException {
if (blockType == BlockType.NONE) {
log.error("JsonLikeStreamWriter.endArray(); called with no active JSON document");
} else {
if (blockType != BlockType.ARRAY) {
log.error("JsonLikeStreamWriter.endArray(); called outside a JSON array. (Use endObject() instead?)");
eventWriter.endObject();
} else {
eventWriter.endArray();
}
blockType = blockStack.pop();
}
return this;
}
@Override
public JsonLikeWriter endBlock() throws IOException {
if (blockType == BlockType.NONE) {
log.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document");
} else {
if (blockType == BlockType.ARRAY) {
eventWriter.endArray();
} else {
eventWriter.endObject();
}
blockType = blockStack.pop();
}
return this;
}
}

View File

@ -53,20 +53,4 @@ public abstract class JsonLikeObject extends JsonLikeValue {
public abstract JsonLikeValue get (String key); public abstract JsonLikeValue get (String key);
public String getString (String key) {
JsonLikeValue value = this.get(key);
if (null == value) {
throw new NullPointerException("Json object missing element named \""+key+"\"");
}
return value.getAsString();
}
public String getString (String key, String defaultValue) {
String result = defaultValue;
JsonLikeValue value = this.get(key);
if (value != null) {
result = value.getAsString();
}
return result;
}
} }

View File

@ -19,11 +19,12 @@
*/ */
package ca.uhn.fhir.parser.json; package ca.uhn.fhir.parser.json;
import ca.uhn.fhir.parser.DataFormatException;
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import ca.uhn.fhir.parser.DataFormatException;
/** /**
* This interface is the generic representation of any sort of data * This interface is the generic representation of any sort of data
* structure that looks and smells like JSON. These data structures * structure that looks and smells like JSON. These data structures
@ -33,7 +34,7 @@ import ca.uhn.fhir.parser.DataFormatException;
* @author Bill.Denton * @author Bill.Denton
*/ */
public interface JsonLikeStructure { public interface JsonLikeStructure {
public JsonLikeStructure getInstance(); JsonLikeStructure getInstance();
/** /**
* Parse the JSON document into the Json-like structure * Parse the JSON document into the Json-like structure
@ -43,10 +44,13 @@ public interface JsonLikeStructure {
* process the JSON input stream * process the JSON input stream
* @throws DataFormatException when invalid JSON is received * @throws DataFormatException when invalid JSON is received
*/ */
public void load (Reader theReader) throws DataFormatException; void load(Reader theReader) throws DataFormatException;
public void load (Reader theReader, boolean allowArray) throws DataFormatException;
public JsonLikeObject getRootObject () throws DataFormatException; void load(Reader theReader, boolean allowArray) throws DataFormatException;
public JsonLikeArray getRootArray () throws DataFormatException;
public JsonLikeWriter getJsonLikeWriter (); JsonLikeObject getRootObject() throws DataFormatException;
public JsonLikeWriter getJsonLikeWriter (Writer writer);
JsonLikeWriter getJsonLikeWriter();
JsonLikeWriter getJsonLikeWriter(Writer writer) throws IOException;
} }

View File

@ -30,54 +30,72 @@ public abstract class JsonLikeWriter {
private boolean prettyPrint; private boolean prettyPrint;
private Writer writer; private Writer writer;
public JsonLikeWriter() {
super();
}
public boolean isPrettyPrint() {
return prettyPrint;
}
public void setPrettyPrint(boolean tf) { public void setPrettyPrint(boolean tf) {
prettyPrint = tf; prettyPrint = tf;
} }
public boolean isPrettyPrint () {
return prettyPrint; public Writer getWriter() {
return writer;
} }
public void setWriter(Writer writer) { public void setWriter(Writer writer) {
this.writer = writer; this.writer = writer;
} }
public Writer getWriter () {
return writer;
}
public abstract JsonLikeWriter init() throws IOException; public abstract JsonLikeWriter init() throws IOException;
public abstract JsonLikeWriter flush() throws IOException; public abstract JsonLikeWriter flush() throws IOException;
public abstract void close() throws IOException; public abstract void close() throws IOException;
public abstract JsonLikeWriter beginObject() throws IOException; public abstract JsonLikeWriter beginObject() throws IOException;
public abstract JsonLikeWriter beginArray () throws IOException;
public abstract JsonLikeWriter beginObject(String name) throws IOException; public abstract JsonLikeWriter beginObject(String name) throws IOException;
public abstract JsonLikeWriter beginArray(String name) throws IOException; public abstract JsonLikeWriter beginArray(String name) throws IOException;
public abstract JsonLikeWriter write(String value) throws IOException; public abstract JsonLikeWriter write(String value) throws IOException;
public abstract JsonLikeWriter write(BigInteger value) throws IOException; public abstract JsonLikeWriter write(BigInteger value) throws IOException;
public abstract JsonLikeWriter write(BigDecimal value) throws IOException; public abstract JsonLikeWriter write(BigDecimal value) throws IOException;
public abstract JsonLikeWriter write(long value) throws IOException; public abstract JsonLikeWriter write(long value) throws IOException;
public abstract JsonLikeWriter write(double value) throws IOException; public abstract JsonLikeWriter write(double value) throws IOException;
public abstract JsonLikeWriter write(Boolean value) throws IOException; public abstract JsonLikeWriter write(Boolean value) throws IOException;
public abstract JsonLikeWriter write(boolean value) throws IOException; public abstract JsonLikeWriter write(boolean value) throws IOException;
public abstract JsonLikeWriter writeNull() throws IOException; public abstract JsonLikeWriter writeNull() throws IOException;
public abstract JsonLikeWriter write(String name, String value) throws IOException; public abstract JsonLikeWriter write(String name, String value) throws IOException;
public abstract JsonLikeWriter write(String name, BigInteger value) throws IOException; public abstract JsonLikeWriter write(String name, BigInteger value) throws IOException;
public abstract JsonLikeWriter write(String name, BigDecimal value) throws IOException; public abstract JsonLikeWriter write(String name, BigDecimal value) throws IOException;
public abstract JsonLikeWriter write(String name, long value) throws IOException; public abstract JsonLikeWriter write(String name, long value) throws IOException;
public abstract JsonLikeWriter write(String name, double value) throws IOException; public abstract JsonLikeWriter write(String name, double value) throws IOException;
public abstract JsonLikeWriter write(String name, Boolean value) throws IOException; public abstract JsonLikeWriter write(String name, Boolean value) throws IOException;
public abstract JsonLikeWriter write(String name, boolean value) throws IOException; public abstract JsonLikeWriter write(String name, boolean value) throws IOException;
public abstract JsonLikeWriter writeNull (String name) throws IOException;
public abstract JsonLikeWriter endObject() throws IOException; public abstract JsonLikeWriter endObject() throws IOException;
public abstract JsonLikeWriter endArray() throws IOException; public abstract JsonLikeWriter endArray() throws IOException;
public abstract JsonLikeWriter endBlock() throws IOException; public abstract JsonLikeWriter endBlock() throws IOException;
public JsonLikeWriter() {
super();
}
} }

View File

@ -0,0 +1,372 @@
package ca.uhn.fhir.parser.json.jackson;
import ca.uhn.fhir.parser.DataFormatException;
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 com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.DecimalNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.jena.tdb.setup.BuilderStdDB;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
public class JacksonStructure implements JsonLikeStructure {
private static final ObjectMapper OBJECT_MAPPER = createObjectMapper();
private JacksonWriter jacksonWriter;
private ROOT_TYPE rootType = null;
private JsonNode nativeRoot = null;
private JsonNode jsonLikeRoot = null;
public void setNativeObject(ObjectNode objectNode) {
this.rootType = ROOT_TYPE.OBJECT;
this.nativeRoot = objectNode;
}
public void setNativeArray(ArrayNode arrayNode) {
this.rootType = ROOT_TYPE.ARRAY;
this.nativeRoot = arrayNode;
}
@Override
public JsonLikeStructure getInstance() {
return new JacksonStructure();
}
@Override
public void load(Reader theReader) throws DataFormatException {
this.load(theReader, false);
}
@Override
public void load(Reader theReader, boolean allowArray) throws DataFormatException {
PushbackReader pbr = new PushbackReader(theReader);
int nextInt;
try {
while (true) {
nextInt = pbr.read();
if (nextInt == -1) {
throw new DataFormatException("Did not find any content to parse");
}
if (nextInt == '{') {
pbr.unread(nextInt);
break;
}
if (Character.isWhitespace(nextInt)) {
continue;
}
if (allowArray) {
if (nextInt == '[') {
pbr.unread(nextInt);
break;
}
throw new DataFormatException("Content does not appear to be FHIR JSON, first non-whitespace character was: '" + (char) nextInt + "' (must be '{' or '[')");
}
throw new DataFormatException("Content does not appear to be FHIR JSON, first non-whitespace character was: '" + (char) nextInt + "' (must be '{')");
}
if (nextInt == '{') {
setNativeObject((ObjectNode) OBJECT_MAPPER.readTree(pbr));
} else {
setNativeArray((ArrayNode) OBJECT_MAPPER.readTree(pbr));
}
} catch (Exception e) {
if (e.getMessage().startsWith("Unexpected char 39")) {
throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage() + " - " +
"This may indicate that single quotes are being used as JSON escapes where double quotes are required", e);
}
throw new DataFormatException("Failed to parse JSON encoded FHIR content: " + e.getMessage(), e);
}
}
@Override
public JsonLikeWriter getJsonLikeWriter(Writer writer) throws IOException {
if (null == jacksonWriter) {
jacksonWriter = new JacksonWriter(OBJECT_MAPPER.getFactory(), writer);
}
return jacksonWriter;
}
@Override
public JsonLikeWriter getJsonLikeWriter() {
if (null == jacksonWriter) {
jacksonWriter = new JacksonWriter();
}
return jacksonWriter;
}
@Override
public JsonLikeObject getRootObject() throws DataFormatException {
if (rootType == ROOT_TYPE.OBJECT) {
if (null == jsonLikeRoot) {
jsonLikeRoot = nativeRoot;
}
return new JacksonJsonObject((ObjectNode) jsonLikeRoot);
}
throw new DataFormatException("Content must be a valid JSON Object. It must start with '{'.");
}
private enum ROOT_TYPE {OBJECT, ARRAY}
private static class JacksonJsonObject extends JsonLikeObject {
private final ObjectNode nativeObject;
private final Map<String, JsonLikeValue> jsonLikeMap = new LinkedHashMap<>();
private Set<String> keySet = null;
public JacksonJsonObject(ObjectNode json) {
this.nativeObject = json;
}
@Override
public Object getValue() {
return null;
}
@Override
public Set<String> keySet() {
if (null == keySet) {
final Iterable<Map.Entry<String, JsonNode>> iterable = nativeObject::fields;
keySet = StreamSupport.stream(iterable.spliterator(), false)
.map(Map.Entry::getKey)
.collect(Collectors.toCollection(EntryOrderedSet::new));
}
return keySet;
}
@Override
public JsonLikeValue get(String key) {
JsonLikeValue result = null;
if (jsonLikeMap.containsKey(key)) {
result = jsonLikeMap.get(key);
} else {
JsonNode child = nativeObject.get(key);
if (child != null) {
result = new JacksonJsonValue(child);
}
jsonLikeMap.put(key, result);
}
return result;
}
}
private static class EntryOrderedSet<T> extends AbstractSet<T> {
private final transient ArrayList<T> data;
public EntryOrderedSet() {
data = new ArrayList<>();
}
@Override
public int size() {
return data.size();
}
@Override
public boolean contains(Object o) {
return data.contains(o);
}
public T get(int index) {
return data.get(index);
}
@Override
public boolean add(T element) {
if (data.contains(element)) {
return false;
}
return data.add(element);
}
@Override
public boolean remove(Object o) {
return data.remove(o);
}
@Override
public void clear() {
data.clear();
}
@Override
public Iterator<T> iterator() {
return data.iterator();
}
}
private static class JacksonJsonArray extends JsonLikeArray {
private final ArrayNode nativeArray;
private final Map<Integer, JsonLikeValue> jsonLikeMap = new LinkedHashMap<Integer, JsonLikeValue>();
public JacksonJsonArray(ArrayNode json) {
this.nativeArray = json;
}
@Override
public Object getValue() {
return null;
}
@Override
public int size() {
return nativeArray.size();
}
@Override
public JsonLikeValue get(int index) {
Integer key = index;
JsonLikeValue result = null;
if (jsonLikeMap.containsKey(key)) {
result = jsonLikeMap.get(key);
} else {
JsonNode child = nativeArray.get(index);
if (child != null) {
result = new JacksonJsonValue(child);
}
jsonLikeMap.put(key, result);
}
return result;
}
}
private static class JacksonJsonValue extends JsonLikeValue {
private final JsonNode nativeValue;
private JsonLikeObject jsonLikeObject = null;
private JsonLikeArray jsonLikeArray = null;
public JacksonJsonValue(JsonNode jsonNode) {
this.nativeValue = jsonNode;
}
@Override
public Object getValue() {
if (nativeValue != null && nativeValue.isValueNode()) {
if (nativeValue.isNumber()) {
return nativeValue.numberValue();
}
if (nativeValue.isBoolean()) {
return nativeValue.booleanValue();
}
return nativeValue.asText();
}
return null;
}
@Override
public ValueType getJsonType() {
if (null == nativeValue || nativeValue.isNull()) {
return ValueType.NULL;
}
if (nativeValue.isObject()) {
return ValueType.OBJECT;
}
if (nativeValue.isArray()) {
return ValueType.ARRAY;
}
if (nativeValue.isValueNode()) {
return ValueType.SCALAR;
}
return null;
}
@Override
public ScalarType getDataType() {
if (nativeValue != null && nativeValue.isValueNode()) {
if (nativeValue.isNumber()) {
return ScalarType.NUMBER;
}
if (nativeValue.isTextual()) {
return ScalarType.STRING;
}
if (nativeValue.isBoolean()) {
return ScalarType.BOOLEAN;
}
}
return null;
}
@Override
public JsonLikeArray getAsArray() {
if (nativeValue != null && nativeValue.isArray()) {
if (null == jsonLikeArray) {
jsonLikeArray = new JacksonJsonArray((ArrayNode) nativeValue);
}
}
return jsonLikeArray;
}
@Override
public JsonLikeObject getAsObject() {
if (nativeValue != null && nativeValue.isObject()) {
if (null == jsonLikeObject) {
jsonLikeObject = new JacksonJsonObject((ObjectNode) nativeValue);
}
}
return jsonLikeObject;
}
@Override
public Number getAsNumber() {
return nativeValue != null ? nativeValue.numberValue() : null;
}
@Override
public String getAsString() {
if (nativeValue != null) {
if (nativeValue instanceof DecimalNode) {
BigDecimal value = nativeValue.decimalValue();
return value.toPlainString();
}
return nativeValue.asText();
}
return null;
}
@Override
public boolean getAsBoolean() {
if (nativeValue != null && nativeValue.isValueNode() && nativeValue.isBoolean()) {
return nativeValue.asBoolean();
}
return super.getAsBoolean();
}
}
private static ObjectMapper createObjectMapper() {
ObjectMapper retVal = new ObjectMapper();
retVal = retVal.setNodeFactory(new JsonNodeFactory(true));
retVal = retVal.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
retVal = retVal.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
retVal = retVal.disable(JsonParser.Feature.INCLUDE_SOURCE_IN_LOCATION);
retVal = retVal.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
retVal = retVal.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
retVal = retVal.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
return retVal;
}
}

View File

@ -0,0 +1,197 @@
package ca.uhn.fhir.parser.json.jackson;
import ca.uhn.fhir.parser.json.JsonLikeWriter;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.Separators;
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
public class JacksonWriter extends JsonLikeWriter {
private JsonGenerator myJsonGenerator;
public JacksonWriter(JsonFactory theJsonFactory, Writer theWriter) throws IOException {
myJsonGenerator = theJsonFactory.createGenerator(theWriter);
setWriter(theWriter);
}
public JacksonWriter() {
}
@Override
public JsonLikeWriter init() {
if (isPrettyPrint()) {
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter() {
/**
* Objects should serialize as
* <pre>
* {
* "key": "value"
* }
* </pre>
* in order to be consistent with Gson behaviour, instead of the jackson default
* <pre>
* {
* "key" : "value"
* }
* </pre>
*/
@Override
public DefaultPrettyPrinter withSeparators(Separators separators) {
_separators = separators;
_objectFieldValueSeparatorWithSpaces = separators.getObjectFieldValueSeparator() + " ";
return this;
}
};
prettyPrinter = prettyPrinter.withObjectIndenter(new DefaultIndenter(" ", "\n"));
myJsonGenerator.setPrettyPrinter(prettyPrinter);
}
return this;
}
@Override
public JsonLikeWriter flush() {
return this;
}
@Override
public void close() throws IOException {
myJsonGenerator.close();
}
@Override
public JsonLikeWriter beginObject() throws IOException {
myJsonGenerator.writeStartObject();
return this;
}
@Override
public JsonLikeWriter beginObject(String name) throws IOException {
myJsonGenerator.writeObjectFieldStart(name);
return this;
}
@Override
public JsonLikeWriter beginArray(String name) throws IOException {
myJsonGenerator.writeArrayFieldStart(name);
return this;
}
@Override
public JsonLikeWriter write(String value) throws IOException {
myJsonGenerator.writeObject(value);
return this;
}
@Override
public JsonLikeWriter write(BigInteger value) throws IOException {
myJsonGenerator.writeObject(value);
return this;
}
@Override
public JsonLikeWriter write(BigDecimal value) throws IOException {
myJsonGenerator.writeObject(value);
return this;
}
@Override
public JsonLikeWriter write(long value) throws IOException {
myJsonGenerator.writeObject(value);
return this;
}
@Override
public JsonLikeWriter write(double value) throws IOException {
myJsonGenerator.writeObject(value);
return this;
}
@Override
public JsonLikeWriter write(Boolean value) throws IOException {
myJsonGenerator.writeObject(value);
return this;
}
@Override
public JsonLikeWriter write(boolean value) throws IOException {
myJsonGenerator.writeObject(value);
return this;
}
@Override
public JsonLikeWriter writeNull() throws IOException {
myJsonGenerator.writeNull();
return this;
}
@Override
public JsonLikeWriter write(String name, String value) throws IOException {
myJsonGenerator.writeObjectField(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, BigInteger value) throws IOException {
myJsonGenerator.writeObjectField(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, BigDecimal value) throws IOException {
myJsonGenerator.writeObjectField(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, long value) throws IOException {
myJsonGenerator.writeObjectField(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, double value) throws IOException {
myJsonGenerator.writeObjectField(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, Boolean value) throws IOException {
myJsonGenerator.writeObjectField(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, boolean value) throws IOException {
myJsonGenerator.writeObjectField(name, value);
return this;
}
@Override
public JsonLikeWriter endObject() throws IOException {
myJsonGenerator.writeEndObject();
return this;
}
@Override
public JsonLikeWriter endArray() throws IOException {
myJsonGenerator.writeEndArray();
return this;
}
@Override
public JsonLikeWriter endBlock() throws IOException {
myJsonGenerator.writeEndObject();
return this;
}
}

View File

@ -5,6 +5,7 @@ import static org.junit.Assert.assertNotNull;
import java.io.StringReader; import java.io.StringReader;
import ca.uhn.fhir.parser.json.jackson.JacksonStructure;
import org.junit.Test; import org.junit.Test;
public class JsonLikeStructureTest { public class JsonLikeStructureTest {
@ -39,7 +40,7 @@ public class JsonLikeStructureTest {
@Test @Test
public void testStructureLoading() { public void testStructureLoading() {
StringReader reader = new StringReader(TEST_STRUCTURELOADING_DATA); StringReader reader = new StringReader(TEST_STRUCTURELOADING_DATA);
JsonLikeStructure jsonStructure = new GsonStructure(); JsonLikeStructure jsonStructure = new JacksonStructure();
jsonStructure.load(reader); jsonStructure.load(reader);
JsonLikeObject rootObject = jsonStructure.getRootObject(); JsonLikeObject rootObject = jsonStructure.getRootObject();
@ -70,7 +71,7 @@ public class JsonLikeStructureTest {
@Test @Test
public void testJsonAndDataTypes() { public void testJsonAndDataTypes() {
StringReader reader = new StringReader(TEST_JSONTYPES_DATA); StringReader reader = new StringReader(TEST_JSONTYPES_DATA);
JsonLikeStructure jsonStructure = new GsonStructure(); JsonLikeStructure jsonStructure = new JacksonStructure();
jsonStructure.load(reader); jsonStructure.load(reader);
JsonLikeObject rootObject = jsonStructure.getRootObject(); JsonLikeObject rootObject = jsonStructure.getRootObject();

View File

@ -5368,7 +5368,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
@Test @Test
public void testValidateJsonWithDuplicateKey() throws IOException { public void testValidateJsonWithDuplicateKey() throws IOException {
String inputStr = "{\"resourceType\":\"Patient\", \"name\":[{\"text\":foo\"}], name:[{\"text\":\"foo\"}] }"; String inputStr = "{\"resourceType\":\"Patient\", \"name\":[{\"text\":\"foo\"}], \"name\":[{\"text\":\"foo\"}] }";
HttpPost post = new HttpPost(ourServerBase + "/Patient/$validate"); HttpPost post = new HttpPost(ourServerBase + "/Patient/$validate");
post.setEntity(new StringEntity(inputStr, ContentType.create(Constants.CT_FHIR_JSON_NEW, "UTF-8"))); post.setEntity(new StringEntity(inputStr, ContentType.create(Constants.CT_FHIR_JSON_NEW, "UTF-8")));
@ -5378,7 +5378,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
ourLog.info(resp); ourLog.info(resp);
assertEquals(412, response.getStatusLine().getStatusCode()); assertEquals(412, response.getStatusLine().getStatusCode());
assertThat(resp, stringContainsInOrder("Error parsing JSON source: Syntax error in json reading special word false at Line 1")); assertThat(resp, stringContainsInOrder("Duplicated property name: name"));
} finally { } finally {
response.getEntity().getContent().close(); response.getEntity().getContent().close();
response.close(); response.close();

View File

@ -1518,13 +1518,13 @@ public class JsonParserDstu2_1Test {
ourCtx.newJsonParser().parseResource("FOO"); ourCtx.newJsonParser().parseResource("FOO");
fail(); fail();
} catch (DataFormatException e) { } catch (DataFormatException e) {
assertEquals("Failed to parse JSON content, error was: Content does not appear to be FHIR JSON, first non-whitespace character was: 'F' (must be '{')", e.getMessage()); assertEquals("Failed to parse JSON encoded FHIR content: Content does not appear to be FHIR JSON, first non-whitespace character was: 'F' (must be '{')", e.getMessage());
} }
try { try {
ourCtx.newJsonParser().parseResource("[\"aaa\"]"); ourCtx.newJsonParser().parseResource("[\"aaa\"]");
fail(); fail();
} catch (DataFormatException e) { } catch (DataFormatException e) {
assertEquals("Failed to parse JSON content, error was: Content does not appear to be FHIR JSON, first non-whitespace character was: '[' (must be '{')", e.getMessage()); assertEquals("Failed to parse JSON encoded FHIR content: Content does not appear to be FHIR JSON, first non-whitespace character was: '[' (must be '{')", e.getMessage());
} }
assertEquals(Bundle.class, ourCtx.newJsonParser().parseResource(" {\"resourceType\" : \"Bundle\"}").getClass()); assertEquals(Bundle.class, ourCtx.newJsonParser().parseResource(" {\"resourceType\" : \"Bundle\"}").getClass());

View File

@ -1999,37 +1999,23 @@ public class XmlParserDstu2_1Test {
" \"resourceType\": \"Patient\",", " \"resourceType\": \"Patient\",",
" \"id\": \"someid\",", " \"id\": \"someid\",",
" \"_id\": {", " \"_id\": {",
" \"fhir_comments\": [", " \"fhir_comments\": [ \" comment 1 \" ]",
" \" comment 1 \"",
" ]",
" },", " },",
" \"extension\": [", " \"extension\": [ {",
" {", " \"fhir_comments\": [ \" comment 2 \", \" comment 7 \" ],",
" \"fhir_comments\": [",
" \" comment 2 \",",
" \" comment 7 \"",
" ],",
" \"url\": \"urn:patientext:att\",", " \"url\": \"urn:patientext:att\",",
" \"valueAttachment\": {", " \"valueAttachment\": {",
" \"fhir_comments\": [", " \"fhir_comments\": [ \" comment 3 \", \" comment 6 \" ],",
" \" comment 3 \",",
" \" comment 6 \"",
" ],",
" \"contentType\": \"aaaa\",", " \"contentType\": \"aaaa\",",
" \"_contentType\": {", " \"_contentType\": {",
" \"fhir_comments\": [", " \"fhir_comments\": [ \" comment 4 \" ]",
" \" comment 4 \"",
" ]",
" },", " },",
" \"data\": \"AAAA\",", " \"data\": \"AAAA\",",
" \"_data\": {", " \"_data\": {",
" \"fhir_comments\": [", " \"fhir_comments\": [ \" comment 5 \" ]",
" \" comment 5 \"",
" ]",
" }", " }",
" }", " }",
" }", " } ]",
" ]",
"}" "}"
)); ));

View File

@ -498,37 +498,28 @@ public class JsonParserDstu2Test {
String enc = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p); String enc = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(enc); ourLog.info(enc);
//@formatter:off
String actual = enc.trim(); String actual = enc.trim();
ourLog.info("Actual:\n{}", actual); ourLog.info("Actual:\n{}", actual);
assertEquals("{\n" + assertThat(actual, stringContainsInOrder("{",
" \"resourceType\": \"Patient\",\n" + " \"resourceType\": \"Patient\",",
" \"meta\": {\n" + " \"meta\": {",
" \"security\": [\n" + " \"security\": [ {",
" {\n" + " \"system\": \"SYSTEM1\",",
" \"system\": \"SYSTEM1\",\n" + " \"version\": \"VERSION1\",",
" \"version\": \"VERSION1\",\n" + " \"code\": \"CODE1\",",
" \"code\": \"CODE1\",\n" + " \"display\": \"DISPLAY1\"",
" \"display\": \"DISPLAY1\"\n" + " }, {",
" },\n" + " \"system\": \"SYSTEM2\",",
" {\n" + " \"version\": \"VERSION2\",",
" \"system\": \"SYSTEM2\",\n" + " \"code\": \"CODE2\",",
" \"version\": \"VERSION2\",\n" + " \"display\": \"DISPLAY2\"",
" \"code\": \"CODE2\",\n" + " } ]",
" \"display\": \"DISPLAY2\"\n" + " },",
" }\n" + " \"name\": [ {",
" ]\n" + " \"family\": [ \"FAMILY\" ]",
" },\n" + " } ]",
" \"name\": [\n" + "}"));
" {\n" +
" \"family\": [\n" +
" \"FAMILY\"\n" +
" ]\n" +
" }\n" +
" ]\n" +
"}", actual);
//@formatter:on
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, enc); Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, enc);
List<BaseCodingDt> gotLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(parsed); List<BaseCodingDt> gotLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(parsed);

View File

@ -1,16 +1,15 @@
package ca.uhn.fhir.parser.jsonlike; package ca.uhn.fhir.parser.jsonlike;
import java.io.StringReader; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IJsonLikeParser;
import ca.uhn.fhir.parser.json.JsonLikeStructure;
import ca.uhn.fhir.parser.json.jackson.JacksonStructure;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import java.io.StringReader;
import ca.uhn.fhir.parser.IJsonLikeParser;
import ca.uhn.fhir.parser.json.GsonStructure;
import ca.uhn.fhir.parser.json.JsonLikeStructure;
import ca.uhn.fhir.util.TestUtil;
public class JsonLikeParserDstu2Test { public class JsonLikeParserDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2(); private static FhirContext ourCtx = FhirContext.forDstu2();
@ -28,7 +27,7 @@ public class JsonLikeParserDstu2Test {
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed); String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(encoded); ourLog.info(encoded);
JsonLikeStructure jsonLikeStructure = new GsonStructure(); JsonLikeStructure jsonLikeStructure = new JacksonStructure();
jsonLikeStructure.load(new StringReader(encoded)); jsonLikeStructure.load(new StringReader(encoded));
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser(); IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();

View File

@ -72,7 +72,8 @@ public class JsonParserDstu3Test {
p.parseResource(input); p.parseResource(input);
fail(); fail();
} catch (DataFormatException e) { } catch (DataFormatException e) {
assertEquals("Found incorrect type for element subject - Expected OBJECT and found SCALAR (STRING)", e.getMessage()); assertEquals("Failed to parse JSON encoded FHIR content: Unexpected character ('=' (code 61)): was expecting a colon to separate field name and value\n" +
" at [Source: UNKNOWN; line: 4, column: 18]", e.getMessage());
} }
} }
@ -488,32 +489,25 @@ public class JsonParserDstu3Test {
String enc = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p); String enc = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(enc); ourLog.info(enc);
//@formatter:off assertThat(enc.trim(), stringContainsInOrder("{",
assertEquals("{\n" + " \"resourceType\": \"Patient\",",
" \"resourceType\": \"Patient\",\n" + " \"meta\": {",
" \"meta\": {\n" + " \"security\": [ {",
" \"security\": [\n" + " \"system\": \"SYSTEM1\",",
" {\n" + " \"version\": \"VERSION1\",",
" \"system\": \"SYSTEM1\",\n" + " \"code\": \"CODE1\",",
" \"version\": \"VERSION1\",\n" + " \"display\": \"DISPLAY1\"",
" \"code\": \"CODE1\",\n" + " }, {",
" \"display\": \"DISPLAY1\"\n" + " \"system\": \"SYSTEM2\",",
" },\n" + " \"version\": \"VERSION2\",",
" {\n" + " \"code\": \"CODE2\",",
" \"system\": \"SYSTEM2\",\n" + " \"display\": \"DISPLAY2\"",
" \"version\": \"VERSION2\",\n" + " } ]",
" \"code\": \"CODE2\",\n" + " },",
" \"display\": \"DISPLAY2\"\n" + " \"name\": [ {",
" }\n" + " \"family\": \"FAMILY\"",
" ]\n" + " } ]",
" },\n" + "}"));
" \"name\": [\n" +
" {\n" +
" \"family\": \"FAMILY\"\n" +
" }\n" +
" ]\n" +
"}", enc.trim());
//@formatter:on
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, enc); Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, enc);
List<Coding> gotLabels = parsed.getMeta().getSecurity(); List<Coding> gotLabels = parsed.getMeta().getSecurity();
@ -1401,7 +1395,8 @@ public class JsonParserDstu3Test {
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}"; String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input); Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
assertEquals("0.0000000000000001", ((Quantity) obs.getValue()).getValueElement().getValueAsString()); DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement();
assertEquals("0.0000000000000001", valueElement.getValueAsString());
String str = ourCtx.newJsonParser().encodeResourceToString(obs); String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str); ourLog.info(str);
@ -1993,13 +1988,13 @@ public class JsonParserDstu3Test {
ourCtx.newJsonParser().parseResource("FOO"); ourCtx.newJsonParser().parseResource("FOO");
fail(); fail();
} catch (DataFormatException e) { } catch (DataFormatException e) {
assertEquals("Failed to parse JSON content, error was: Content does not appear to be FHIR JSON, first non-whitespace character was: 'F' (must be '{')", e.getMessage()); assertEquals("Failed to parse JSON encoded FHIR content: Content does not appear to be FHIR JSON, first non-whitespace character was: 'F' (must be '{')", e.getMessage());
} }
try { try {
ourCtx.newJsonParser().parseResource("[\"aaa\"]"); ourCtx.newJsonParser().parseResource("[\"aaa\"]");
fail(); fail();
} catch (DataFormatException e) { } catch (DataFormatException e) {
assertEquals("Failed to parse JSON content, error was: Content does not appear to be FHIR JSON, first non-whitespace character was: '[' (must be '{')", e.getMessage()); assertEquals("Failed to parse JSON encoded FHIR content: Content does not appear to be FHIR JSON, first non-whitespace character was: '[' (must be '{')", e.getMessage());
} }
assertEquals(Bundle.class, ourCtx.newJsonParser().parseResource(" {\"resourceType\" : \"Bundle\"}").getClass()); assertEquals(Bundle.class, ourCtx.newJsonParser().parseResource(" {\"resourceType\" : \"Bundle\"}").getClass());
@ -2221,25 +2216,47 @@ public class JsonParserDstu3Test {
@Test @Test
public void testParseWithPrecision() { public void testParseWithPrecision() {
// BigDecimal d0 = new BigDecimal("0.1");
// BigDecimal d1 = new BigDecimal("0.1000");
//
// ourLog.info("Value: {}", d0);
// ourLog.info("Value: {}", d1);
{
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0100}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement();
assertEquals("0.0100", valueElement.getValueAsString());
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0100}}", str);
}
{
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}"; String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input); Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement(); DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement();
assertEquals("0.000000000000000100", valueElement.getValueAsString()); assertEquals("0.000000000000000100", valueElement.getValueAsString());
String str = ourCtx.newJsonParser().encodeResourceToString(obs); String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str); ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str); assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
} }
}
@Test(expected = DataFormatException.class) @Test
public void testParseWithTrailingContent() { public void testParseWithTrailingContent() {
String bundle = "{\n" + String bundle = "{\n" +
" \"resourceType\": \"Bundle\",\n" + " \"resourceType\": \"Bundle\",\n" +
" \"total\": 1\n" + " \"total\": 1\n" +
"}}"; "}}";
try {
ourCtx.newJsonParser().parseResource(Bundle.class, bundle); ourCtx.newJsonParser().parseResource(Bundle.class, bundle);
fail();
} catch (DataFormatException e) {
assertEquals("Failed to parse JSON encoded FHIR content: Unexpected close marker '}': expected ']' (for root starting at [Source: UNKNOWN; line: 1, column: 0])\n" +
" at [Source: UNKNOWN; line: 4, column: 3]", e.getMessage());
}
} }
@Test @Test

View File

@ -2508,42 +2508,27 @@ public class XmlParserDstu3Test {
output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(pat); output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(pat);
ourLog.info(output); ourLog.info(output);
assertThat(output, stringContainsInOrder( assertThat(output, stringContainsInOrder("{",
"{",
" \"resourceType\": \"Patient\",", " \"resourceType\": \"Patient\",",
" \"id\": \"someid\",", " \"id\": \"someid\",",
" \"_id\": {", " \"_id\": {",
" \"fhir_comments\": [", " \"fhir_comments\": [ \" comment 1 \" ]",
" \" comment 1 \"",
" ]",
" },", " },",
" \"extension\": [", " \"extension\": [ {",
" {", " \"fhir_comments\": [ \" comment 2 \", \" comment 7 \" ],",
" \"fhir_comments\": [",
" \" comment 2 \",",
" \" comment 7 \"",
" ],",
" \"url\": \"urn:patientext:att\",", " \"url\": \"urn:patientext:att\",",
" \"valueAttachment\": {", " \"valueAttachment\": {",
" \"fhir_comments\": [", " \"fhir_comments\": [ \" comment 3 \", \" comment 6 \" ],",
" \" comment 3 \",",
" \" comment 6 \"",
" ],",
" \"contentType\": \"aaaa\",", " \"contentType\": \"aaaa\",",
" \"_contentType\": {", " \"_contentType\": {",
" \"fhir_comments\": [", " \"fhir_comments\": [ \" comment 4 \" ]",
" \" comment 4 \"",
" ]",
" },", " },",
" \"data\": \"AAAA\",", " \"data\": \"AAAA\",",
" \"_data\": {", " \"_data\": {",
" \"fhir_comments\": [", " \"fhir_comments\": [ \" comment 5 \" ]",
" \" comment 5 \"",
" ]",
" }", " }",
" }", " }",
" }", " } ]",
" ]",
"}")); "}"));
} }

View File

@ -1,5 +1,19 @@
package ca.uhn.fhir.parser.jsonlike; package ca.uhn.fhir.parser.jsonlike;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IJsonLikeParser;
import ca.uhn.fhir.parser.json.JsonLikeStructure;
import ca.uhn.fhir.parser.json.JsonLikeWriter;
import ca.uhn.fhir.parser.json.jackson.JacksonStructure;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Reference;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -10,22 +24,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Stack; import java.util.Stack;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Extension;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Reference;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IJsonLikeParser;
import ca.uhn.fhir.parser.json.GsonStructure;
import ca.uhn.fhir.parser.json.JsonLikeStructure;
import ca.uhn.fhir.parser.json.JsonLikeWriter;
import ca.uhn.fhir.util.TestUtil;
public class JsonLikeParserDstu3Test { public class JsonLikeParserDstu3Test {
private static FhirContext ourCtx = FhirContext.forDstu3(); private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserDstu3Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserDstu3Test.class);
@ -42,7 +40,7 @@ public class JsonLikeParserDstu3Test {
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed); String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(encoded); ourLog.info(encoded);
JsonLikeStructure jsonLikeStructure = new GsonStructure(); JsonLikeStructure jsonLikeStructure = new JacksonStructure();
jsonLikeStructure.load(new StringReader(encoded)); jsonLikeStructure.load(new StringReader(encoded));
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser(); IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();
@ -192,17 +190,6 @@ public class JsonLikeParserDstu3Test {
return this; return this;
} }
@Override
public JsonLikeWriter beginArray() throws IOException {
if (currentBlock.getType() == BlockType.NONE) {
throw new IOException("JsonLikeStreamWriter.beginArray() called but only beginObject() is allowed here.");
}
blockStack.push(currentBlock);
currentBlock = new Block(BlockType.ARRAY);
currentBlock.setArray(new ArrayList<Object>());
return this;
}
@Override @Override
public JsonLikeWriter beginObject(String name) throws IOException { public JsonLikeWriter beginObject(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) { if (currentBlock.getType() == BlockType.ARRAY) {
@ -363,15 +350,6 @@ public class JsonLikeParserDstu3Test {
return this; return this;
} }
@Override
public JsonLikeWriter writeNull(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, null);
return this;
}
@Override @Override
public JsonLikeWriter endObject() throws IOException { public JsonLikeWriter endObject() throws IOException {
if (currentBlock.getType() == BlockType.NONE) { if (currentBlock.getType() == BlockType.NONE) {
@ -399,7 +377,7 @@ public class JsonLikeParserDstu3Test {
} }
@Override @Override
public JsonLikeWriter endBlock() throws IOException { public JsonLikeWriter endBlock() {
if (currentBlock.getType() == BlockType.NONE) { if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document"); ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document");
} else { } else {

View File

@ -1097,12 +1097,6 @@ public class JsonParserHl7OrgDstu2Test {
assertEquals("idsystem", p.getIdentifier().get(0).getSystem()); assertEquals("idsystem", p.getIdentifier().get(0).getSystem());
} }
@Test
public void testParseSingleQuotes() {
ourCtx.newJsonParser().parseResource(Bundle.class, "{ \"resourceType\": \"Bundle\" }");
ourCtx.newJsonParser().parseResource(Bundle.class, "{ 'resourceType': 'Bundle' }");
}
/** /**
* HAPI FHIR < 0.6 incorrectly used "resource" instead of "reference" * HAPI FHIR < 0.6 incorrectly used "resource" instead of "reference"
*/ */

View File

@ -175,6 +175,11 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<!-- Dependencies for Schematron --> <!-- Dependencies for Schematron -->
<dependency> <dependency>
@ -215,9 +220,8 @@
<!-- UNIT TEST DEPENDENCIES --> <!-- UNIT TEST DEPENDENCIES -->
<dependency> <dependency>
<groupId>org.apache.jena</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>apache-jena-libs</artifactId> <artifactId>gson</artifactId>
<type>pom</type>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -248,6 +248,12 @@ public class JsonParserR4Test extends BaseTest {
} }
@Test
public void testParseSingleQuotes() {
Bundle bundle = ourCtx.newJsonParser().parseResource(Bundle.class, "{ 'resourceType': 'Bundle', 'id': '123' }");
assertEquals("123", bundle.getIdElement().getIdPart());
}
@Test @Test
public void testEncodeBinary() { public void testEncodeBinary() {
@ -260,6 +266,18 @@ public class JsonParserR4Test extends BaseTest {
assertEquals("{\"resourceType\":\"Binary\",\"contentType\":\"application/octet-stream\",\"data\":\"AAECAwQ=\"}", output); assertEquals("{\"resourceType\":\"Binary\",\"contentType\":\"application/octet-stream\",\"data\":\"AAECAwQ=\"}", output);
} }
@Test
public void testAlwaysUseUnixNewlines() {
Patient p = new Patient();
p.setId("1");
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
assertEquals("{\n" +
" \"resourceType\": \"Patient\",\n" +
" \"id\": \"1\"\n" +
"}", encoded);
}
@Test @Test
public void testEncodeWithInvalidExtensionMissingUrl() { public void testEncodeWithInvalidExtensionMissingUrl() {
@ -586,6 +604,14 @@ public class JsonParserR4Test extends BaseTest {
* 15:20:41.708 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:574] - Encoded 1200 passes - 28ms / pass - 34.5 / second * 15:20:41.708 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:574] - Encoded 1200 passes - 28ms / pass - 34.5 / second
* 15:20:44.722 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:574] - Encoded 1300 passes - 29ms / pass - 34.4 / second * 15:20:44.722 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:574] - Encoded 1300 passes - 29ms / pass - 34.4 / second
* 15:20:47.716 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:574] - Encoded 1400 passes - 29ms / pass - 34.4 / second * 15:20:47.716 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:574] - Encoded 1400 passes - 29ms / pass - 34.4 / second
*
* 2020-02-27 - Post #1673
* 21:27:25.817 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:609] - Encoded 1100 passes - 28ms / pass - 35.5 / second
* 21:27:28.598 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:609] - Encoded 1200 passes - 28ms / pass - 35.5 / second
* 21:27:31.436 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:609] - Encoded 1300 passes - 28ms / pass - 35.5 / second
* 21:27:34.246 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:609] - Encoded 1400 passes - 28ms / pass - 35.5 / second
* 21:27:37.013 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:609] - Encoded 1500 passes - 28ms / pass - 35.6 / second
* 21:27:39.874 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:609] - Encoded 1600 passes - 28ms / pass - 35.5 / second
*/ */
@Test @Test
@Ignore @Ignore
@ -655,6 +681,12 @@ public class JsonParserR4Test extends BaseTest {
* 15:22:40.699 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:638] - Parsed 2500 passes - 12ms / pass - 79.7 / second * 15:22:40.699 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:638] - Parsed 2500 passes - 12ms / pass - 79.7 / second
* 15:22:42.135 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:638] - Parsed 2600 passes - 12ms / pass - 79.3 / second * 15:22:42.135 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:638] - Parsed 2600 passes - 12ms / pass - 79.3 / second
* *
* 2020-02-27 - Post #1673
* 21:29:38.157 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:687] - Parsed 2200 passes - 11ms / pass - 83.4 / second
* 21:29:39.374 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:687] - Parsed 2300 passes - 12ms / pass - 83.3 / second
* 21:29:40.576 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:687] - Parsed 2400 passes - 12ms / pass - 83.3 / second
* 21:29:41.778 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:687] - Parsed 2500 passes - 12ms / pass - 83.3 / second
* 21:29:42.999 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:687] - Parsed 2600 passes - 12ms / pass - 83.3 / second
* *
*/ */
@Test @Test

View File

@ -1,5 +1,26 @@
package ca.uhn.fhir.parser.jsonlike; package ca.uhn.fhir.parser.jsonlike;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IJsonLikeParser;
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.parser.json.jackson.JacksonStructure;
import ca.uhn.fhir.parser.view.ExtPatient;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
@ -14,31 +35,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Stack; import java.util.Stack;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Extension;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IJsonLikeParser;
import ca.uhn.fhir.parser.IParser;
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.parser.json.JsonLikeValue.ScalarType;
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
import ca.uhn.fhir.parser.view.ExtPatient;
import ca.uhn.fhir.util.TestUtil;
public class JsonLikeParserTest { public class JsonLikeParserTest {
private static FhirContext ourCtx = FhirContext.forR4(); private static FhirContext ourCtx = FhirContext.forR4();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserTest.class);
@ -55,7 +51,7 @@ public class JsonLikeParserTest {
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed); String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(encoded); ourLog.info(encoded);
JsonLikeStructure jsonLikeStructure = new GsonStructure(); JsonLikeStructure jsonLikeStructure = new JacksonStructure();
jsonLikeStructure.load(new StringReader(encoded)); jsonLikeStructure.load(new StringReader(encoded));
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser(); IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();
@ -258,17 +254,6 @@ public class JsonLikeParserTest {
return this; return this;
} }
@Override
public JsonLikeWriter beginArray() throws IOException {
if (currentBlock.getType() == BlockType.NONE) {
throw new IOException("JsonLikeStreamWriter.beginArray() called but only beginObject() is allowed here.");
}
blockStack.push(currentBlock);
currentBlock = new Block(BlockType.ARRAY);
currentBlock.setArray(new ArrayList<Object>());
return this;
}
@Override @Override
public JsonLikeWriter beginObject(String name) throws IOException { public JsonLikeWriter beginObject(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) { if (currentBlock.getType() == BlockType.ARRAY) {
@ -429,15 +414,6 @@ public class JsonLikeParserTest {
return this; return this;
} }
@Override
public JsonLikeWriter writeNull(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, null);
return this;
}
@Override @Override
public JsonLikeWriter endObject() throws IOException { public JsonLikeWriter endObject() throws IOException {
if (currentBlock.getType() == BlockType.NONE) { if (currentBlock.getType() == BlockType.NONE) {
@ -452,7 +428,7 @@ public class JsonLikeParserTest {
} }
@Override @Override
public JsonLikeWriter endArray() throws IOException { public JsonLikeWriter endArray() {
if (currentBlock.getType() == BlockType.NONE) { if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endArray(); called with no active JSON document"); ourLog.error("JsonLikeStreamWriter.endArray(); called with no active JSON document");
} else { } else {
@ -465,11 +441,11 @@ public class JsonLikeParserTest {
} }
@Override @Override
public JsonLikeWriter endBlock() throws IOException { public JsonLikeWriter endBlock() {
if (currentBlock.getType() == BlockType.NONE) { if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document"); ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document");
} else { } else {
Object toPut = null; Object toPut;
if (currentBlock.getType() == BlockType.ARRAY) { if (currentBlock.getType() == BlockType.ARRAY) {
toPut = currentBlock.getArray(); toPut = currentBlock.getArray();
} else { } else {
@ -544,14 +520,9 @@ public class JsonLikeParserTest {
return jsonLikeObject; return jsonLikeObject;
} }
@Override
public JsonLikeArray getRootArray() throws DataFormatException {
throw new DataFormatException("JSON document must be an object not an array for native Java Map structures");
}
private class JsonMapObject extends JsonLikeObject { private class JsonMapObject extends JsonLikeObject {
private Map<String,Object> nativeObject; private Map<String,Object> nativeObject;
private Map<String,JsonLikeValue> jsonLikeMap = new LinkedHashMap<String,JsonLikeValue>(); private Map<String,JsonLikeValue> jsonLikeMap = new LinkedHashMap<>();
public JsonMapObject (Map<String,Object> json) { public JsonMapObject (Map<String,Object> json) {
this.nativeObject = json; this.nativeObject = json;
@ -585,7 +556,7 @@ public class JsonLikeParserTest {
private class JsonMapArray extends JsonLikeArray { private class JsonMapArray extends JsonLikeArray {
private List<Object> nativeArray; private List<Object> nativeArray;
private Map<Integer,JsonLikeValue> jsonLikeMap = new LinkedHashMap<Integer,JsonLikeValue>(); private Map<Integer,JsonLikeValue> jsonLikeMap = new LinkedHashMap<>();
public JsonMapArray (List<Object> json) { public JsonMapArray (List<Object> json) {
this.nativeArray = json; this.nativeArray = json;
@ -603,7 +574,7 @@ public class JsonLikeParserTest {
@Override @Override
public JsonLikeValue get(int index) { public JsonLikeValue get(int index) {
Integer key = Integer.valueOf(index); Integer key = index;
JsonLikeValue result = null; JsonLikeValue result = null;
if (jsonLikeMap.containsKey(key)) { if (jsonLikeMap.containsKey(key)) {
result = jsonLikeMap.get(key); result = jsonLikeMap.get(key);
@ -694,7 +665,7 @@ public class JsonLikeParserTest {
@Override @Override
public boolean getAsBoolean() { public boolean getAsBoolean() {
if (nativeValue != null && isBoolean()) { if (nativeValue != null && isBoolean()) {
return ((Boolean)nativeValue).booleanValue(); return (Boolean) nativeValue;
} }
return super.getAsBoolean(); return super.getAsBoolean();
} }

View File

@ -91,7 +91,7 @@ public class BlockingContentR4Test {
if (myByteCount++ == 10) { if (myByteCount++ == 10) {
ourLog.info("About to block..."); ourLog.info("About to block...");
try { try {
Thread.sleep(30000); Thread.sleep(3000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
ourLog.warn("Interrupted", e); ourLog.warn("Interrupted", e);
} }

View File

@ -35,12 +35,16 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.Invocation;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.io.IOException; import java.io.IOException;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -201,12 +205,13 @@ public class ConsentInterceptorTest {
assertThat(responseContent, containsString("A DIAG")); assertThat(responseContent, containsString("A DIAG"));
} }
verify(myConsentSvc, times(1)).startOperation(any(), any()); verify(myConsentSvc, timeout(10000).times(1)).startOperation(any(), any());
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any()); verify(myConsentSvc, timeout(10000).times(2)).canSeeResource(any(), any(), any());
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any()); verify(myConsentSvc, timeout(10000).times(3)).willSeeResource(any(), any(), any());
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any()); verify(myConsentSvc, timeout(10000).times(1)).completeOperationSuccess(any(), any());
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any()); verify(myConsentSvc, timeout(10000).times(0)).completeOperationFailure(any(), any(), any());
verifyNoMoreInteractions(myConsentSvc); verifyNoMoreInteractions(myConsentSvc);
} }
@Test @Test
@ -241,6 +246,7 @@ public class ConsentInterceptorTest {
ourPatientProvider.store((Patient) new Patient().setActive(true).setId("PTA")); ourPatientProvider.store((Patient) new Patient().setActive(true).setId("PTA"));
ourPatientProvider.store((Patient) new Patient().setActive(false).setId("PTB")); ourPatientProvider.store((Patient) new Patient().setActive(false).setId("PTB"));
reset(myConsentSvc);
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED); when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED); when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.PROCEED);
when(myConsentSvc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{ when(myConsentSvc.willSeeResource(any(RequestDetails.class), any(IBaseResource.class), any())).thenAnswer(t->{
@ -266,10 +272,10 @@ public class ConsentInterceptorTest {
assertEquals("PTB", response.getEntry().get(1).getResource().getIdElement().getIdPart()); assertEquals("PTB", response.getEntry().get(1).getResource().getIdElement().getIdPart());
} }
verify(myConsentSvc, times(1)).startOperation(any(), any()); verify(myConsentSvc, timeout(1000).times(1)).startOperation(any(), any());
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any()); verify(myConsentSvc, timeout(1000).times(2)).canSeeResource(any(), any(), any());
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any()); verify(myConsentSvc, timeout(1000).times(3)).willSeeResource(any(), any(), any());
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any()); verify(myConsentSvc, timeout(1000).times(1)).completeOperationSuccess(any(), any());
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any()); verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
verifyNoMoreInteractions(myConsentSvc); verifyNoMoreInteractions(myConsentSvc);
} }

View File

@ -7,6 +7,7 @@ import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -21,7 +22,11 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.Resource;
import org.junit.*; import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -30,11 +35,12 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import ca.uhn.fhir.test.utilities.JettyUtil; import static org.junit.Assert.assertTrue;
public class InterceptorThrowingExceptionR4Test { public class InterceptorThrowingExceptionR4Test {
@ -84,26 +90,26 @@ public class InterceptorThrowingExceptionR4Test {
@Test @Test
public void testFailureInProcessingCompletedNormally() throws Exception { public void testFailureInProcessingCompletedNormally() throws Exception {
final List<Integer> hit = new ArrayList<>(); final List<Integer> hit = Collections.synchronizedList(new ArrayList<>());
ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() { ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() {
@Override @Override
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) { public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
hit.add(1); hit.add(1);
throw new NullPointerException(); throw new NullPointerException("Hit 1");
} }
}); });
ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() { ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() {
@Override @Override
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) { public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
hit.add(2); hit.add(2);
throw new NullPointerException(); throw new NullPointerException("Hit 2");
} }
}); });
ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() { ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() {
@Override @Override
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) { public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
hit.add(3); hit.add(3);
throw new NullPointerException(); throw new NullPointerException("Hit 3");
} }
}); });
@ -119,6 +125,9 @@ public class InterceptorThrowingExceptionR4Test {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(response, containsString("FAM")); assertThat(response, containsString("FAM"));
assertTrue(ourHitMethod); assertTrue(ourHitMethod);
await().until(() -> hit.size() == 3);
ourLog.info("Hit: {}", hit); ourLog.info("Hit: {}", hit);
assertThat("Hits: " + hit.toString(), hit, contains(1, 2, 3)); assertThat("Hits: " + hit.toString(), hit, contains(1, 2, 3));

View File

@ -66,6 +66,10 @@
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<!--<dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-structures-dev</artifactId> <version>0.9</version> </dependency> --> <!--<dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-structures-dev</artifactId> <version>0.9</version> </dependency> -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.thymeleaf</groupId> <groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId> <artifactId>thymeleaf</artifactId>

View File

@ -1,42 +1,59 @@
package ca.uhn.fhir.to; package ca.uhn.fhir.to;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.client.impl.GenericClient;
import ca.uhn.fhir.rest.gclient.ICreateTyped;
import ca.uhn.fhir.rest.gclient.IHistory;
import ca.uhn.fhir.rest.gclient.IHistoryTyped;
import ca.uhn.fhir.rest.gclient.IHistoryUntyped;
import ca.uhn.fhir.rest.gclient.IQuery;
import ca.uhn.fhir.rest.gclient.IUntypedQuery;
import ca.uhn.fhir.rest.gclient.NumberClientParam.IMatches;
import ca.uhn.fhir.rest.gclient.QuantityClientParam;
import ca.uhn.fhir.rest.gclient.QuantityClientParam.IAndUnits;
import ca.uhn.fhir.rest.gclient.StringClientParam;
import ca.uhn.fhir.rest.gclient.TokenClientParam;
import ca.uhn.fhir.to.model.HomeRequest;
import ca.uhn.fhir.to.model.ResourceRequest;
import ca.uhn.fhir.to.model.TransactionRequest;
import com.google.gson.stream.JsonWriter;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu3.model.CapabilityStatement;
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent;
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseConformance;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import static org.apache.commons.lang3.StringUtils.defaultIfEmpty; import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu3.model.CapabilityStatement;
import org.hl7.fhir.dstu3.model.CapabilityStatement.*;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.*;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import com.google.gson.stream.JsonWriter;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
import ca.uhn.fhir.model.primitive.*;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.client.impl.GenericClient;
import ca.uhn.fhir.rest.gclient.*;
import ca.uhn.fhir.rest.gclient.NumberClientParam.IMatches;
import ca.uhn.fhir.rest.gclient.QuantityClientParam.IAndUnits;
import ca.uhn.fhir.to.model.*;
@org.springframework.stereotype.Controller() @org.springframework.stereotype.Controller()
public class Controller extends BaseController { public class Controller extends BaseController {
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Controller.class); static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Controller.class);

View File

@ -46,6 +46,15 @@
<artifactId>jsr305</artifactId> <artifactId>jsr305</artifactId>
</dependency> </dependency>
<!--
Note: As of HAPI FHIR 5.0.0 we now use Jackson for JSON parsing, but the
validator still uses GSON so it is a dependency here
-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- <!--
Optional dependencies from RI codebase Optional dependencies from RI codebase
--> -->