Support JSON-like resource structures (#469)
* rebuild on 2.1 code and add more test coverage * additional test coverage
This commit is contained in:
parent
79e14798cd
commit
913fd32c2b
|
@ -0,0 +1,101 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeStructure;
|
||||
import ca.uhn.fhir.parser.json.JsonLikeWriter;
|
||||
|
||||
/**
|
||||
* An extension to the parser interface that is implemented by parsers that understand a generalized form of
|
||||
* JSON data. This generalized form uses Map-like, List-like, and scalar elements to construct resources.
|
||||
* <p>
|
||||
* Thread safety: <b>Parsers are not guaranteed to be thread safe</b>. Create a new parser instance for every thread or
|
||||
* every message being parsed/encoded.
|
||||
* </p>
|
||||
*/
|
||||
public interface IJsonLikeParser extends IParser {
|
||||
|
||||
void encodeBundleToJsonLikeWriter(Bundle theBundle, JsonLikeWriter theJsonLikeWriter) throws IOException, DataFormatException;
|
||||
|
||||
void encodeResourceToJsonLikeWriter(IBaseResource theResource, JsonLikeWriter theJsonLikeWriter) throws IOException, DataFormatException;
|
||||
|
||||
void encodeTagListToJsonLikeWriter(TagList theTagList, JsonLikeWriter theJsonLikeWriter) throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Parse a DSTU1 style Atom Bundle. Note that as of DSTU2, Bundle is a resource so you should use
|
||||
* {@link #parseResource(Class, JsonLikeStructure)} with the Bundle class found in the
|
||||
* <code>ca.uhn.hapi.fhir.model.[version].resource</code> package instead.
|
||||
*/
|
||||
<T extends IBaseResource> Bundle parseBundle(Class<T> theResourceType, JsonLikeStructure theJsonLikeStructure);
|
||||
|
||||
/**
|
||||
* Parse a DSTU1 style Atom Bundle. Note that as of DSTU2, Bundle is a resource so you should use
|
||||
* {@link #parseResource(Class, JsonLikeStructure)} with the Bundle class found in the
|
||||
* <code>ca.uhn.hapi.fhir.model.[version].resource</code> package instead.
|
||||
*/
|
||||
Bundle parseBundle(JsonLikeStructure theJsonLikeStructure) throws DataFormatException;
|
||||
|
||||
/**
|
||||
* Parses a resource from a JSON-like data structure
|
||||
*
|
||||
* @param theResourceType
|
||||
* The resource type to use. This can be used to explicitly specify a class which extends a built-in type
|
||||
* (e.g. a custom type extending the default Patient class)
|
||||
* @param theJsonLikeStructure
|
||||
* The JSON-like structure to parse
|
||||
* @return A parsed resource
|
||||
* @throws DataFormatException
|
||||
* If the resource can not be parsed because the data is not recognized or invalid for any reason
|
||||
*/
|
||||
<T extends IBaseResource> T parseResource(Class<T> theResourceType, JsonLikeStructure theJsonLikeStructure) throws DataFormatException;
|
||||
|
||||
|
||||
/**
|
||||
* Parses a resource from a JSON-like data structure
|
||||
*
|
||||
* @param theJsonLikeStructure
|
||||
* The JSON-like structure to parse
|
||||
* @return A parsed resource. Note that the returned object will be an instance of {@link IResource} or
|
||||
* {@link IAnyResource} depending on the specific FhirContext which created this parser.
|
||||
* @throws DataFormatException
|
||||
* If the resource can not be parsed because the data is not recognized or invalid for any reason
|
||||
*/
|
||||
IBaseResource parseResource(JsonLikeStructure theJsonLikeStructure) throws DataFormatException;
|
||||
|
||||
/**
|
||||
* Parses a tag list from a JSON-like data structure
|
||||
*
|
||||
* @param theJsonLikeStructure
|
||||
* The JSON-like structure to parse
|
||||
* @return A parsed tag list
|
||||
*/
|
||||
TagList parseTagList(JsonLikeStructure theJsonLikeStructure);
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,389 @@
|
|||
package ca.uhn.fhir.parser.json;
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import 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 GsonStructure (JsonObject json) {
|
||||
super();
|
||||
setNativeObject(json);
|
||||
}
|
||||
public GsonStructure (JsonArray json) {
|
||||
super();
|
||||
setNativeArray(json);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
package ca.uhn.fhir.parser.json;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package ca.uhn.fhir.parser.json;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
public abstract class JsonLikeArray extends JsonLikeValue {
|
||||
|
||||
@Override
|
||||
public ValueType getJsonType() {
|
||||
return ValueType.ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType getDataType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeArray getAsArray() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract int size ();
|
||||
|
||||
public abstract JsonLikeValue get (int index);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package ca.uhn.fhir.parser.json;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
public abstract class JsonLikeObject extends JsonLikeValue {
|
||||
|
||||
@Override
|
||||
public ValueType getJsonType() {
|
||||
return ValueType.OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType getDataType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObject() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonLikeObject getAsObject() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract Set<String> keySet ();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
package ca.uhn.fhir.parser.json;
|
||||
|
||||
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
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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);
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
package ca.uhn.fhir.parser.json;
|
||||
|
||||
/**
|
||||
* This is the generalization of anything that is a "value"
|
||||
* element in a JSON structure. This could be a JSON object,
|
||||
* a JSON array, a scalar value (number, string, boolean),
|
||||
* or a null.
|
||||
*
|
||||
*/
|
||||
public abstract class JsonLikeValue {
|
||||
|
||||
public enum ValueType {
|
||||
ARRAY, OBJECT, SCALAR, NULL
|
||||
};
|
||||
|
||||
public enum ScalarType {
|
||||
NUMBER, STRING, BOOLEAN
|
||||
}
|
||||
|
||||
public abstract ValueType getJsonType ();
|
||||
|
||||
public abstract ScalarType getDataType ();
|
||||
|
||||
public abstract Object getValue ();
|
||||
|
||||
public boolean isArray () {
|
||||
return this.getJsonType() == ValueType.ARRAY;
|
||||
}
|
||||
|
||||
public boolean isObject () {
|
||||
return this.getJsonType() == ValueType.OBJECT;
|
||||
}
|
||||
|
||||
public boolean isScalar () {
|
||||
return this.getJsonType() == ValueType.SCALAR;
|
||||
}
|
||||
|
||||
public boolean isString () {
|
||||
return this.getJsonType() == ValueType.SCALAR && this.getDataType() == ScalarType.STRING;
|
||||
}
|
||||
|
||||
public boolean isNumber () {
|
||||
return this.getJsonType() == ValueType.SCALAR && this.getDataType() == ScalarType.NUMBER;
|
||||
}
|
||||
|
||||
public boolean isNull () {
|
||||
return this.getJsonType() == ValueType.NULL;
|
||||
}
|
||||
|
||||
public JsonLikeArray getAsArray () {
|
||||
return null;
|
||||
}
|
||||
public JsonLikeObject getAsObject () {
|
||||
return null;
|
||||
}
|
||||
public String getAsString () {
|
||||
return this.toString();
|
||||
}
|
||||
public Number getAsNumber () {
|
||||
return this.isNumber() ? (Number)this.getValue() : null;
|
||||
}
|
||||
public boolean getAsBoolean () {
|
||||
return !isNull();
|
||||
}
|
||||
|
||||
public static JsonLikeArray asArray (JsonLikeValue element) {
|
||||
if (element != null) {
|
||||
return element.getAsArray();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static JsonLikeObject asObject (JsonLikeValue element) {
|
||||
if (element != null) {
|
||||
return element.getAsObject();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static String asString (JsonLikeValue element) {
|
||||
if (element != null) {
|
||||
return element.getAsString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static boolean asBoolean (JsonLikeValue element) {
|
||||
if (element != null) {
|
||||
return element.getAsBoolean();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static final JsonLikeValue NULL = new JsonLikeValue() {
|
||||
@Override
|
||||
public ValueType getJsonType() {
|
||||
return ValueType.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType getDataType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object obj) {
|
||||
if (this == obj){
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof JsonLikeValue) {
|
||||
return getJsonType().equals(((JsonLikeValue)obj).getJsonType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return "null".hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "null";
|
||||
}
|
||||
};
|
||||
|
||||
public static final JsonLikeValue TRUE = new JsonLikeValue() {
|
||||
@Override
|
||||
public ValueType getJsonType() {
|
||||
return ValueType.SCALAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType getDataType() {
|
||||
return ScalarType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj){
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof JsonLikeValue) {
|
||||
return getJsonType().equals(((JsonLikeValue)obj).getJsonType())
|
||||
&& getDataType().equals(((JsonLikeValue)obj).getDataType())
|
||||
&& toString().equals(((JsonLikeValue)obj).toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return "true".hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "true";
|
||||
}
|
||||
};
|
||||
|
||||
public static final JsonLikeValue FALSE = new JsonLikeValue() {
|
||||
@Override
|
||||
public ValueType getJsonType() {
|
||||
return ValueType.SCALAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType getDataType() {
|
||||
return ScalarType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj){
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof JsonLikeValue) {
|
||||
return getJsonType().equals(((JsonLikeValue)obj).getJsonType())
|
||||
&& getDataType().equals(((JsonLikeValue)obj).getDataType())
|
||||
&& toString().equals(((JsonLikeValue)obj).toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return "false".hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "false";
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package ca.uhn.fhir.parser.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package ca.uhn.fhir.parser.json;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
||||
public class JsonLikeStructureTest {
|
||||
private static FhirContext ourCtx;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeStructureTest.class);
|
||||
|
||||
private static final String TEST_STRUCTURELOADING_DATA =
|
||||
"{" +
|
||||
" \"resourceType\":\"Organization\"," +
|
||||
" \"id\":\"11111\"," +
|
||||
" \"meta\":{" +
|
||||
" \"lastUpdated\":\"3900-09-20T10:10:10.000-07:00\"" +
|
||||
" }," +
|
||||
" \"identifier\":[" +
|
||||
" {" +
|
||||
" \"value\":\"15250\"" +
|
||||
" }" +
|
||||
" ]," +
|
||||
" \"type\":{" +
|
||||
" \"coding\":[" +
|
||||
" {" +
|
||||
" \"system\":\"http://test\"," +
|
||||
" \"code\":\"ins\"," +
|
||||
" \"display\":\"General Ledger System\"," +
|
||||
" \"userSelected\":false" +
|
||||
" }" +
|
||||
" ]" +
|
||||
" }," +
|
||||
" \"name\":\"Acme Investments\"" +
|
||||
"}";
|
||||
|
||||
@Test
|
||||
public void testStructureLoading() {
|
||||
StringReader reader = new StringReader(TEST_STRUCTURELOADING_DATA);
|
||||
JsonLikeStructure jsonStructure = new GsonStructure();
|
||||
jsonStructure.load(reader);
|
||||
|
||||
JsonLikeObject rootObject = jsonStructure.getRootObject();
|
||||
|
||||
assertNotNull(rootObject);
|
||||
assertEquals(JsonLikeValue.ValueType.OBJECT, rootObject.getJsonType());
|
||||
}
|
||||
|
||||
private static final String TEST_JSONTYPES_DATA =
|
||||
"{" +
|
||||
" \"scalar-string\":\"A scalar string\"," +
|
||||
" \"scalar-number\":11111," +
|
||||
" \"scalar-boolean\":true," +
|
||||
" \"null-value\":null," +
|
||||
" \"object-value\":{" +
|
||||
" \"lastUpdated\":\"3900-09-20T10:10:10.000-07:00\"," +
|
||||
" \"deleted\":\"3909-09-20T10:10:10.000-07:00\"" +
|
||||
" }," +
|
||||
" \"array-value\":[" +
|
||||
" 12345," +
|
||||
" {" +
|
||||
" \"value\":\"15250\"" +
|
||||
" }" +
|
||||
" ]" +
|
||||
"}";
|
||||
|
||||
|
||||
@Test
|
||||
public void testJsonAndDataTypes() {
|
||||
StringReader reader = new StringReader(TEST_JSONTYPES_DATA);
|
||||
JsonLikeStructure jsonStructure = new GsonStructure();
|
||||
jsonStructure.load(reader);
|
||||
|
||||
JsonLikeObject rootObject = jsonStructure.getRootObject();
|
||||
|
||||
assertNotNull(rootObject);
|
||||
|
||||
JsonLikeValue value = rootObject.get("object-value");
|
||||
assertNotNull(value);
|
||||
assertEquals(JsonLikeValue.ValueType.OBJECT, value.getJsonType());
|
||||
assertEquals(true, value.isObject());
|
||||
assertEquals(false, value.isArray());
|
||||
assertEquals(false, value.isScalar());
|
||||
assertEquals(false, value.isNull());
|
||||
|
||||
JsonLikeObject obj = value.getAsObject();
|
||||
assertNotNull(obj);
|
||||
assertEquals(JsonLikeValue.ValueType.OBJECT, obj.getJsonType());
|
||||
assertEquals(true, obj.isObject());
|
||||
assertEquals(false, obj.isArray());
|
||||
assertEquals(false, obj.isScalar());
|
||||
assertEquals(false, obj.isNull());
|
||||
|
||||
value = rootObject.get("array-value");
|
||||
assertNotNull(value);
|
||||
assertEquals(JsonLikeValue.ValueType.ARRAY, value.getJsonType());
|
||||
assertEquals(false, value.isObject());
|
||||
assertEquals(true, value.isArray());
|
||||
assertEquals(false, value.isScalar());
|
||||
assertEquals(false, value.isNull());
|
||||
|
||||
JsonLikeArray array = value.getAsArray();
|
||||
assertNotNull(array);
|
||||
assertEquals(JsonLikeValue.ValueType.ARRAY, array.getJsonType());
|
||||
assertEquals(false, array.isObject());
|
||||
assertEquals(true, array.isArray());
|
||||
assertEquals(false, array.isScalar());
|
||||
assertEquals(false, array.isNull());
|
||||
|
||||
value = rootObject.get("null-value");
|
||||
assertNotNull(value);
|
||||
assertEquals(JsonLikeValue.ValueType.NULL, value.getJsonType());
|
||||
assertEquals(false, value.isObject());
|
||||
assertEquals(false, value.isArray());
|
||||
assertEquals(false, value.isScalar());
|
||||
assertEquals(true, value.isNull());
|
||||
|
||||
value = rootObject.get("scalar-string");
|
||||
assertNotNull(value);
|
||||
assertEquals(JsonLikeValue.ValueType.SCALAR, value.getJsonType());
|
||||
assertEquals(false, value.isObject());
|
||||
assertEquals(false, value.isArray());
|
||||
assertEquals(true, value.isScalar());
|
||||
assertEquals(false, value.isNull());
|
||||
assertEquals(JsonLikeValue.ScalarType.STRING, value.getDataType());
|
||||
assertEquals(value.getAsString(), "A scalar string");
|
||||
|
||||
value = rootObject.get("scalar-number");
|
||||
assertNotNull(value);
|
||||
assertEquals(JsonLikeValue.ValueType.SCALAR, value.getJsonType());
|
||||
assertEquals(JsonLikeValue.ScalarType.NUMBER, value.getDataType());
|
||||
assertEquals(value.getAsString(), "11111");
|
||||
|
||||
value = rootObject.get("scalar-boolean");
|
||||
assertNotNull(value);
|
||||
assertEquals(JsonLikeValue.ValueType.SCALAR, value.getJsonType());
|
||||
assertEquals(JsonLikeValue.ScalarType.BOOLEAN, value.getDataType());
|
||||
assertEquals(value.getAsString(), "true");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
package ca.uhn.fhir.parser.jsonlike;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IJsonLikeParser;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.parser.JsonParser;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.parser.XmlParser;
|
||||
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;
|
||||
import net.sf.json.JSON;
|
||||
import net.sf.json.JSONSerializer;
|
||||
|
||||
public class JsonLikeParserTest {
|
||||
private static FhirContext ourCtx;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserTest.class);
|
||||
|
||||
@Test
|
||||
public void testJsonLikeSimpleBundleEncode() throws InterruptedException, IOException {
|
||||
String xmlString = IOUtils.toString(JsonParser.class.getResourceAsStream("/atom-document-large.xml"), Charset.forName("UTF-8"));
|
||||
Bundle obs = ourCtx.newXmlParser().parseBundle(xmlString);
|
||||
|
||||
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser().setPrettyPrint(true);
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonLikeStructure jsonLikeStructure = new GsonStructure();
|
||||
JsonLikeWriter jsonLikeWriter = jsonLikeStructure.getJsonLikeWriter(stringWriter);
|
||||
jsonLikeParser.encodeBundleToJsonLikeWriter(obs, jsonLikeWriter);
|
||||
String encoded = stringWriter.toString();
|
||||
ourLog.info(encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonLikeSimpleResourceEncode() throws IOException {
|
||||
|
||||
String xmlString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.xml"), Charset.forName("UTF-8"));
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||
Patient obs = parser.parseResource(Patient.class, xmlString);
|
||||
|
||||
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser();
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonLikeStructure jsonLikeStructure = new GsonStructure();
|
||||
JsonLikeWriter jsonLikeWriter = jsonLikeStructure.getJsonLikeWriter(stringWriter);
|
||||
jsonLikeParser.encodeResourceToJsonLikeWriter(obs, jsonLikeWriter);
|
||||
String encoded = stringWriter.toString();
|
||||
ourLog.info(encoded);
|
||||
|
||||
String jsonString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.json"), Charset.forName("UTF-8"));
|
||||
|
||||
JSON expected = JSONSerializer.toJSON(jsonString);
|
||||
JSON actual = JSONSerializer.toJSON(encoded.trim());
|
||||
|
||||
// The encoded escapes quote marks using XML escaping instead of JSON escaping, which is probably nicer anyhow...
|
||||
String exp = expected.toString().replace("\\\"Jim\\\"", ""Jim"");
|
||||
String act = actual.toString();
|
||||
|
||||
ourLog.info("Expected: {}", exp);
|
||||
ourLog.info("Actual : {}", act);
|
||||
assertEquals("\nExpected: " + exp + "\nActual : " + act, exp, act);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonLikeSimpleResourceParse() throws DataFormatException, IOException {
|
||||
|
||||
String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/example-patient-general.json"));
|
||||
|
||||
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser().setPrettyPrint(true);
|
||||
StringReader reader = new StringReader(msg);
|
||||
JsonLikeStructure jsonLikeStructure = new GsonStructure();
|
||||
jsonLikeStructure.load(reader);
|
||||
|
||||
Patient res = jsonLikeParser.parseResource(Patient.class, jsonLikeStructure);
|
||||
|
||||
assertEquals(2, res.getUndeclaredExtensions().size());
|
||||
assertEquals(1, res.getUndeclaredModifierExtensions().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonLikeParseBundle() throws DataFormatException, IOException {
|
||||
|
||||
String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/atom-document-large.json"));
|
||||
|
||||
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser().setPrettyPrint(true);
|
||||
StringReader reader = new StringReader(msg);
|
||||
JsonLikeStructure jsonLikeStructure = new GsonStructure();
|
||||
jsonLikeStructure.load(reader);
|
||||
|
||||
Bundle bundle = jsonLikeParser.parseBundle(jsonLikeStructure);
|
||||
|
||||
assertEquals(1, bundle.getCategories().size());
|
||||
assertEquals("http://scheme", bundle.getCategories().get(0).getScheme());
|
||||
assertEquals("http://term", bundle.getCategories().get(0).getTerm());
|
||||
assertEquals("label", bundle.getCategories().get(0).getLabel());
|
||||
|
||||
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertEquals("http://fhir.healthintersections.com.au/open/DiagnosticReport/_search?_format=application/json+fhir&search-id=46d5f0e7-9240-4d4f-9f51-f8ac975c65&search-sort=_id",
|
||||
bundle.getLinkSelf().getValue());
|
||||
assertEquals("urn:uuid:0b754ff9-03cf-4322-a119-15019af8a3", bundle.getBundleId().getValue());
|
||||
|
||||
BundleEntry entry = bundle.getEntries().get(0);
|
||||
assertEquals("http://fhir.healthintersections.com.au/open/DiagnosticReport/101", entry.getId().getValue());
|
||||
assertEquals("http://fhir.healthintersections.com.au/open/DiagnosticReport/101/_history/1", entry.getLinkSelf().getValue());
|
||||
assertEquals("2014-03-10T11:55:59Z", entry.getUpdated().getValueAsString());
|
||||
|
||||
DiagnosticReport res = (DiagnosticReport) entry.getResource();
|
||||
assertEquals("Complete Blood Count", res.getName().getText().getValue());
|
||||
|
||||
assertThat(entry.getSummary().getValueAsString(), containsString("CBC Report for Wile"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonLikeTagList() throws IOException {
|
||||
|
||||
//@formatter:off
|
||||
String tagListStr = "{\n" +
|
||||
" \"resourceType\" : \"TagList\", " +
|
||||
" \"category\" : [" +
|
||||
" { " +
|
||||
" \"term\" : \"term0\", " +
|
||||
" \"label\" : \"label0\", " +
|
||||
" \"scheme\" : \"scheme0\" " +
|
||||
" }," +
|
||||
" { " +
|
||||
" \"term\" : \"term1\", " +
|
||||
" \"label\" : \"label1\", " +
|
||||
" \"scheme\" : null " +
|
||||
" }," +
|
||||
" { " +
|
||||
" \"term\" : \"term2\", " +
|
||||
" \"label\" : \"label2\" " +
|
||||
" }" +
|
||||
" ] " +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
IJsonLikeParser jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser().setPrettyPrint(true);
|
||||
StringReader reader = new StringReader(tagListStr);
|
||||
JsonLikeStructure jsonLikeStructure = new GsonStructure();
|
||||
jsonLikeStructure.load(reader);
|
||||
|
||||
TagList tagList = jsonLikeParser.parseTagList(jsonLikeStructure);
|
||||
assertEquals(3, tagList.size());
|
||||
assertEquals("term0", tagList.get(0).getTerm());
|
||||
assertEquals("label0", tagList.get(0).getLabel());
|
||||
assertEquals("scheme0", tagList.get(0).getScheme());
|
||||
assertEquals("term1", tagList.get(1).getTerm());
|
||||
assertEquals("label1", tagList.get(1).getLabel());
|
||||
assertEquals(null, tagList.get(1).getScheme());
|
||||
assertEquals("term2", tagList.get(2).getTerm());
|
||||
assertEquals("label2", tagList.get(2).getLabel());
|
||||
assertEquals(null, tagList.get(2).getScheme());
|
||||
|
||||
/*
|
||||
* Encode
|
||||
*/
|
||||
|
||||
//@formatter:off
|
||||
String expected = "{" +
|
||||
"\"resourceType\":\"TagList\"," +
|
||||
"\"category\":[" +
|
||||
"{" +
|
||||
"\"term\":\"term0\"," +
|
||||
"\"label\":\"label0\"," +
|
||||
"\"scheme\":\"scheme0\"" +
|
||||
"}," +
|
||||
"{" +
|
||||
"\"term\":\"term1\"," +
|
||||
"\"label\":\"label1\"" +
|
||||
"}," +
|
||||
"{" +
|
||||
"\"term\":\"term2\"," +
|
||||
"\"label\":\"label2\"" +
|
||||
"}" +
|
||||
"]" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
|
||||
jsonLikeParser = (IJsonLikeParser)ourCtx.newJsonParser();
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
jsonLikeStructure = new GsonStructure();
|
||||
JsonLikeWriter jsonLikeWriter = jsonLikeStructure.getJsonLikeWriter(stringWriter);
|
||||
jsonLikeParser.encodeTagListToJsonLikeWriter(tagList, jsonLikeWriter);
|
||||
String encoded = stringWriter.toString();
|
||||
assertEquals(expected, encoded);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forDstu1();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -1688,7 +1688,7 @@ public class JsonParserDstu2Test {
|
|||
ourCtx.newJsonParser().parseResource(Conformance.class, input);
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("Syntax error parsing JSON FHIR structure: Expected ARRAY at element 'modifierExtension', found 'JsonObject'", e.getMessage());
|
||||
assertEquals("Syntax error parsing JSON FHIR structure: Expected ARRAY at element 'modifierExtension', found 'OBJECT'", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package ca.uhn.fhir.parser.jsonlike;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
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;
|
||||
|
||||
public class JsonLikeParserDstu2Test {
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonLikeParserDstu2Test.class);
|
||||
|
||||
/**
|
||||
* Test for #146
|
||||
*/
|
||||
@Test
|
||||
public void testJsonLikeParseAndEncodeBundleFromXmlToJson() throws Exception {
|
||||
String content = IOUtils.toString(JsonLikeParserDstu2Test.class.getResourceAsStream("/bundle-example2.xml"));
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.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();
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = jsonLikeparser.parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, jsonLikeStructure);
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue