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 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- XML -->

View File

@ -22,20 +22,29 @@ package ca.uhn.fhir.parser;
import ca.uhn.fhir.context.*;
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.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
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.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.util.ElementUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.text.WordUtils;
@ -45,11 +54,17 @@ import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
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.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
@ -147,10 +162,9 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
theEventWriter.beginObject(arrayName);
}
private JsonLikeWriter createJsonWriter(Writer theWriter) {
JsonLikeStructure jsonStructure = new GsonStructure();
JsonLikeWriter retVal = jsonStructure.getJsonLikeWriter(theWriter);
return retVal;
private JsonLikeWriter createJsonWriter(Writer theWriter) throws IOException {
JsonLikeStructure jsonStructure = new JacksonStructure();
return jsonStructure.getJsonLikeWriter(theWriter);
}
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 {
JsonLikeWriter eventWriter = createJsonWriter(theWriter);
doEncodeResourceToJsonLikeWriter(theResource, eventWriter, theEncodeContext);
eventWriter.close();
}
@Override
public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) {
JsonLikeStructure jsonStructure = new GsonStructure();
JsonLikeStructure jsonStructure = new JacksonStructure();
jsonStructure.load(theReader);
T retVal = doParseResource(theResourceType, jsonStructure);
@ -418,10 +433,10 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
String currentChildName = null;
boolean inArray = false;
ArrayList<ArrayList<HeldExtension>> extensions = new ArrayList<ArrayList<HeldExtension>>(0);
ArrayList<ArrayList<HeldExtension>> modifierExtensions = new ArrayList<ArrayList<HeldExtension>>(0);
ArrayList<ArrayList<String>> comments = new ArrayList<ArrayList<String>>(0);
ArrayList<String> ids = new ArrayList<String>(0);
ArrayList<ArrayList<HeldExtension>> extensions = new ArrayList<>(0);
ArrayList<ArrayList<HeldExtension>> modifierExtensions = new ArrayList<>(0);
ArrayList<ArrayList<String>> comments = new ArrayList<>(0);
ArrayList<String> ids = new ArrayList<>(0);
int valueIdx = 0;
for (IBase nextValue : values) {
@ -1107,7 +1122,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
} else {
// must be a SCALAR
theState.enteringNewElement(null, theName);
theState.attributeValue("value", theJsonVal.getAsString());
String asString = theJsonVal.getAsString();
theState.attributeValue("value", asString);
parseAlternates(theAlternateVal, theState, theAlternateName, theAlternateName);
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 {
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 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,34 +19,38 @@
*/
package ca.uhn.fhir.parser.json;
import ca.uhn.fhir.parser.DataFormatException;
import java.io.IOException;
import java.io.Reader;
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
* can be abstractly viewed as a <code.Map</code> or <code>List</code>
* whose members are other Maps, Lists, or scalars (Strings, Numbers, Boolean)
*
*
* @author Bill.Denton
*/
public interface JsonLikeStructure {
public JsonLikeStructure getInstance();
JsonLikeStructure getInstance();
/**
* Parse the JSON document into the Json-like structure
* so that it can be navigated.
*
*
* @param theReader a <code>Reader</code> that will
* process the JSON input stream
* process the JSON input stream
* @throws DataFormatException when invalid JSON is received
*/
public void load (Reader theReader) throws DataFormatException;
public void load (Reader theReader, boolean allowArray) throws DataFormatException;
public JsonLikeObject getRootObject () throws DataFormatException;
public JsonLikeArray getRootArray () throws DataFormatException;
public JsonLikeWriter getJsonLikeWriter ();
public JsonLikeWriter getJsonLikeWriter (Writer writer);
void load(Reader theReader) throws DataFormatException;
void load(Reader theReader, boolean allowArray) throws DataFormatException;
JsonLikeObject getRootObject() throws DataFormatException;
JsonLikeWriter getJsonLikeWriter();
JsonLikeWriter getJsonLikeWriter(Writer writer) throws IOException;
}

View File

@ -29,55 +29,73 @@ public abstract class JsonLikeWriter {
private boolean prettyPrint;
private Writer writer;
public void setPrettyPrint (boolean tf) {
prettyPrint = tf;
}
public boolean isPrettyPrint () {
return prettyPrint;
}
public void setWriter (Writer writer) {
this.writer = writer;
}
public Writer getWriter () {
return writer;
}
public abstract JsonLikeWriter init () throws IOException;
public abstract JsonLikeWriter flush () throws IOException;
public abstract void close () 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 beginArray (String name) throws IOException;
public abstract JsonLikeWriter write (String value) throws IOException;
public abstract JsonLikeWriter write (BigInteger value) throws IOException;
public abstract JsonLikeWriter write (BigDecimal value) throws IOException;
public abstract JsonLikeWriter write (long 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 writeNull () 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, BigDecimal 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, 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 endArray () throws IOException;
public abstract JsonLikeWriter endBlock () throws IOException;
public JsonLikeWriter() {
super();
}
public boolean isPrettyPrint() {
return prettyPrint;
}
public void setPrettyPrint(boolean tf) {
prettyPrint = tf;
}
public Writer getWriter() {
return writer;
}
public void setWriter(Writer writer) {
this.writer = writer;
}
public abstract JsonLikeWriter init() throws IOException;
public abstract JsonLikeWriter flush() throws IOException;
public abstract void close() throws IOException;
public abstract JsonLikeWriter beginObject() throws IOException;
public abstract JsonLikeWriter beginObject(String name) throws IOException;
public abstract JsonLikeWriter beginArray(String name) throws IOException;
public abstract JsonLikeWriter write(String value) throws IOException;
public abstract JsonLikeWriter write(BigInteger value) throws IOException;
public abstract JsonLikeWriter write(BigDecimal value) throws IOException;
public abstract JsonLikeWriter write(long 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 writeNull() 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, BigDecimal 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, Boolean value) throws IOException;
public abstract JsonLikeWriter write(String name, boolean value) throws IOException;
public abstract JsonLikeWriter endObject() throws IOException;
public abstract JsonLikeWriter endArray() throws IOException;
public abstract JsonLikeWriter endBlock() throws IOException;
}

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 ca.uhn.fhir.parser.json.jackson.JacksonStructure;
import org.junit.Test;
public class JsonLikeStructureTest {
@ -39,7 +40,7 @@ public class JsonLikeStructureTest {
@Test
public void testStructureLoading() {
StringReader reader = new StringReader(TEST_STRUCTURELOADING_DATA);
JsonLikeStructure jsonStructure = new GsonStructure();
JsonLikeStructure jsonStructure = new JacksonStructure();
jsonStructure.load(reader);
JsonLikeObject rootObject = jsonStructure.getRootObject();
@ -70,7 +71,7 @@ public class JsonLikeStructureTest {
@Test
public void testJsonAndDataTypes() {
StringReader reader = new StringReader(TEST_JSONTYPES_DATA);
JsonLikeStructure jsonStructure = new GsonStructure();
JsonLikeStructure jsonStructure = new JacksonStructure();
jsonStructure.load(reader);
JsonLikeObject rootObject = jsonStructure.getRootObject();

View File

@ -5368,7 +5368,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
@Test
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");
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);
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 {
response.getEntity().getContent().close();
response.close();

View File

@ -1518,13 +1518,13 @@ public class JsonParserDstu2_1Test {
ourCtx.newJsonParser().parseResource("FOO");
fail();
} 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 {
ourCtx.newJsonParser().parseResource("[\"aaa\"]");
fail();
} 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());

View File

@ -1996,41 +1996,27 @@ public class XmlParserDstu2_1Test {
assertThat(output, stringContainsInOrder(
"{",
" \"resourceType\": \"Patient\",",
" \"id\": \"someid\",",
" \"_id\": {",
" \"fhir_comments\": [",
" \" comment 1 \"",
" ]",
" },",
" \"extension\": [",
" {",
" \"fhir_comments\": [",
" \" comment 2 \",",
" \" comment 7 \"",
" ],",
" \"url\": \"urn:patientext:att\",",
" \"valueAttachment\": {",
" \"fhir_comments\": [",
" \" comment 3 \",",
" \" comment 6 \"",
" ],",
" \"contentType\": \"aaaa\",",
" \"_contentType\": {",
" \"fhir_comments\": [",
" \" comment 4 \"",
" ]",
" },",
" \"data\": \"AAAA\",",
" \"_data\": {",
" \"fhir_comments\": [",
" \" comment 5 \"",
" ]",
" }",
" }",
" }",
" ]",
"}"
" \"resourceType\": \"Patient\",",
" \"id\": \"someid\",",
" \"_id\": {",
" \"fhir_comments\": [ \" comment 1 \" ]",
" },",
" \"extension\": [ {",
" \"fhir_comments\": [ \" comment 2 \", \" comment 7 \" ],",
" \"url\": \"urn:patientext:att\",",
" \"valueAttachment\": {",
" \"fhir_comments\": [ \" comment 3 \", \" comment 6 \" ],",
" \"contentType\": \"aaaa\",",
" \"_contentType\": {",
" \"fhir_comments\": [ \" comment 4 \" ]",
" },",
" \"data\": \"AAAA\",",
" \"_data\": {",
" \"fhir_comments\": [ \" comment 5 \" ]",
" }",
" }",
" } ]",
"}"
));
//@formatter:on

View File

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

View File

@ -1,16 +1,15 @@
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.junit.AfterClass;
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.util.TestUtil;
import java.io.StringReader;
public class JsonLikeParserDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
@ -28,7 +27,7 @@ public class JsonLikeParserDstu2Test {
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(encoded);
JsonLikeStructure jsonLikeStructure = new GsonStructure();
JsonLikeStructure jsonLikeStructure = new JacksonStructure();
jsonLikeStructure.load(new StringReader(encoded));
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();

View File

@ -72,7 +72,8 @@ public class JsonParserDstu3Test {
p.parseResource(input);
fail();
} 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);
ourLog.info(enc);
//@formatter:off
assertEquals("{\n" +
" \"resourceType\": \"Patient\",\n" +
" \"meta\": {\n" +
" \"security\": [\n" +
" {\n" +
" \"system\": \"SYSTEM1\",\n" +
" \"version\": \"VERSION1\",\n" +
" \"code\": \"CODE1\",\n" +
" \"display\": \"DISPLAY1\"\n" +
" },\n" +
" {\n" +
" \"system\": \"SYSTEM2\",\n" +
" \"version\": \"VERSION2\",\n" +
" \"code\": \"CODE2\",\n" +
" \"display\": \"DISPLAY2\"\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"name\": [\n" +
" {\n" +
" \"family\": \"FAMILY\"\n" +
" }\n" +
" ]\n" +
"}", enc.trim());
//@formatter:on
assertThat(enc.trim(), stringContainsInOrder("{",
" \"resourceType\": \"Patient\",",
" \"meta\": {",
" \"security\": [ {",
" \"system\": \"SYSTEM1\",",
" \"version\": \"VERSION1\",",
" \"code\": \"CODE1\",",
" \"display\": \"DISPLAY1\"",
" }, {",
" \"system\": \"SYSTEM2\",",
" \"version\": \"VERSION2\",",
" \"code\": \"CODE2\",",
" \"display\": \"DISPLAY2\"",
" } ]",
" },",
" \"name\": [ {",
" \"family\": \"FAMILY\"",
" } ]",
"}"));
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, enc);
List<Coding> gotLabels = parsed.getMeta().getSecurity();
@ -1401,7 +1395,8 @@ public class JsonParserDstu3Test {
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.0000000000000001}}";
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);
ourLog.info(str);
@ -1993,13 +1988,13 @@ public class JsonParserDstu3Test {
ourCtx.newJsonParser().parseResource("FOO");
fail();
} 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 {
ourCtx.newJsonParser().parseResource("[\"aaa\"]");
fail();
} 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());
@ -2221,25 +2216,47 @@ public class JsonParserDstu3Test {
@Test
public void testParseWithPrecision() {
String input = "{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement();
assertEquals("0.000000000000000100", valueElement.getValueAsString());
// BigDecimal d0 = new BigDecimal("0.1");
// BigDecimal d1 = new BigDecimal("0.1000");
//
// ourLog.info("Value: {}", d0);
// ourLog.info("Value: {}", d1);
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
{
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}}";
Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, input);
DecimalType valueElement = ((Quantity) obs.getValue()).getValueElement();
assertEquals("0.000000000000000100", valueElement.getValueAsString());
String str = ourCtx.newJsonParser().encodeResourceToString(obs);
ourLog.info(str);
assertEquals("{\"resourceType\":\"Observation\",\"valueQuantity\":{\"value\":0.000000000000000100}}", str);
}
}
@Test(expected = DataFormatException.class)
@Test
public void testParseWithTrailingContent() {
String bundle = "{\n" +
" \"resourceType\" : \"Bundle\",\n" +
" \"total\" : 1\n" +
" \"resourceType\": \"Bundle\",\n" +
" \"total\": 1\n" +
"}}";
ourCtx.newJsonParser().parseResource(Bundle.class, bundle);
try {
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

View File

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

View File

@ -1,426 +1,404 @@
package ca.uhn.fhir.parser.jsonlike;
import java.io.IOException;
import java.io.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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 {
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserDstu3Test.class);
/**
* Test for JSON Parser with user-supplied JSON-like structure (use default GSON)
*/
@Test
public void testJsonLikeParseAndEncodeBundleFromXmlToJson() throws Exception {
String content = IOUtils.toString(JsonLikeParserDstu3Test.class.getResourceAsStream("/bundle_with_woven_obs.xml"));
Bundle parsed = ourCtx.newXmlParser().parseResource(Bundle.class, content);
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(encoded);
JsonLikeStructure jsonLikeStructure = new GsonStructure();
jsonLikeStructure.load(new StringReader(encoded));
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();
Bundle bundle = jsonLikeparser.parseResource(Bundle.class, jsonLikeStructure);
}
/**
* Test JSON-Like writer using custom stream writer
*
*/
@Test
public void testJsonLikeParseWithCustomJSONStreamWriter() throws Exception {
String refVal = "http://my.org/FooBar";
Patient fhirPat = new Patient();
fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser();
JsonLikeMapWriter jsonLikeWriter = new JsonLikeMapWriter();
jsonLikeParser.encodeResourceToJsonLikeWriter(fhirPat, jsonLikeWriter);
Map<String,Object> jsonLikeMap = jsonLikeWriter.getResultMap();
System.out.println("encoded map: " + jsonLikeMap.toString());
Assert.assertNotNull("Encoded resource missing 'resourceType' element", jsonLikeMap.get("resourceType"));
Assert.assertEquals("Expecting 'resourceType'='Patient'; found '"+jsonLikeMap.get("resourceType")+"'", jsonLikeMap.get("resourceType"), "Patient");
Assert.assertNotNull("Encoded resource missing 'extension' element", jsonLikeMap.get("extension"));
Assert.assertTrue("'extension' element is not a List", (jsonLikeMap.get("extension") instanceof List));
List<Object> extensions = (List<Object>)jsonLikeMap.get("extension");
Assert.assertEquals("'extnesion' array has more than one entry", 1, extensions.size());
Assert.assertTrue("'extension' array entry is not a Map", (extensions.get(0) instanceof Map));
Map<String, Object> extension = (Map<String,Object>)extensions.get(0);
Assert.assertNotNull("'extension' entry missing 'url' member", extension.get("url"));
Assert.assertTrue("'extension' entry 'url' member is not a String", (extension.get("url") instanceof String));
Assert.assertEquals("Expecting '/extension[]/url' = 'x1'; found '"+extension.get("url")+"'", "x1", (String)extension.get("url"));
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
public static class JsonLikeMapWriter extends JsonLikeWriter {
private Map<String,Object> target;
private static class Block {
private BlockType type;
private String name;
private Map<String,Object> object;
private List<Object> array;
public Block(BlockType type) {
this.type = type;
}
public BlockType getType() {
return type;
}
public String getName() {
return name;
}
public void setName(String currentName) {
this.name = currentName;
}
public Map<String, Object> getObject() {
return object;
}
public void setObject(Map<String, Object> currentObject) {
this.object = currentObject;
}
public List<Object> getArray() {
return array;
}
public void setArray(List<Object> currentArray) {
this.array = currentArray;
}
}
private enum BlockType {
NONE, OBJECT, ARRAY
}
private Block currentBlock = new Block(BlockType.NONE);
private Stack<Block> blockStack = new Stack<Block>();
public JsonLikeMapWriter () {
super();
}
public Map<String,Object> getResultMap() {
return target;
}
public void setResultMap(Map<String,Object> target) {
this.target = target;
}
@Override
public JsonLikeWriter init() throws IOException {
if (target != null) {
target.clear();
}
currentBlock = new Block(BlockType.NONE);
blockStack.clear();
return this;
}
@Override
public JsonLikeWriter flush() throws IOException {
if (currentBlock.getType() != BlockType.NONE) {
throw new IOException("JsonLikeStreamWriter.flush() called but JSON document is not finished");
}
return this;
}
@Override
public void close() {
// nothing to do
}
@Override
public JsonLikeWriter beginObject() throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
Map<String,Object> newObject = null;
if (currentBlock.getType() == BlockType.NONE) {
if (null == target) {
// for this test, we don't care about ordering of map elements
// target = new EntryOrderedMap<String,Object>();
target = new HashMap<String,Object>();
}
newObject = target;
} else {
// for this test, we don't care about ordering of map elements
// newObject = new EntryOrderedMap<String,Object>();
newObject = new HashMap<String,Object>();
}
blockStack.push(currentBlock);
currentBlock = new Block(BlockType.OBJECT);
currentBlock.setObject(newObject);
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
public JsonLikeWriter beginObject(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
blockStack.push(currentBlock);
currentBlock = new Block(BlockType.OBJECT);
currentBlock.setName(name);
// for this test, we don't care about ordering of map elements
// currentBlock.setObject(new EntryOrderedMap<String,Object>());
currentBlock.setObject(new HashMap<String,Object>());
return this;
}
@Override
public JsonLikeWriter beginArray(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
blockStack.push(currentBlock);
currentBlock = new Block(BlockType.ARRAY);
currentBlock.setName(name);
currentBlock.setArray(new ArrayList<Object>());
return this;
}
@Override
public JsonLikeWriter write(String value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(value);
return this;
}
@Override
public JsonLikeWriter write(BigInteger value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(value);
return this;
}
@Override
public JsonLikeWriter write(BigDecimal value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(value);
return this;
}
@Override
public JsonLikeWriter write(long value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(Long.valueOf(value));
return this;
}
@Override
public JsonLikeWriter write(double value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(Double.valueOf(value));
return this;
}
@Override
public JsonLikeWriter write(Boolean value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(value);
return this;
}
@Override
public JsonLikeWriter write(boolean value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(Boolean.valueOf(value));
return this;
}
@Override
public JsonLikeWriter writeNull() throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(null);
return this;
}
@Override
public JsonLikeWriter write(String name, String value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, BigInteger value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, BigDecimal value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, long value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, Long.valueOf(value));
return this;
}
@Override
public JsonLikeWriter write(String name, double value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, Double.valueOf(value));
return this;
}
@Override
public JsonLikeWriter write(String name, Boolean value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, boolean value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, Boolean.valueOf(value));
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
public JsonLikeWriter endObject() throws IOException {
if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endObject(); called with no active JSON document");
} else {
if (currentBlock.getType() != BlockType.OBJECT) {
ourLog.error("JsonLikeStreamWriter.endObject(); called outside a JSON object. (Use endArray() instead?)");
}
endBlock();
}
return this;
}
@Override
public JsonLikeWriter endArray() throws IOException {
if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endArray(); called with no active JSON document");
} else {
if (currentBlock.getType() != BlockType.ARRAY) {
ourLog.error("JsonLikeStreamWriter.endArray(); called outside a JSON array. (Use endObject() instead?)");
}
endBlock();
}
return this;
}
@Override
public JsonLikeWriter endBlock() throws IOException {
if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document");
} else {
Object toPut = null;
if (currentBlock.getType() == BlockType.ARRAY) {
toPut = currentBlock.getArray();
} else {
toPut = currentBlock.getObject();
}
Block parentBlock = blockStack.pop();
if (parentBlock.getType() == BlockType.OBJECT) {
parentBlock.getObject().put(currentBlock.getName(), toPut);
} else
if (parentBlock.getType() == BlockType.ARRAY) {
parentBlock.getArray().add(toPut);
}
currentBlock = parentBlock;
}
return this;
}
}
}
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.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class JsonLikeParserDstu3Test {
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserDstu3Test.class);
/**
* Test for JSON Parser with user-supplied JSON-like structure (use default GSON)
*/
@Test
public void testJsonLikeParseAndEncodeBundleFromXmlToJson() throws Exception {
String content = IOUtils.toString(JsonLikeParserDstu3Test.class.getResourceAsStream("/bundle_with_woven_obs.xml"));
Bundle parsed = ourCtx.newXmlParser().parseResource(Bundle.class, content);
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed);
ourLog.info(encoded);
JsonLikeStructure jsonLikeStructure = new JacksonStructure();
jsonLikeStructure.load(new StringReader(encoded));
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();
Bundle bundle = jsonLikeparser.parseResource(Bundle.class, jsonLikeStructure);
}
/**
* Test JSON-Like writer using custom stream writer
*
*/
@Test
public void testJsonLikeParseWithCustomJSONStreamWriter() throws Exception {
String refVal = "http://my.org/FooBar";
Patient fhirPat = new Patient();
fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser();
JsonLikeMapWriter jsonLikeWriter = new JsonLikeMapWriter();
jsonLikeParser.encodeResourceToJsonLikeWriter(fhirPat, jsonLikeWriter);
Map<String,Object> jsonLikeMap = jsonLikeWriter.getResultMap();
System.out.println("encoded map: " + jsonLikeMap.toString());
Assert.assertNotNull("Encoded resource missing 'resourceType' element", jsonLikeMap.get("resourceType"));
Assert.assertEquals("Expecting 'resourceType'='Patient'; found '"+jsonLikeMap.get("resourceType")+"'", jsonLikeMap.get("resourceType"), "Patient");
Assert.assertNotNull("Encoded resource missing 'extension' element", jsonLikeMap.get("extension"));
Assert.assertTrue("'extension' element is not a List", (jsonLikeMap.get("extension") instanceof List));
List<Object> extensions = (List<Object>)jsonLikeMap.get("extension");
Assert.assertEquals("'extnesion' array has more than one entry", 1, extensions.size());
Assert.assertTrue("'extension' array entry is not a Map", (extensions.get(0) instanceof Map));
Map<String, Object> extension = (Map<String,Object>)extensions.get(0);
Assert.assertNotNull("'extension' entry missing 'url' member", extension.get("url"));
Assert.assertTrue("'extension' entry 'url' member is not a String", (extension.get("url") instanceof String));
Assert.assertEquals("Expecting '/extension[]/url' = 'x1'; found '"+extension.get("url")+"'", "x1", (String)extension.get("url"));
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
public static class JsonLikeMapWriter extends JsonLikeWriter {
private Map<String,Object> target;
private static class Block {
private BlockType type;
private String name;
private Map<String,Object> object;
private List<Object> array;
public Block(BlockType type) {
this.type = type;
}
public BlockType getType() {
return type;
}
public String getName() {
return name;
}
public void setName(String currentName) {
this.name = currentName;
}
public Map<String, Object> getObject() {
return object;
}
public void setObject(Map<String, Object> currentObject) {
this.object = currentObject;
}
public List<Object> getArray() {
return array;
}
public void setArray(List<Object> currentArray) {
this.array = currentArray;
}
}
private enum BlockType {
NONE, OBJECT, ARRAY
}
private Block currentBlock = new Block(BlockType.NONE);
private Stack<Block> blockStack = new Stack<Block>();
public JsonLikeMapWriter () {
super();
}
public Map<String,Object> getResultMap() {
return target;
}
public void setResultMap(Map<String,Object> target) {
this.target = target;
}
@Override
public JsonLikeWriter init() throws IOException {
if (target != null) {
target.clear();
}
currentBlock = new Block(BlockType.NONE);
blockStack.clear();
return this;
}
@Override
public JsonLikeWriter flush() throws IOException {
if (currentBlock.getType() != BlockType.NONE) {
throw new IOException("JsonLikeStreamWriter.flush() called but JSON document is not finished");
}
return this;
}
@Override
public void close() {
// nothing to do
}
@Override
public JsonLikeWriter beginObject() throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
Map<String,Object> newObject = null;
if (currentBlock.getType() == BlockType.NONE) {
if (null == target) {
// for this test, we don't care about ordering of map elements
// target = new EntryOrderedMap<String,Object>();
target = new HashMap<String,Object>();
}
newObject = target;
} else {
// for this test, we don't care about ordering of map elements
// newObject = new EntryOrderedMap<String,Object>();
newObject = new HashMap<String,Object>();
}
blockStack.push(currentBlock);
currentBlock = new Block(BlockType.OBJECT);
currentBlock.setObject(newObject);
return this;
}
@Override
public JsonLikeWriter beginObject(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
blockStack.push(currentBlock);
currentBlock = new Block(BlockType.OBJECT);
currentBlock.setName(name);
// for this test, we don't care about ordering of map elements
// currentBlock.setObject(new EntryOrderedMap<String,Object>());
currentBlock.setObject(new HashMap<String,Object>());
return this;
}
@Override
public JsonLikeWriter beginArray(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
blockStack.push(currentBlock);
currentBlock = new Block(BlockType.ARRAY);
currentBlock.setName(name);
currentBlock.setArray(new ArrayList<Object>());
return this;
}
@Override
public JsonLikeWriter write(String value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(value);
return this;
}
@Override
public JsonLikeWriter write(BigInteger value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(value);
return this;
}
@Override
public JsonLikeWriter write(BigDecimal value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(value);
return this;
}
@Override
public JsonLikeWriter write(long value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(Long.valueOf(value));
return this;
}
@Override
public JsonLikeWriter write(double value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(Double.valueOf(value));
return this;
}
@Override
public JsonLikeWriter write(Boolean value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(value);
return this;
}
@Override
public JsonLikeWriter write(boolean value) throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(Boolean.valueOf(value));
return this;
}
@Override
public JsonLikeWriter writeNull() throws IOException {
if (currentBlock.getType() == BlockType.OBJECT) {
throw new IOException("Unnamed JSON elements can only be created in JSON arrays");
}
currentBlock.getArray().add(null);
return this;
}
@Override
public JsonLikeWriter write(String name, String value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, BigInteger value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, BigDecimal value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, long value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, Long.valueOf(value));
return this;
}
@Override
public JsonLikeWriter write(String name, double value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, Double.valueOf(value));
return this;
}
@Override
public JsonLikeWriter write(String name, Boolean value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, value);
return this;
}
@Override
public JsonLikeWriter write(String name, boolean value) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
throw new IOException("Named JSON elements can only be created in JSON objects");
}
currentBlock.getObject().put(name, Boolean.valueOf(value));
return this;
}
@Override
public JsonLikeWriter endObject() throws IOException {
if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endObject(); called with no active JSON document");
} else {
if (currentBlock.getType() != BlockType.OBJECT) {
ourLog.error("JsonLikeStreamWriter.endObject(); called outside a JSON object. (Use endArray() instead?)");
}
endBlock();
}
return this;
}
@Override
public JsonLikeWriter endArray() throws IOException {
if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endArray(); called with no active JSON document");
} else {
if (currentBlock.getType() != BlockType.ARRAY) {
ourLog.error("JsonLikeStreamWriter.endArray(); called outside a JSON array. (Use endObject() instead?)");
}
endBlock();
}
return this;
}
@Override
public JsonLikeWriter endBlock() {
if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document");
} else {
Object toPut = null;
if (currentBlock.getType() == BlockType.ARRAY) {
toPut = currentBlock.getArray();
} else {
toPut = currentBlock.getObject();
}
Block parentBlock = blockStack.pop();
if (parentBlock.getType() == BlockType.OBJECT) {
parentBlock.getObject().put(currentBlock.getName(), toPut);
} else
if (parentBlock.getType() == BlockType.ARRAY) {
parentBlock.getArray().add(toPut);
}
currentBlock = parentBlock;
}
return this;
}
}
}

View File

@ -1097,12 +1097,6 @@ public class JsonParserHl7OrgDstu2Test {
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"
*/

View File

@ -175,6 +175,11 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<!-- Dependencies for Schematron -->
<dependency>
@ -215,9 +220,8 @@
<!-- UNIT TEST DEPENDENCIES -->
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>apache-jena-libs</artifactId>
<type>pom</type>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<scope>test</scope>
</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
public void testEncodeBinary() {
@ -260,6 +266,18 @@ public class JsonParserR4Test extends BaseTest {
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
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: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
*
* 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
@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: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

View File

@ -1,5 +1,26 @@
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.Reader;
import java.io.StringReader;
@ -14,31 +35,6 @@ import java.util.Map;
import java.util.Set;
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 {
private static FhirContext ourCtx = FhirContext.forR4();
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);
ourLog.info(encoded);
JsonLikeStructure jsonLikeStructure = new GsonStructure();
JsonLikeStructure jsonLikeStructure = new JacksonStructure();
jsonLikeStructure.load(new StringReader(encoded));
IJsonLikeParser jsonLikeparser = (IJsonLikeParser)ourCtx.newJsonParser();
@ -258,17 +254,6 @@ public class JsonLikeParserTest {
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
public JsonLikeWriter beginObject(String name) throws IOException {
if (currentBlock.getType() == BlockType.ARRAY) {
@ -429,15 +414,6 @@ public class JsonLikeParserTest {
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
public JsonLikeWriter endObject() throws IOException {
if (currentBlock.getType() == BlockType.NONE) {
@ -452,7 +428,7 @@ public class JsonLikeParserTest {
}
@Override
public JsonLikeWriter endArray() throws IOException {
public JsonLikeWriter endArray() {
if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endArray(); called with no active JSON document");
} else {
@ -465,11 +441,11 @@ public class JsonLikeParserTest {
}
@Override
public JsonLikeWriter endBlock() throws IOException {
public JsonLikeWriter endBlock() {
if (currentBlock.getType() == BlockType.NONE) {
ourLog.error("JsonLikeStreamWriter.endBlock(); called with no active JSON document");
} else {
Object toPut = null;
Object toPut;
if (currentBlock.getType() == BlockType.ARRAY) {
toPut = currentBlock.getArray();
} else {
@ -544,14 +520,9 @@ public class JsonLikeParserTest {
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 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) {
this.nativeObject = json;
@ -585,7 +556,7 @@ public class JsonLikeParserTest {
private class JsonMapArray extends JsonLikeArray {
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) {
this.nativeArray = json;
@ -603,7 +574,7 @@ public class JsonLikeParserTest {
@Override
public JsonLikeValue get(int index) {
Integer key = Integer.valueOf(index);
Integer key = index;
JsonLikeValue result = null;
if (jsonLikeMap.containsKey(key)) {
result = jsonLikeMap.get(key);
@ -694,7 +665,7 @@ public class JsonLikeParserTest {
@Override
public boolean getAsBoolean() {
if (nativeValue != null && isBoolean()) {
return ((Boolean)nativeValue).booleanValue();
return (Boolean) nativeValue;
}
return super.getAsBoolean();
}

View File

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

View File

@ -35,12 +35,16 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.Invocation;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*;
@ -201,12 +205,13 @@ public class ConsentInterceptorTest {
assertThat(responseContent, containsString("A DIAG"));
}
verify(myConsentSvc, times(1)).startOperation(any(), any());
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any());
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any());
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any());
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
verify(myConsentSvc, timeout(10000).times(1)).startOperation(any(), any());
verify(myConsentSvc, timeout(10000).times(2)).canSeeResource(any(), any(), any());
verify(myConsentSvc, timeout(10000).times(3)).willSeeResource(any(), any(), any());
verify(myConsentSvc, timeout(10000).times(1)).completeOperationSuccess(any(), any());
verify(myConsentSvc, timeout(10000).times(0)).completeOperationFailure(any(), any(), any());
verifyNoMoreInteractions(myConsentSvc);
}
@Test
@ -241,6 +246,7 @@ public class ConsentInterceptorTest {
ourPatientProvider.store((Patient) new Patient().setActive(true).setId("PTA"));
ourPatientProvider.store((Patient) new Patient().setActive(false).setId("PTB"));
reset(myConsentSvc);
when(myConsentSvc.startOperation(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->{
@ -266,10 +272,10 @@ public class ConsentInterceptorTest {
assertEquals("PTB", response.getEntry().get(1).getResource().getIdElement().getIdPart());
}
verify(myConsentSvc, times(1)).startOperation(any(), any());
verify(myConsentSvc, times(2)).canSeeResource(any(), any(), any());
verify(myConsentSvc, times(3)).willSeeResource(any(), any(), any());
verify(myConsentSvc, times(1)).completeOperationSuccess(any(), any());
verify(myConsentSvc, timeout(1000).times(1)).startOperation(any(), any());
verify(myConsentSvc, timeout(1000).times(2)).canSeeResource(any(), any(), any());
verify(myConsentSvc, timeout(1000).times(3)).willSeeResource(any(), any(), any());
verify(myConsentSvc, timeout(1000).times(1)).completeOperationSuccess(any(), any());
verify(myConsentSvc, times(0)).completeOperationFailure(any(), any(), any());
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.RestfulServer;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
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.Patient;
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.nio.charset.StandardCharsets;
@ -30,11 +35,12 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.*;
import ca.uhn.fhir.test.utilities.JettyUtil;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class InterceptorThrowingExceptionR4Test {
@ -57,7 +63,7 @@ public class InterceptorThrowingExceptionR4Test {
}
@After
public void after(){
public void after() {
ourServlet.getInterceptorService().unregisterAllInterceptors();
}
@ -84,26 +90,26 @@ public class InterceptorThrowingExceptionR4Test {
@Test
public void testFailureInProcessingCompletedNormally() throws Exception {
final List<Integer> hit = new ArrayList<>();
final List<Integer> hit = Collections.synchronizedList(new ArrayList<>());
ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() {
@Override
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
hit.add(1);
throw new NullPointerException();
throw new NullPointerException("Hit 1");
}
});
ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() {
@Override
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
hit.add(2);
throw new NullPointerException();
throw new NullPointerException("Hit 2");
}
});
ourServlet.getInterceptorService().registerInterceptor(new InterceptorAdapter() {
@Override
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
hit.add(3);
throw new NullPointerException();
throw new NullPointerException("Hit 3");
}
});
@ -119,6 +125,9 @@ public class InterceptorThrowingExceptionR4Test {
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(response, containsString("FAM"));
assertTrue(ourHitMethod);
await().until(() -> hit.size() == 3);
ourLog.info("Hit: {}", hit);
assertThat("Hits: " + hit.toString(), hit, contains(1, 2, 3));
@ -165,7 +174,7 @@ public class InterceptorThrowingExceptionR4Test {
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
JettyUtil.startServer(ourServer);
ourPort = JettyUtil.getPortForStartedServer(ourServer);
ourPort = JettyUtil.getPortForStartedServer(ourServer);
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();

View File

@ -66,6 +66,10 @@
<version>${project.version}</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>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>

View File

@ -1,42 +1,59 @@
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.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
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()
public class Controller extends BaseController {
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Controller.class);

View File

@ -46,6 +46,15 @@
<artifactId>jsr305</artifactId>
</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
-->