Merge remote-tracking branch 'remotes/origin/master' into ks-subscription-delivery-queue-configurable-name

This commit is contained in:
Ken Stevens 2019-10-01 09:20:00 -04:00
commit ade9e0316e
21 changed files with 495 additions and 327 deletions

View File

@ -66,13 +66,17 @@ public abstract class BaseRuntimeChildDefinition {
} }
public interface IAccessor { public interface IAccessor {
List<IBase> getValues(Object theTarget); List<IBase> getValues(IBase theTarget);
default IBase getFirstValueOrNull(IBase theTarget) {
return getValues(theTarget).stream().findFirst().orElse(null);
}
} }
public interface IMutator { public interface IMutator {
void addValue(Object theTarget, IBase theValue); void addValue(IBase theTarget, IBase theValue);
void setValue(Object theTarget, IBase theValue); void setValue(IBase theTarget, IBase theValue);
} }
BaseRuntimeElementDefinition<?> findResourceReferenceDefinition(Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) { BaseRuntimeElementDefinition<?> findResourceReferenceDefinition(Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {

View File

@ -20,34 +20,33 @@ package ca.uhn.fhir.context;
* #L% * #L%
*/ */
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.util.ValidateUtil;
public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition { public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition {
private final IAccessor myAccessor; private final IAccessor myAccessor;
private String myBindingValueSet;
private final String myElementName; private final String myElementName;
private final Field myField; private final Field myField;
private final String myFormalDefinition; private final String myFormalDefinition;
private final int myMax; private final int myMax;
private final int myMin; private final int myMin;
private boolean myModifier;
private final IMutator myMutator; private final IMutator myMutator;
private final String myShortDefinition; private final String myShortDefinition;
private String myBindingValueSet;
private boolean myModifier;
private boolean mySummary; private boolean mySummary;
BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException { BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException {
super(); super();
Validate.notNull(theField, "No field speficied"); Validate.notNull(theField, "No field specified");
ValidateUtil.isGreaterThanOrEqualTo(theChildAnnotation.min(), 0, "Min must be >= 0"); ValidateUtil.isGreaterThanOrEqualTo(theChildAnnotation.min(), 0, "Min must be >= 0");
Validate.isTrue(theChildAnnotation.max() == -1 || theChildAnnotation.max() >= theChildAnnotation.min(), "Max must be >= Min (unless it is -1 / unlimited)"); Validate.isTrue(theChildAnnotation.max() == -1 || theChildAnnotation.max() >= theChildAnnotation.min(), "Max must be >= Min (unless it is -1 / unlimited)");
Validate.notBlank(theElementName, "Element name must not be blank"); Validate.notBlank(theElementName, "Element name must not be blank");
@ -87,6 +86,10 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
return myBindingValueSet; return myBindingValueSet;
} }
void setBindingValueSet(String theBindingValueSet) {
myBindingValueSet = theBindingValueSet;
}
@Override @Override
public String getElementName() { public String getElementName() {
return myElementName; return myElementName;
@ -119,107 +122,99 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
return myShortDefinition; return myShortDefinition;
} }
public BaseRuntimeElementDefinition<?> getSingleChildOrThrow() {
if (getValidChildNames().size() != 1) {
throw new IllegalStateException("This child has " + getValidChildNames().size() + " children, expected 1. This is a HAPI bug. Found: " + getValidChildNames());
}
return getChildByName(getValidChildNames().iterator().next());
}
public boolean isModifier() { public boolean isModifier() {
return myModifier; return myModifier;
} }
protected void setModifier(boolean theModifier) {
myModifier = theModifier;
}
@Override @Override
public boolean isSummary() { public boolean isSummary() {
return mySummary; return mySummary;
} }
void setBindingValueSet(String theBindingValueSet) {
myBindingValueSet = theBindingValueSet;
}
protected void setModifier(boolean theModifier) {
myModifier = theModifier;
}
private final class FieldListAccessor implements IAccessor { private final class FieldListAccessor implements IAccessor {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public List<IBase> getValues(Object theTarget) { public List<IBase> getValues(IBase theTarget) {
List<IBase> retVal; List<IBase> retVal = (List<IBase>) getFieldValue(theTarget, myField);
try {
retVal = (List<IBase>) myField.get(theTarget);
} catch (Exception e) {
throw new ConfigurationException("Failed to get value", e);
}
if (retVal == null) { if (retVal == null) {
retVal = Collections.emptyList(); retVal = Collections.emptyList();
} }
return retVal; return retVal;
} }
} }
protected final class FieldListMutator implements IMutator { protected final class FieldListMutator implements IMutator {
@Override @Override
public void addValue(Object theTarget, IBase theValue) { public void addValue(IBase theTarget, IBase theValue) {
addValue(theTarget, theValue, false); addValue(theTarget, theValue, false);
} }
private void addValue(Object theTarget, IBase theValue, boolean theClear) { private void addValue(IBase theTarget, IBase theValue, boolean theClear) {
try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<IBase> existingList = (List<IBase>) myField.get(theTarget); List<IBase> existingList = (List<IBase>) getFieldValue(theTarget, myField);
if (existingList == null) { if (existingList == null) {
existingList = new ArrayList<IBase>(2); existingList = new ArrayList<>(2);
myField.set(theTarget, existingList); setFieldValue(theTarget, existingList, myField);
} }
if (theClear) { if (theClear) {
existingList.clear(); existingList.clear();
} }
existingList.add(theValue); existingList.add(theValue);
} catch (Exception e) {
throw new ConfigurationException("Failed to set value", e);
}
} }
@Override @Override
public void setValue(Object theTarget, IBase theValue) { public void setValue(IBase theTarget, IBase theValue) {
addValue(theTarget, theValue, true); addValue(theTarget, theValue, true);
} }
} }
private final class FieldPlainAccessor implements IAccessor { private final class FieldPlainAccessor implements IAccessor {
@Override @Override
public List<IBase> getValues(Object theTarget) { public List<IBase> getValues(IBase theTarget) {
try { Object values = getFieldValue(theTarget, myField);
Object values = myField.get(theTarget);
if (values == null) { if (values == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<IBase> retVal = Collections.singletonList((IBase) values); return Collections.singletonList((IBase) values);
return retVal;
} catch (Exception e) {
throw new ConfigurationException("Failed to get value", e);
} }
@Override
public IBase getFirstValueOrNull(IBase theTarget) {
return (IBase) getFieldValue(theTarget, myField);
} }
} }
protected final class FieldPlainMutator implements IMutator { protected final class FieldPlainMutator implements IMutator {
@Override @Override
public void addValue(Object theTarget, IBase theValue) { public void addValue(IBase theTarget, IBase theValue) {
try { setFieldValue(theTarget, theValue, myField);
myField.set(theTarget, theValue);
} catch (Exception e) {
throw new ConfigurationException("Failed to set value", e);
}
} }
@Override @Override
public void setValue(Object theTarget, IBase theValue) { public void setValue(IBase theTarget, IBase theValue) {
addValue(theTarget, theValue); addValue(theTarget, theValue);
} }
} }
private static void setFieldValue(IBase theTarget, Object theValue, Field theField) {
try {
theField.set(theTarget, theValue);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to set value", e);
}
}
private static Object getFieldValue(IBase theTarget, Field theField) {
try {
return theField.get(theTarget);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e);
}
}
} }

View File

@ -68,7 +68,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
public IAccessor getAccessor() { public IAccessor getAccessor() {
return new IAccessor() { return new IAccessor() {
@Override @Override
public List<IBase> getValues(Object theTarget) { public List<IBase> getValues(IBase theTarget) {
ExtensionDt target = (ExtensionDt) theTarget; ExtensionDt target = (ExtensionDt) theTarget;
if (target.getValue() != null) { if (target.getValue() != null) {
return Collections.singletonList((IBase) target.getValue()); return Collections.singletonList((IBase) target.getValue());
@ -76,6 +76,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
ArrayList<IBase> retVal = new ArrayList<IBase>(target.getUndeclaredExtensions()); ArrayList<IBase> retVal = new ArrayList<IBase>(target.getUndeclaredExtensions());
return retVal; return retVal;
} }
}; };
} }
@ -113,7 +114,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
public IMutator getMutator() { public IMutator getMutator() {
return new IMutator() { return new IMutator() {
@Override @Override
public void addValue(Object theTarget, IBase theValue) { public void addValue(IBase theTarget, IBase theValue) {
ExtensionDt target = (ExtensionDt) theTarget; ExtensionDt target = (ExtensionDt) theTarget;
if (theValue instanceof IDatatype) { if (theValue instanceof IDatatype) {
target.setValue((IDatatype) theTarget); target.setValue((IDatatype) theTarget);
@ -123,7 +124,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
} }
@Override @Override
public void setValue(Object theTarget, IBase theValue) { public void setValue(IBase theTarget, IBase theValue) {
ExtensionDt target = (ExtensionDt) theTarget; ExtensionDt target = (ExtensionDt) theTarget;
if (theValue instanceof IDatatype) { if (theValue instanceof IDatatype) {
target.setValue((IDatatype) theTarget); target.setValue((IDatatype) theTarget);

View File

@ -19,17 +19,6 @@ package ca.uhn.fhir.parser;
* limitations under the License. * limitations under the License.
* #L% * #L%
*/ */
import static org.apache.commons.lang3.StringUtils.*;
import java.util.*;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*; import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IMutator; import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IMutator;
@ -37,21 +26,32 @@ import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap; import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
import ca.uhn.fhir.model.primitive.*; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType; import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType; import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
import ca.uhn.fhir.util.*; import ca.uhn.fhir.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.api.*;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.*;
class ParserState<T> { class ParserState<T> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
private List<String> myComments = new ArrayList<String>(2);
private final FhirContext myContext; private final FhirContext myContext;
private final IParserErrorHandler myErrorHandler; private final IParserErrorHandler myErrorHandler;
private final boolean myJsonMode; private final boolean myJsonMode;
private T myObject;
private final IParser myParser; private final IParser myParser;
private List<String> myComments = new ArrayList<String>(2);
private T myObject;
private IBase myPreviousElement; private IBase myPreviousElement;
private BaseState myState; private BaseState myState;
@ -152,38 +152,6 @@ class ParserState<T> {
} }
} }
/**
* @param theResourceType
* May be null
*/
static <T extends IBaseResource> ParserState<T> getPreResourceInstance(IParser theParser, Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler)
throws DataFormatException {
ParserState<T> retVal = new ParserState<T>(theParser, theContext, theJsonMode, theErrorHandler);
if (theResourceType == null) {
if (theContext.getVersion().getVersion().isRi()) {
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
} else {
retVal.push(retVal.new PreResourceStateHapi(theResourceType));
}
} else {
if (IResource.class.isAssignableFrom(theResourceType)) {
retVal.push(retVal.new PreResourceStateHapi(theResourceType));
} else {
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
}
}
return retVal;
}
static ParserState<TagList> getPreTagListInstance(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
ParserState<TagList> retVal = new ParserState<TagList>(theParser, theContext, theJsonMode, theErrorHandler);
retVal.push(retVal.new PreTagListState());
return retVal;
}
private abstract class BaseState { private abstract class BaseState {
private PreResourceState myPreResourceState; private PreResourceState myPreResourceState;
@ -195,8 +163,7 @@ class ParserState<T> {
} }
/** /**
* @param theValue * @param theValue The attribute value
* The attribute value
*/ */
public void attributeValue(String theName, String theValue) throws DataFormatException { public void attributeValue(String theName, String theValue) throws DataFormatException {
myErrorHandler.unknownAttribute(null, theName); myErrorHandler.unknownAttribute(null, theName);
@ -211,8 +178,7 @@ class ParserState<T> {
} }
/** /**
* @param theNamespaceUri * @param theNamespaceUri The XML namespace (if XML) or null
* The XML namespace (if XML) or null
*/ */
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException { public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
myErrorHandler.unknownElement(null, theLocalPart); myErrorHandler.unknownElement(null, theLocalPart);
@ -275,8 +241,7 @@ class ParserState<T> {
} }
/** /**
* @param theData * @param theData The string value
* The string value
*/ */
public void string(String theData) { public void string(String theData) {
// ignore by default // ignore by default
@ -287,8 +252,7 @@ class ParserState<T> {
} }
/** /**
* @param theNextEvent * @param theNextEvent The XML event
* The XML event
*/ */
public void xmlEvent(XMLEvent theNextEvent) { public void xmlEvent(XMLEvent theNextEvent) {
// ignore // ignore
@ -890,7 +854,6 @@ class ParserState<T> {
} }
private abstract class PreResourceState extends BaseState { private abstract class PreResourceState extends BaseState {
private Map<String, IBaseResource> myContainedResources; private Map<String, IBaseResource> myContainedResources;
@ -1137,7 +1100,7 @@ class ParserState<T> {
private class PreResourceStateHapi extends PreResourceState { private class PreResourceStateHapi extends PreResourceState {
private IMutator myMutator; private IMutator myMutator;
private Object myTarget; private IBase myTarget;
public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) { public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
@ -1145,7 +1108,7 @@ class ParserState<T> {
assert theResourceType == null || IResource.class.isAssignableFrom(theResourceType); assert theResourceType == null || IResource.class.isAssignableFrom(theResourceType);
} }
public PreResourceStateHapi(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) { public PreResourceStateHapi(IBase theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType); super(theResourceType);
myTarget = theTarget; myTarget = theTarget;
myMutator = theMutator; myMutator = theMutator;
@ -1195,13 +1158,13 @@ class ParserState<T> {
private class PreResourceStateHl7Org extends PreResourceState { private class PreResourceStateHl7Org extends PreResourceState {
private IMutator myMutator; private IMutator myMutator;
private Object myTarget; private IBase myTarget;
public PreResourceStateHl7Org(Class<? extends IBaseResource> theResourceType) { public PreResourceStateHl7Org(Class<? extends IBaseResource> theResourceType) {
super(theResourceType); super(theResourceType);
} }
public PreResourceStateHl7Org(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) { public PreResourceStateHl7Org(IBase theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType); super(theResourceType);
myMutator = theMutator; myMutator = theMutator;
myTarget = theTarget; myTarget = theTarget;
@ -1604,4 +1567,32 @@ class ParserState<T> {
} }
/**
* @param theResourceType May be null
*/
static <T extends IBaseResource> ParserState<T> getPreResourceInstance(IParser theParser, Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler)
throws DataFormatException {
ParserState<T> retVal = new ParserState<T>(theParser, theContext, theJsonMode, theErrorHandler);
if (theResourceType == null) {
if (theContext.getVersion().getVersion().isRi()) {
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
} else {
retVal.push(retVal.new PreResourceStateHapi(theResourceType));
}
} else {
if (IResource.class.isAssignableFrom(theResourceType)) {
retVal.push(retVal.new PreResourceStateHapi(theResourceType));
} else {
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
}
}
return retVal;
}
static ParserState<TagList> getPreTagListInstance(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
ParserState<TagList> retVal = new ParserState<TagList>(theParser, theContext, theJsonMode, theErrorHandler);
retVal.push(retVal.new PreTagListState());
return retVal;
}
} }

View File

@ -354,17 +354,10 @@ public class XmlParser extends BaseParser {
} }
if (nextChild instanceof RuntimeChildNarrativeDefinition) { if (nextChild instanceof RuntimeChildNarrativeDefinition) {
INarrative narr = (INarrative) nextChild.getAccessor().getFirstValueOrNull(theElement);
INarrativeGenerator gen = myContext.getNarrativeGenerator(); INarrativeGenerator gen = myContext.getNarrativeGenerator();
INarrative narr; if (gen != null && (narr == null || narr.isEmpty())) {
if (theResource instanceof IResource) {
narr = ((IResource) theResource).getText();
} else if (theResource instanceof IDomainResource) {
narr = ((IDomainResource) theResource).getText();
} else {
narr = null;
}
// FIXME potential null access on narr see line 623
if (gen != null && narr.isEmpty()) {
gen.populateResourceNarrative(myContext, theResource); gen.populateResourceNarrative(myContext, theResource);
} }
if (narr != null && narr.isEmpty() == false) { if (narr != null && narr.isEmpty() == false) {

View File

@ -216,12 +216,12 @@ public class FhirTerser {
} }
public Object getSingleValueOrNull(IBase theTarget, String thePath) { public Object getSingleValueOrNull(IBase theTarget, String thePath) {
Class<Object> wantedType = Object.class; Class<IBase> wantedType = IBase.class;
return getSingleValueOrNull(theTarget, thePath, wantedType); return getSingleValueOrNull(theTarget, thePath, wantedType);
} }
public <T> T getSingleValueOrNull(IBase theTarget, String thePath, Class<T> theWantedType) { public <T extends IBase> T getSingleValueOrNull(IBase theTarget, String thePath, Class<T> theWantedType) {
Validate.notNull(theTarget, "theTarget must not be null"); Validate.notNull(theTarget, "theTarget must not be null");
Validate.notBlank(thePath, "thePath must not be empty"); Validate.notBlank(thePath, "thePath must not be empty");
@ -241,12 +241,12 @@ public class FhirTerser {
return retVal.get(0); return retVal.get(0);
} }
private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass) { private <T extends IBase> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, IBase theCurrentObj, List<String> theSubList, Class<T> theWantedClass) {
return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false, false); return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false, false);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) { private <T extends IBase> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, IBase theCurrentObj, List<String> theSubList, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
String name = theSubList.get(0); String name = theSubList.get(0);
List<T> retVal = new ArrayList<>(); List<T> retVal = new ArrayList<>();
@ -325,7 +325,7 @@ public class FhirTerser {
List<T> values = retVal; List<T> values = retVal;
retVal = new ArrayList<>(); retVal = new ArrayList<>();
for (T nextElement : values) { for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass()); BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension); List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues); retVal.addAll(foundValues);
} }
@ -410,7 +410,7 @@ public class FhirTerser {
List<T> values = retVal; List<T> values = retVal;
retVal = new ArrayList<>(); retVal = new ArrayList<>();
for (T nextElement : values) { for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass()); BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension); List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues); retVal.addAll(foundValues);
} }
@ -476,9 +476,10 @@ public class FhirTerser {
* @return A list of values of type {@link Object}. * @return A list of values of type {@link Object}.
*/ */
public List<Object> getValues(IBaseResource theResource, String thePath) { public List<Object> getValues(IBaseResource theResource, String thePath) {
Class<Object> wantedClass = Object.class; Class<IBase> wantedClass = IBase.class;
return getValues(theResource, thePath, wantedClass); List values = getValues(theResource, thePath, wantedClass);
return values;
} }
/** /**
@ -491,9 +492,10 @@ public class FhirTerser {
* @return A list of values of type {@link Object}. * @return A list of values of type {@link Object}.
*/ */
public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate) { public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate) {
Class<Object> wantedClass = Object.class; Class<IBase> wantedClass = IBase.class;
return getValues(theResource, thePath, wantedClass, theCreate); List retVal = getValues(theResource, thePath, wantedClass, theCreate);
return retVal;
} }
/** /**
@ -507,9 +509,10 @@ public class FhirTerser {
* @return A list of values of type {@link Object}. * @return A list of values of type {@link Object}.
*/ */
public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate, boolean theAddExtension) { public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate, boolean theAddExtension) {
Class<Object> wantedClass = Object.class; Class<IBase> wantedClass = IBase.class;
return getValues(theResource, thePath, wantedClass, theCreate, theAddExtension); List retVal = getValues(theResource, thePath, wantedClass, theCreate, theAddExtension);
return retVal;
} }
/** /**
@ -522,7 +525,7 @@ public class FhirTerser {
* @param <T> Type declared by <code>theWantedClass</code> * @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>. * @return A list of values of type <code>theWantedClass</code>.
*/ */
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass) { public <T extends IBase> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath); List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass); return getValues(def, theResource, parts, theWantedClass);
@ -539,7 +542,7 @@ public class FhirTerser {
* @param <T> Type declared by <code>theWantedClass</code> * @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>. * @return A list of values of type <code>theWantedClass</code>.
*/ */
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate) { public <T extends IBase> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath); List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass, theCreate, false); return getValues(def, theResource, parts, theWantedClass, theCreate, false);
@ -557,7 +560,7 @@ public class FhirTerser {
* @param <T> Type declared by <code>theWantedClass</code> * @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>. * @return A list of values of type <code>theWantedClass</code>.
*/ */
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) { public <T extends IBase> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath); List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass, theCreate, theAddExtension); return getValues(def, theResource, parts, theWantedClass, theCreate, theAddExtension);

View File

@ -276,6 +276,12 @@
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId> <artifactId>commons-dbcp2</artifactId>
<scope>test</scope> <scope>test</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
@ -500,6 +506,12 @@
<dependency> <dependency>
<groupId>org.hibernate</groupId> <groupId>org.hibernate</groupId>
<artifactId>hibernate-search-elasticsearch</artifactId> <artifactId>hibernate-search-elasticsearch</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- Misc --> <!-- Misc -->

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.dao; package ca.uhn.fhir.jpa.dao;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2019 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 ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.search.elastic; package ca.uhn.fhir.jpa.search.elastic;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2019 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 org.hibernate.search.cfg.Environment; import org.hibernate.search.cfg.Environment;
import org.hibernate.search.elasticsearch.cfg.ElasticsearchEnvironment; import org.hibernate.search.elasticsearch.cfg.ElasticsearchEnvironment;
import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus; import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus;

View File

@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.search.elastic;
/*- /*-
* #%L * #%L
* HAPI FHIR JPA Server - ElasticSearch Integration * HAPI FHIR JPA Server
* %% * %%
* Copyright (C) 2014 - 2019 University Health Network * Copyright (C) 2014 - 2019 University Health Network
* %% * %%

View File

@ -80,7 +80,6 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
bulkExportJob.addIndex("IDX_BLKEX_EXPTIME").unique(false).withColumns("EXP_TIME"); bulkExportJob.addIndex("IDX_BLKEX_EXPTIME").unique(false).withColumns("EXP_TIME");
bulkExportJob.addIndex("IDX_BLKEX_JOB_ID").unique(true).withColumns("JOB_ID"); bulkExportJob.addIndex("IDX_BLKEX_JOB_ID").unique(true).withColumns("JOB_ID");
// HFJ_BLK_EXPORT_COLLECTION // HFJ_BLK_EXPORT_COLLECTION
version.addIdGenerator("SEQ_BLKEXCOL_PID"); version.addIdGenerator("SEQ_BLKEXCOL_PID");
Builder.BuilderAddTableByColumns bulkExportCollection = version.addTableByColumns("HFJ_BLK_EXPORT_COLLECTION", "PID"); Builder.BuilderAddTableByColumns bulkExportCollection = version.addTableByColumns("HFJ_BLK_EXPORT_COLLECTION", "PID");
@ -99,7 +98,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
bulkExportCollectionFile.addColumn("RES_ID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 100); bulkExportCollectionFile.addColumn("RES_ID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 100);
bulkExportCollectionFile.addForeignKey("FK_BLKEXCOLFILE_COLLECT").toColumn("COLLECTION_PID").references("HFJ_BLK_EXPORT_COLLECTION", "PID"); bulkExportCollectionFile.addForeignKey("FK_BLKEXCOLFILE_COLLECT").toColumn("COLLECTION_PID").references("HFJ_BLK_EXPORT_COLLECTION", "PID");
// HFJ_RES_VER_PROV
version.startSectionWithMessage("Processing bulkExportCollectionFile: HFJ_RES_VER_PROV"); version.startSectionWithMessage("Processing bulkExportCollectionFile: HFJ_RES_VER_PROV");
Builder.BuilderAddTableByColumns resVerProv = version.addTableByColumns("HFJ_RES_VER_PROV", "RES_VER_PID"); Builder.BuilderAddTableByColumns resVerProv = version.addTableByColumns("HFJ_RES_VER_PROV", "RES_VER_PID");
resVerProv.addColumn("RES_VER_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); resVerProv.addColumn("RES_VER_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
@ -149,7 +148,6 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
.unique(true) .unique(true)
.withColumns("VALUESET_PID", "VALUESET_ORDER"); .withColumns("VALUESET_PID", "VALUESET_ORDER");
// Account for RESTYPE_LEN column increasing from 30 to 35 // Account for RESTYPE_LEN column increasing from 30 to 35
version.onTable("HFJ_RESOURCE").modifyColumn("RES_TYPE").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 35); version.onTable("HFJ_RESOURCE").modifyColumn("RES_TYPE").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 35);
version.onTable("HFJ_HISTORY_TAG").modifyColumn("RES_TYPE").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 35); version.onTable("HFJ_HISTORY_TAG").modifyColumn("RES_TYPE").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 35);
@ -165,8 +163,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
version.startSectionWithMessage("Processing table: TRM_VALUESET_C_DESIGNATION"); version.startSectionWithMessage("Processing table: TRM_VALUESET_C_DESIGNATION");
version.onTable("TRM_VALUESET_C_DESIGNATION").modifyColumn("VAL").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 2000); version.onTable("TRM_VALUESET_C_DESIGNATION").modifyColumn("VAL").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 2000);
// TermConceptProperty
version.startSectionWithMessage("Processing table: TRM_CONCEPT_PROPERTY"); version.startSectionWithMessage("Processing table: TRM_CONCEPT_PROPERTY");
version.onTable("TRM_CONCEPT_PROPERTY").addColumn("PROP_VAL_LOB").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.CLOB); version.onTable("TRM_CONCEPT_PROPERTY").addColumn("PROP_VAL_LOB").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.BLOB);
} }
protected void init400() { protected void init400() {

View File

@ -319,6 +319,29 @@ public class JsonParserDstu3Test {
} }
/**
* See #402
*/
@Test
public void testEncodeCompositionDoesntOverwriteNarrative() {
FhirContext ctx = FhirContext.forDstu3();
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
Composition composition = new Composition();
composition.getText().setDivAsString("<div>root</div>");
composition.addSection().getText().setDivAsString("<div>section0</div>");
composition.addSection().getText().setDivAsString("<div>section1</div>");
String output = ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(composition);
ourLog.info(output);
assertThat(output, containsString("<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">root</div>"));
assertThat(output, containsString("<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">section0</div>"));
assertThat(output, containsString("<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">section1</div>"));
}
@Test @Test
public void testEncodeAndParseMetaProfileAndTags() { public void testEncodeAndParseMetaProfileAndTags() {
Patient p = new Patient(); Patient p = new Patient();

View File

@ -1070,6 +1070,28 @@ public class XmlParserDstu3Test {
assertEquals("grandparent", gp.getName()); assertEquals("grandparent", gp.getName());
} }
/**
* See #402
*/
@Test
public void testEncodeCompositionDoesntOverwriteNarrative() {
FhirContext ctx = FhirContext.forDstu3();
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
Composition composition = new Composition();
composition.getText().setDivAsString("<div>root</div>");
composition.addSection().getText().setDivAsString("<div>section0</div>");
composition.addSection().getText().setDivAsString("<div>section1</div>");
String output = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(composition);
ourLog.info(output);
assertThat(output, containsString("<div xmlns=\"http://www.w3.org/1999/xhtml\">root</div>"));
assertThat(output, containsString("<div xmlns=\"http://www.w3.org/1999/xhtml\">section0</div>"));
assertThat(output, containsString("<div xmlns=\"http://www.w3.org/1999/xhtml\">section1</div>"));
}
/** /**
* See #326 * See #326
*/ */

View File

@ -448,6 +448,34 @@ public class JsonParserR4Test {
} }
private Composition createComposition(String sectionText) {
Composition c = new Composition();
Narrative compositionText = new Narrative().setStatus(Narrative.NarrativeStatus.GENERATED);
compositionText.setDivAsString("Composition");
Narrative compositionSectionText = new Narrative().setStatus(Narrative.NarrativeStatus.GENERATED);
compositionSectionText.setDivAsString(sectionText);
c.setText(compositionText);
c.addSection().setText(compositionSectionText);
return c;
}
/**
* See #402 (however JSON is fine)
*/
@Test
public void testEncodingTextSection() {
String sectionText = "sectionText";
Composition composition = createComposition(sectionText);
String encoded = ourCtx.newJsonParser().encodeResourceToString(composition);
ourLog.info(encoded);
int idx = encoded.indexOf(sectionText);
assertNotEquals(-1, idx);
}
/** /**
* 2019-09-19 - Pre #1489 * 2019-09-19 - Pre #1489
* 18:24:48.548 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:483] - Encoded 200 passes - 50ms / pass - 19.7 / second * 18:24:48.548 [main] INFO ca.uhn.fhir.parser.JsonParserR4Test [JsonParserR4Test.java:483] - Encoded 200 passes - 50ms / pass - 19.7 / second

View File

@ -0,0 +1,45 @@
package ca.uhn.fhir.parser;
import static org.junit.Assert.assertNotEquals;
import org.hl7.fhir.r4.model.Composition;
import org.hl7.fhir.r4.model.Narrative;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ca.uhn.fhir.context.FhirContext;
public class XmlParserR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(XmlParserR4Test.class);
private static FhirContext ourCtx = FhirContext.forR4();
private Composition createComposition(String sectionText) {
Composition c = new Composition();
Narrative compositionText = new Narrative().setStatus(Narrative.NarrativeStatus.GENERATED);
compositionText.setDivAsString("Composition");
Narrative compositionSectionText = new Narrative().setStatus(Narrative.NarrativeStatus.GENERATED);
compositionSectionText.setDivAsString(sectionText);
c.setText(compositionText);
c.addSection().setText(compositionSectionText);
return c;
}
/**
* See #402 section.text is overwritten by composition.text
*/
@Test
public void testEncodingTextSection() {
String sectionText = "sectionText";
Composition composition = createComposition(sectionText);
String encoded = ourCtx.newXmlParser().encodeResourceToString(composition);
ourLog.info(encoded);
int idx = encoded.indexOf(sectionText);
assertNotEquals(-1, idx);
}
}

View File

@ -20,7 +20,7 @@
<script th:src="@{/fa/js/all.min.js}" data-auto-replace-svg="nest"></script> <script th:src="@{/fa/js/all.min.js}" data-auto-replace-svg="nest"></script>
<link href="css/hapi-narrative.css" rel="stylesheet"/> <link href="css/hapi-narrative.css" rel="stylesheet"/>
<script type="text/javascript" src="js/moment.min.js"></script> <script type="text/javascript" src="js/moment-with-locales.min.js"></script>
<link href="css/bootstrap-datetimepicker.min.css" rel="stylesheet"/> <link href="css/bootstrap-datetimepicker.min.css" rel="stylesheet"/>
<script src="js/bootstrap-datetimepicker.min.js"></script> <script src="js/bootstrap-datetimepicker.min.js"></script>
<link href="css/select2.css" rel="stylesheet"/> <link href="css/select2.css" rel="stylesheet"/>

View File

@ -331,8 +331,8 @@ function addSearchControlDate(theSearchParamName, theContainerRowNum, theRowNum,
) )
); );
input.datetimepicker({ input.datetimepicker({
pickTime: false, format: "YYYY-MM-DD",
showToday: true showTodayButton: true
}); });
// Set up the qualifier dropdown after we've initialized the datepicker, since it // Set up the qualifier dropdown after we've initialized the datepicker, since it
// overrides all addon buttons while it inits.. // overrides all addon buttons while it inits..

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -552,6 +552,9 @@
<id>dmap</id> <id>dmap</id>
<name>David Maplesden</name> <name>David Maplesden</name>
</developer> </developer>
<developer>
<id>jaferkhan</id>
</developer>
</developers> </developers>
<licenses> <licenses>

View File

@ -287,6 +287,15 @@
conditional creates can now be authorized even if they are happening inside a FHIR conditional creates can now be authorized even if they are happening inside a FHIR
transaction. transaction.
</action> </action>
<action type="fix" issue="402">
When encoding a Composition resource in XML, the section narrative blocks were incorrectly
replaced by the main resource narrative. Thanks to Mirjam Baltus for reporting!
</action>
<action type="fix" issue="1473">
AN issue with date pickers not working in the hapi-fhir-testpage-overlay
project has been fixed. Thanks to GitHub user @jaferkhan for the pull
request!
</action>
</release> </release>
<release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)"> <release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
<action type="fix"> <action type="fix">