Add serialization support and fix build regression
This commit is contained in:
parent
e8730b6e47
commit
56a4c1b04b
|
@ -20,17 +20,31 @@ package ca.uhn.fhir.model.api;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.io.Externalizable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInput;
|
||||||
|
import java.io.ObjectOutput;
|
||||||
|
|
||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
|
||||||
public abstract class BasePrimitive<T> extends BaseIdentifiableElement implements IPrimitiveDatatype<T> {
|
public abstract class BasePrimitive<T> extends BaseIdentifiableElement implements IPrimitiveDatatype<T>, Externalizable {
|
||||||
|
|
||||||
private T myCoercedValue;
|
private T myCoercedValue;
|
||||||
private String myStringValue;
|
private String myStringValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses must override to convert a "coerced" value into an encoded one.
|
||||||
|
*
|
||||||
|
* @param theValue
|
||||||
|
* Will not be null
|
||||||
|
* @return May return null if the value does not correspond to anything
|
||||||
|
*/
|
||||||
|
protected abstract String encode(T theValue);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object theObj) {
|
public boolean equals(Object theObj) {
|
||||||
if (theObj == null) {
|
if (theObj == null) {
|
||||||
|
@ -67,6 +81,21 @@ public abstract class BasePrimitive<T> extends BaseIdentifiableElement implement
|
||||||
return super.isBaseEmpty() && getValue() == null;
|
return super.isBaseEmpty() && getValue() == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses must override to convert an encoded representation of this datatype into a "coerced" one
|
||||||
|
*
|
||||||
|
* @param theValue
|
||||||
|
* Will not be null
|
||||||
|
* @return May return null if the value does not correspond to anything
|
||||||
|
*/
|
||||||
|
protected abstract T parse(String theValue);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readExternal(ObjectInput theIn) throws IOException, ClassNotFoundException {
|
||||||
|
String object = (String) theIn.readObject();
|
||||||
|
setValueAsString(object);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IPrimitiveType<T> setValue(T theValue) throws DataFormatException {
|
public IPrimitiveType<T> setValue(T theValue) throws DataFormatException {
|
||||||
myCoercedValue = theValue;
|
myCoercedValue = theValue;
|
||||||
|
@ -74,15 +103,6 @@ public abstract class BasePrimitive<T> extends BaseIdentifiableElement implement
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateStringValue() {
|
|
||||||
if (myCoercedValue == null) {
|
|
||||||
myStringValue = null;
|
|
||||||
} else {
|
|
||||||
// NB this might be null
|
|
||||||
myStringValue = encode(myCoercedValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValueAsString(String theValue) throws DataFormatException {
|
public void setValueAsString(String theValue) throws DataFormatException {
|
||||||
if (theValue == null) {
|
if (theValue == null) {
|
||||||
|
@ -94,26 +114,22 @@ public abstract class BasePrimitive<T> extends BaseIdentifiableElement implement
|
||||||
myStringValue = theValue;
|
myStringValue = theValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclasses must override to convert an encoded representation of this datatype into a "coerced" one
|
|
||||||
*
|
|
||||||
* @param theValue
|
|
||||||
* Will not be null
|
|
||||||
* @return May return null if the value does not correspond to anything
|
|
||||||
*/
|
|
||||||
protected abstract T parse(String theValue);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclasses must override to convert a "coerced" value into an encoded one.
|
|
||||||
*
|
|
||||||
* @param theValue
|
|
||||||
* Will not be null
|
|
||||||
* @return May return null if the value does not correspond to anything
|
|
||||||
*/
|
|
||||||
protected abstract String encode(T theValue);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName() + "[" + getValueAsString() + "]";
|
return getClass().getSimpleName() + "[" + getValueAsString() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void updateStringValue() {
|
||||||
|
if (myCoercedValue == null) {
|
||||||
|
myStringValue = null;
|
||||||
|
} else {
|
||||||
|
// NB this might be null
|
||||||
|
myStringValue = encode(myCoercedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeExternal(ObjectOutput theOut) throws IOException {
|
||||||
|
theOut.writeObject(getValueAsString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.model.api;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.*;
|
import static org.apache.commons.lang3.StringUtils.*;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -61,7 +62,9 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
* define their own keys for storage in resource metadata if needed.
|
* define their own keys for storage in resource metadata if needed.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public abstract class ResourceMetadataKeyEnum<T> {
|
public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If present and populated with a date/time (as an instance of {@link InstantDt}), this value is an indication that the resource is in the deleted state. This key is only used in a limited number
|
* If present and populated with a date/time (as an instance of {@link InstantDt}), this value is an indication that the resource is in the deleted state. This key is only used in a limited number
|
||||||
|
|
|
@ -20,6 +20,8 @@ package ca.uhn.fhir.model.primitive;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
|
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
|
||||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||||
|
|
||||||
|
@ -28,16 +30,27 @@ public class BoundCodeDt<T extends Enum<?>> extends CodeDt {
|
||||||
|
|
||||||
private IValueSetEnumBinder<T> myBinder;
|
private IValueSetEnumBinder<T> myBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated This constructor is provided only for serialization support. Do not call it directly!
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public BoundCodeDt() {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
public BoundCodeDt(IValueSetEnumBinder<T> theBinder) {
|
public BoundCodeDt(IValueSetEnumBinder<T> theBinder) {
|
||||||
|
Validate.notNull(theBinder, "theBinder must not be null");
|
||||||
myBinder = theBinder;
|
myBinder = theBinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoundCodeDt(IValueSetEnumBinder<T> theBinder, T theValue) {
|
public BoundCodeDt(IValueSetEnumBinder<T> theBinder, T theValue) {
|
||||||
|
Validate.notNull(theBinder, "theBinder must not be null");
|
||||||
myBinder = theBinder;
|
myBinder = theBinder;
|
||||||
setValueAsEnum(theValue);
|
setValueAsEnum(theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValueAsEnum(T theValue) {
|
public void setValueAsEnum(T theValue) {
|
||||||
|
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeDt() should not be called!");
|
||||||
if (theValue==null) {
|
if (theValue==null) {
|
||||||
setValue(null);
|
setValue(null);
|
||||||
} else {
|
} else {
|
||||||
|
@ -46,6 +59,7 @@ public class BoundCodeDt<T extends Enum<?>> extends CodeDt {
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getValueAsEnum() {
|
public T getValueAsEnum() {
|
||||||
|
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeDt() should not be called!");
|
||||||
T retVal = myBinder.fromCodeString(getValue());
|
T retVal = myBinder.fromCodeString(getValue());
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
// TODO: throw special exception type?
|
// TODO: throw special exception type?
|
||||||
|
|
|
@ -41,6 +41,8 @@ import ca.uhn.fhir.util.XmlUtil;
|
||||||
@DatatypeDef(name = "xhtml")
|
@DatatypeDef(name = "xhtml")
|
||||||
public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1554,7 +1554,7 @@ class ParserState<T> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child.getMax() < 2 && !myParsedNonRepeatableNames.add(theChildName)) {
|
if ((child.getMax() == 0 || child.getMax() == 1) && !myParsedNonRepeatableNames.add(theChildName)) {
|
||||||
myErrorHandler.unexpectedRepeatingElement(null, theChildName);
|
myErrorHandler.unexpectedRepeatingElement(null, theChildName);
|
||||||
push(new SwallowChildrenWholeState(getPreResourceState()));
|
push(new SwallowChildrenWholeState(getPreResourceState()));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -24,7 +24,9 @@ import net.sourceforge.cobertura.CoverageIgnore;
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.util.OperationOutcomeUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an <b>HTTP 422 Unprocessable Entity</b> response, which means that a resource was rejected by the server because it "violated applicable FHIR profiles or server business rules".
|
* Represents an <b>HTTP 422 Unprocessable Entity</b> response, which means that a resource was rejected by the server because it "violated applicable FHIR profiles or server business rules".
|
||||||
|
@ -56,11 +58,21 @@ public class UnprocessableEntityException extends BaseServerResponseException {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor which accepts an {@link IBaseOperationOutcome} resource which will be supplied in the response
|
* Constructor which accepts an {@link IBaseOperationOutcome} resource which will be supplied in the response
|
||||||
|
*
|
||||||
|
* @deprecated Use constructor with FhirContext argument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public UnprocessableEntityException(IBaseOperationOutcome theOperationOutcome) {
|
public UnprocessableEntityException(IBaseOperationOutcome theOperationOutcome) {
|
||||||
super(STATUS_CODE, DEFAULT_MESSAGE, theOperationOutcome);
|
super(STATUS_CODE, DEFAULT_MESSAGE, theOperationOutcome);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor which accepts an {@link IBaseOperationOutcome} resource which will be supplied in the response
|
||||||
|
*/
|
||||||
|
public UnprocessableEntityException(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome) {
|
||||||
|
super(STATUS_CODE, OperationOutcomeUtil.getFirstIssueDetails(theCtx, theOperationOutcome), theOperationOutcome);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor which accepts a String describing the issue. This string will be translated into an {@link IBaseOperationOutcome} resource which will be supplied in the response.
|
* Constructor which accepts a String describing the issue. This string will be translated into an {@link IBaseOperationOutcome} resource which will be supplied in the response.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.validation;
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2015 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.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.validation;
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2015 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.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.hl7.fhir.instance.model.api;
|
package org.hl7.fhir.instance.model.api;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR - Core Library
|
* HAPI FHIR - Core Library
|
||||||
|
@ -25,7 +27,7 @@ package org.hl7.fhir.instance.model.api;
|
||||||
* structure of some kind. It is provided mostly to simplify convergence
|
* structure of some kind. It is provided mostly to simplify convergence
|
||||||
* between the HL7.org structures and the HAPI ones.
|
* between the HL7.org structures and the HAPI ones.
|
||||||
*/
|
*/
|
||||||
public interface IBase {
|
public interface IBase extends Serializable {
|
||||||
|
|
||||||
boolean isEmpty();
|
boolean isEmpty();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2015 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.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
@ -41,7 +61,7 @@ public class FhirResourceDaoQuestionnaireAnswersDstu2 extends FhirResourceDaoDst
|
||||||
ValidationResult result = val.validateWithResult(myRefImplCtx.newJsonParser().parseResource(getContext().newJsonParser().encodeResourceToString(qa)));
|
ValidationResult result = val.validateWithResult(myRefImplCtx.newJsonParser().parseResource(getContext().newJsonParser().encodeResourceToString(qa)));
|
||||||
if (!result.isSuccessful()) {
|
if (!result.isSuccessful()) {
|
||||||
IBaseOperationOutcome oo = getContext().newJsonParser().parseResource(OperationOutcome.class, myRefImplCtx.newJsonParser().encodeResourceToString(result.toOperationOutcome()));
|
IBaseOperationOutcome oo = getContext().newJsonParser().parseResource(OperationOutcome.class, myRefImplCtx.newJsonParser().encodeResourceToString(result.toOperationOutcome()));
|
||||||
throw new UnprocessableEntityException(oo);
|
throw new UnprocessableEntityException(getContext(), oo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.IBoundCodeableConcept;
|
import ca.uhn.fhir.model.api.IBoundCodeableConcept;
|
||||||
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
|
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
|
||||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||||
|
@ -37,10 +39,19 @@ public class BoundCodeableConceptDt<T extends Enum<?>> extends CodeableConceptDt
|
||||||
|
|
||||||
private IValueSetEnumBinder<T> myBinder;
|
private IValueSetEnumBinder<T> myBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated This constructor is provided only for serialization support. Do not call it directly!
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public BoundCodeableConceptDt() {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder) {
|
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder) {
|
||||||
|
Validate.notNull(theBinder, "theBinder must not be null");
|
||||||
myBinder = theBinder;
|
myBinder = theBinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +59,7 @@ public class BoundCodeableConceptDt<T extends Enum<?>> extends CodeableConceptDt
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder, T theValue) {
|
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder, T theValue) {
|
||||||
|
Validate.notNull(theBinder, "theBinder must not be null");
|
||||||
myBinder = theBinder;
|
myBinder = theBinder;
|
||||||
setValueAsEnum(theValue);
|
setValueAsEnum(theValue);
|
||||||
}
|
}
|
||||||
|
@ -56,6 +68,7 @@ public class BoundCodeableConceptDt<T extends Enum<?>> extends CodeableConceptDt
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder, Collection<T> theValues) {
|
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder, Collection<T> theValues) {
|
||||||
|
Validate.notNull(theBinder, "theBinder must not be null");
|
||||||
myBinder = theBinder;
|
myBinder = theBinder;
|
||||||
setValueAsEnum(theValues);
|
setValueAsEnum(theValues);
|
||||||
}
|
}
|
||||||
|
@ -70,6 +83,7 @@ public class BoundCodeableConceptDt<T extends Enum<?>> extends CodeableConceptDt
|
||||||
* The value to add, or <code>null</code>
|
* The value to add, or <code>null</code>
|
||||||
*/
|
*/
|
||||||
public void setValueAsEnum(Collection<T> theValues) {
|
public void setValueAsEnum(Collection<T> theValues) {
|
||||||
|
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!");
|
||||||
getCoding().clear();
|
getCoding().clear();
|
||||||
if (theValues != null) {
|
if (theValues != null) {
|
||||||
for (T next : theValues) {
|
for (T next : theValues) {
|
||||||
|
@ -88,6 +102,7 @@ public class BoundCodeableConceptDt<T extends Enum<?>> extends CodeableConceptDt
|
||||||
* The value to add, or <code>null</code>
|
* The value to add, or <code>null</code>
|
||||||
*/
|
*/
|
||||||
public void setValueAsEnum(T theValue) {
|
public void setValueAsEnum(T theValue) {
|
||||||
|
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!");
|
||||||
getCoding().clear();
|
getCoding().clear();
|
||||||
if (theValue == null) {
|
if (theValue == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -107,6 +122,7 @@ public class BoundCodeableConceptDt<T extends Enum<?>> extends CodeableConceptDt
|
||||||
* no codes that match the enum.
|
* no codes that match the enum.
|
||||||
*/
|
*/
|
||||||
public Set<T> getValueAsEnum() {
|
public Set<T> getValueAsEnum() {
|
||||||
|
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!");
|
||||||
Set<T> retVal = new HashSet<T>();
|
Set<T> retVal = new HashSet<T>();
|
||||||
for (CodingDt next : getCoding()) {
|
for (CodingDt next : getCoding()) {
|
||||||
if (next == null) {
|
if (next == null) {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package ca.uhn.fhir.model.dstu2;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.SerializationUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
|
||||||
|
public class ModelSerializationTest {
|
||||||
|
|
||||||
|
private static final FhirContext ourCtx = FhirContext.forDstu2();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerialization() throws Exception {
|
||||||
|
String input = IOUtils.toString(ModelSerializationTest.class.getResourceAsStream("/diagnosticreport-examples-lab-text(72ac8493-52ac-41bd-8d5d-7258c289b5ea).xml"));
|
||||||
|
|
||||||
|
Bundle parsed = ourCtx.newXmlParser().parseResource(Bundle.class, input);
|
||||||
|
Bundle roundTripped = SerializationUtils.roundtrip(parsed);
|
||||||
|
|
||||||
|
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||||
|
assertEquals(p.encodeResourceToString(parsed), p.encodeResourceToString(roundTripped));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import org.hl7.fhir.instance.model.Questionnaire.GroupComponent;
|
||||||
import org.hl7.fhir.instance.model.Questionnaire.QuestionComponent;
|
import org.hl7.fhir.instance.model.Questionnaire.QuestionComponent;
|
||||||
import org.hl7.fhir.instance.model.QuestionnaireAnswers;
|
import org.hl7.fhir.instance.model.QuestionnaireAnswers;
|
||||||
import org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionAnswerComponent;
|
import org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionAnswerComponent;
|
||||||
|
import org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionnaireAnswersStatus;
|
||||||
import org.hl7.fhir.instance.model.Reference;
|
import org.hl7.fhir.instance.model.Reference;
|
||||||
import org.hl7.fhir.instance.model.Resource;
|
import org.hl7.fhir.instance.model.Resource;
|
||||||
import org.hl7.fhir.instance.model.StringType;
|
import org.hl7.fhir.instance.model.StringType;
|
||||||
|
@ -44,11 +45,11 @@ import org.hl7.fhir.instance.utils.WorkerContext;
|
||||||
*/
|
*/
|
||||||
public class QuestionnaireAnswersValidator extends BaseValidator {
|
public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
|
|
||||||
/*
|
/* *****************************************************************
|
||||||
* Note to anyone working on this class -
|
* Note to anyone working on this class -
|
||||||
*
|
*
|
||||||
* This class has unit tests which run within the HAPI project build. Please sync any changes here to HAPI and ensure that unit tests are run.
|
* This class has unit tests which run within the HAPI project build. Please sync any changes here to HAPI and ensure that unit tests are run.
|
||||||
*/
|
* *****************************************************************/
|
||||||
|
|
||||||
private WorkerContext myWorkerCtx;
|
private WorkerContext myWorkerCtx;
|
||||||
|
|
||||||
|
@ -102,9 +103,17 @@ public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QuestionnaireAnswersStatus status = theAnswers.getStatus();
|
||||||
|
boolean validateRequired = false;
|
||||||
|
if (status == QuestionnaireAnswersStatus.COMPLETED || status == QuestionnaireAnswersStatus.AMENDED) {
|
||||||
|
validateRequired = true;
|
||||||
|
} else {
|
||||||
|
hint(theErrors, null, null, false, "Questionnaire has status {0} so ");
|
||||||
|
}
|
||||||
|
|
||||||
pathStack.removeLast();
|
pathStack.removeLast();
|
||||||
pathStack.add("group(0)");
|
pathStack.add("group(0)");
|
||||||
validateGroup(theErrors, questionnaire.getGroup(), theAnswers.getGroup(), pathStack, theAnswers);
|
validateGroup(theErrors, questionnaire.getGroup(), theAnswers.getGroup(), pathStack, theAnswers, validateRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Questionnaire getQuestionnaire(QuestionnaireAnswers theAnswers, Reference theQuestionnaireRef) {
|
private Questionnaire getQuestionnaire(QuestionnaireAnswers theAnswers, Reference theQuestionnaireRef) {
|
||||||
|
@ -142,7 +151,7 @@ public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateGroup(List<ValidationMessage> theErrors, GroupComponent theQuestGroup, org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent theAnsGroup,
|
private void validateGroup(List<ValidationMessage> theErrors, GroupComponent theQuestGroup, org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent theAnsGroup,
|
||||||
LinkedList<String> thePathStack, QuestionnaireAnswers theAnswers) {
|
LinkedList<String> thePathStack, QuestionnaireAnswers theAnswers, boolean theValidateRequired) {
|
||||||
|
|
||||||
for (org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionComponent next : theAnsGroup.getQuestion()) {
|
for (org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionComponent next : theAnsGroup.getQuestion()) {
|
||||||
rule(theErrors, IssueType.INVALID, thePathStack, isNotBlank(next.getLinkId()), "Question found with no linkId");
|
rule(theErrors, IssueType.INVALID, thePathStack, isNotBlank(next.getLinkId()), "Question found with no linkId");
|
||||||
|
@ -155,7 +164,7 @@ public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
|
|
||||||
for (int i = 0; i < theQuestGroup.getQuestion().size(); i++) {
|
for (int i = 0; i < theQuestGroup.getQuestion().size(); i++) {
|
||||||
QuestionComponent nextQuestion = theQuestGroup.getQuestion().get(i);
|
QuestionComponent nextQuestion = theQuestGroup.getQuestion().get(i);
|
||||||
validateQuestion(theErrors, nextQuestion, theAnsGroup, thePathStack, theAnswers);
|
validateQuestion(theErrors, nextQuestion, theAnsGroup, thePathStack, theAnswers, theValidateRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there are no extra answers
|
// Check that there are no extra answers
|
||||||
|
@ -167,12 +176,12 @@ public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
thePathStack.remove();
|
thePathStack.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
validateGroupGroups(theErrors, theQuestGroup, theAnsGroup, thePathStack, theAnswers);
|
validateGroupGroups(theErrors, theQuestGroup, theAnsGroup, thePathStack, theAnswers, theValidateRequired);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateQuestion(List<ValidationMessage> theErrors, QuestionComponent theQuestion, org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent theAnsGroup,
|
private void validateQuestion(List<ValidationMessage> theErrors, QuestionComponent theQuestion, org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent theAnsGroup,
|
||||||
LinkedList<String> thePathStack, QuestionnaireAnswers theAnswers) {
|
LinkedList<String> thePathStack, QuestionnaireAnswers theAnswers, boolean theValidateRequired) {
|
||||||
String linkId = theQuestion.getLinkId();
|
String linkId = theQuestion.getLinkId();
|
||||||
if (!fail(theErrors, IssueType.INVALID, thePathStack, isNotBlank(linkId), "Questionnaire is invalid, question found with no link ID")) {
|
if (!fail(theErrors, IssueType.INVALID, thePathStack, isNotBlank(linkId), "Questionnaire is invalid, question found with no link ID")) {
|
||||||
return;
|
return;
|
||||||
|
@ -192,32 +201,32 @@ public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, !theQuestion.getRequired(), "Multiple answers repetitions found with linkId[{0}]", linkId);
|
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, !theQuestion.getRequired(), "Multiple answers repetitions found with linkId[{0}]", linkId);
|
||||||
}
|
}
|
||||||
if (answers.size() == 0) {
|
if (answers.size() == 0) {
|
||||||
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, !theQuestion.getRequired(), "Missing answer to required question with linkId[{0}]", linkId);
|
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, !(theQuestion.getRequired() && theValidateRequired), "Missing answer to required question with linkId[{0}]", linkId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionComponent answerQuestion = answers.get(0);
|
org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionComponent answerQuestion = answers.get(0);
|
||||||
try {
|
try {
|
||||||
thePathStack.add("question(" + answers.indexOf(answerQuestion) + ")");
|
thePathStack.add("question(" + answers.indexOf(answerQuestion) + ")");
|
||||||
validateQuestionAnswers(theErrors, theQuestion, thePathStack, type, answerQuestion, theAnswers);
|
validateQuestionAnswers(theErrors, theQuestion, thePathStack, type, answerQuestion, theAnswers, theValidateRequired);
|
||||||
validateQuestionGroups(theErrors, theQuestion, answerQuestion, thePathStack, theAnswers);
|
validateQuestionGroups(theErrors, theQuestion, answerQuestion, thePathStack, theAnswers, theValidateRequired);
|
||||||
} finally {
|
} finally {
|
||||||
thePathStack.removeLast();
|
thePathStack.removeLast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateQuestionGroups(List<ValidationMessage> theErrors, QuestionComponent theQuestion, org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionComponent theAnswerQuestion,
|
private void validateQuestionGroups(List<ValidationMessage> theErrors, QuestionComponent theQuestion, org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionComponent theAnswerQuestion,
|
||||||
LinkedList<String> thePathSpec, QuestionnaireAnswers theAnswers) {
|
LinkedList<String> thePathSpec, QuestionnaireAnswers theAnswers, boolean theValidateRequired) {
|
||||||
validateGroups(theErrors, theQuestion.getGroup(), theAnswerQuestion.getGroup(), thePathSpec, theAnswers);
|
validateGroups(theErrors, theQuestion.getGroup(), theAnswerQuestion.getGroup(), thePathSpec, theAnswers, theValidateRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateGroupGroups(List<ValidationMessage> theErrors, GroupComponent theQuestGroup, org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent theAnsGroup,
|
private void validateGroupGroups(List<ValidationMessage> theErrors, GroupComponent theQuestGroup, org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent theAnsGroup,
|
||||||
LinkedList<String> thePathSpec, QuestionnaireAnswers theAnswers) {
|
LinkedList<String> thePathSpec, QuestionnaireAnswers theAnswers, boolean theValidateRequired) {
|
||||||
validateGroups(theErrors, theQuestGroup.getGroup(), theAnsGroup.getGroup(), thePathSpec, theAnswers);
|
validateGroups(theErrors, theQuestGroup.getGroup(), theAnsGroup.getGroup(), thePathSpec, theAnswers, theValidateRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateGroups(List<ValidationMessage> theErrors, List<GroupComponent> theQuestionGroups, List<org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent> theAnswerGroups,
|
private void validateGroups(List<ValidationMessage> theErrors, List<GroupComponent> theQuestionGroups, List<org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent> theAnswerGroups,
|
||||||
LinkedList<String> thePathStack, QuestionnaireAnswers theAnswers) {
|
LinkedList<String> thePathStack, QuestionnaireAnswers theAnswers, boolean theValidateRequired) {
|
||||||
Set<String> allowedGroups = new HashSet<String>();
|
Set<String> allowedGroups = new HashSet<String>();
|
||||||
for (GroupComponent nextQuestionGroup : theQuestionGroups) {
|
for (GroupComponent nextQuestionGroup : theQuestionGroups) {
|
||||||
String linkId = nextQuestionGroup.getLinkId();
|
String linkId = nextQuestionGroup.getLinkId();
|
||||||
|
@ -225,7 +234,7 @@ public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
|
|
||||||
List<org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent> answerGroups = findGroupByLinkId(theAnswerGroups, linkId);
|
List<org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent> answerGroups = findGroupByLinkId(theAnswerGroups, linkId);
|
||||||
if (answerGroups.isEmpty()) {
|
if (answerGroups.isEmpty()) {
|
||||||
if (nextQuestionGroup.getRequired()) {
|
if (nextQuestionGroup.getRequired() && theValidateRequired) {
|
||||||
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, false, "Missing required group with linkId[{0}]", linkId);
|
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, false, "Missing required group with linkId[{0}]", linkId);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -241,7 +250,7 @@ public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
for (org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent nextAnswerGroup : answerGroups) {
|
for (org.hl7.fhir.instance.model.QuestionnaireAnswers.GroupComponent nextAnswerGroup : answerGroups) {
|
||||||
int index = theAnswerGroups.indexOf(answerGroups.get(1));
|
int index = theAnswerGroups.indexOf(answerGroups.get(1));
|
||||||
thePathStack.add("group(" + index + ")");
|
thePathStack.add("group(" + index + ")");
|
||||||
validateGroup(theErrors, nextQuestionGroup, nextAnswerGroup, thePathStack, theAnswers);
|
validateGroup(theErrors, nextQuestionGroup, nextAnswerGroup, thePathStack, theAnswers, theValidateRequired);
|
||||||
thePathStack.removeLast();
|
thePathStack.removeLast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,13 +268,13 @@ public class QuestionnaireAnswersValidator extends BaseValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateQuestionAnswers(List<ValidationMessage> theErrors, QuestionComponent theQuestion, LinkedList<String> thePathStack, AnswerFormat type,
|
private void validateQuestionAnswers(List<ValidationMessage> theErrors, QuestionComponent theQuestion, LinkedList<String> thePathStack, AnswerFormat type,
|
||||||
org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionComponent answerQuestion, QuestionnaireAnswers theAnswers) {
|
org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionComponent answerQuestion, QuestionnaireAnswers theAnswers, boolean theValidateRequired) {
|
||||||
|
|
||||||
String linkId = theQuestion.getLinkId();
|
String linkId = theQuestion.getLinkId();
|
||||||
Set<Class<? extends Type>> allowedAnswerTypes = determineAllowedAnswerTypes(type);
|
Set<Class<? extends Type>> allowedAnswerTypes = determineAllowedAnswerTypes(type);
|
||||||
if (allowedAnswerTypes.isEmpty()) {
|
if (allowedAnswerTypes.isEmpty()) {
|
||||||
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, answerQuestion.isEmpty(), "Question with linkId[{0}] has no answer type but an answer was provided", linkId);
|
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, answerQuestion.isEmpty(), "Question with linkId[{0}] has no answer type but an answer was provided", linkId);
|
||||||
} else {
|
} else if (theValidateRequired) {
|
||||||
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, !(answerQuestion.getAnswer().size() > 1 && !theQuestion.getRepeats()), "Multiple answers to non repeating question with linkId[{0}]",
|
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, !(answerQuestion.getAnswer().size() > 1 && !theQuestion.getRepeats()), "Multiple answers to non repeating question with linkId[{0}]",
|
||||||
linkId);
|
linkId);
|
||||||
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, !(theQuestion.getRequired() && answerQuestion.getAnswer().isEmpty()), "Missing answer to required question with linkId[{0}]", linkId);
|
rule(theErrors, IssueType.BUSINESSRULE, thePathStack, !(theQuestion.getRequired() && answerQuestion.getAnswer().isEmpty()), "Missing answer to required question with linkId[{0}]", linkId);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ca.uhn.fhir.validation;
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -12,12 +13,15 @@ import java.util.List;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hl7.fhir.instance.model.Coding;
|
import org.hl7.fhir.instance.model.Coding;
|
||||||
import org.hl7.fhir.instance.model.IdType;
|
import org.hl7.fhir.instance.model.IdType;
|
||||||
|
import org.hl7.fhir.instance.model.IntegerType;
|
||||||
import org.hl7.fhir.instance.model.Questionnaire;
|
import org.hl7.fhir.instance.model.Questionnaire;
|
||||||
|
import org.hl7.fhir.instance.model.Questionnaire.GroupComponent;
|
||||||
import org.hl7.fhir.instance.model.QuestionnaireAnswers;
|
import org.hl7.fhir.instance.model.QuestionnaireAnswers;
|
||||||
import org.hl7.fhir.instance.model.Reference;
|
import org.hl7.fhir.instance.model.Reference;
|
||||||
import org.hl7.fhir.instance.model.StringType;
|
import org.hl7.fhir.instance.model.StringType;
|
||||||
import org.hl7.fhir.instance.model.ValueSet;
|
import org.hl7.fhir.instance.model.ValueSet;
|
||||||
import org.hl7.fhir.instance.model.Questionnaire.AnswerFormat;
|
import org.hl7.fhir.instance.model.Questionnaire.AnswerFormat;
|
||||||
|
import org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionnaireAnswersStatus;
|
||||||
import org.hl7.fhir.instance.utils.WorkerContext;
|
import org.hl7.fhir.instance.utils.WorkerContext;
|
||||||
import org.hl7.fhir.instance.validation.QuestionnaireAnswersValidator;
|
import org.hl7.fhir.instance.validation.QuestionnaireAnswersValidator;
|
||||||
import org.hl7.fhir.instance.validation.ValidationMessage;
|
import org.hl7.fhir.instance.validation.ValidationMessage;
|
||||||
|
@ -26,37 +30,38 @@ import org.junit.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
|
||||||
public class QuestionnaireAnswersValidatorIntegrationTest {
|
public class QuestionnaireAnswersValidatorIntegrationTest {
|
||||||
private static final FhirContext ourCtx = FhirContext.forDstu2Hl7Org();
|
private static final FhirContext ourCtx = FhirContext.forDstu2Hl7Org();
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(QuestionnaireAnswersValidatorIntegrationTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(QuestionnaireAnswersValidatorIntegrationTest.class);
|
||||||
|
|
||||||
private IResourceLoader myResourceLoaderMock;
|
private IResourceLoader myResourceLoaderMock;
|
||||||
|
|
||||||
private FhirValidator myVal;
|
private FhirValidator myVal;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
myResourceLoaderMock = mock(IResourceLoader.class);
|
myResourceLoaderMock = mock(IResourceLoader.class);
|
||||||
|
|
||||||
FhirQuestionnaireAnswersValidator qaVal = new FhirQuestionnaireAnswersValidator();
|
FhirQuestionnaireAnswersValidator qaVal = new FhirQuestionnaireAnswersValidator();
|
||||||
qaVal.setResourceLoader(myResourceLoaderMock);
|
qaVal.setResourceLoader(myResourceLoaderMock);
|
||||||
|
|
||||||
myVal = ourCtx.newValidator();
|
myVal = ourCtx.newValidator();
|
||||||
myVal.setValidateAgainstStandardSchema(false);
|
myVal.setValidateAgainstStandardSchema(false);
|
||||||
myVal.setValidateAgainstStandardSchematron(false);
|
myVal.setValidateAgainstStandardSchematron(false);
|
||||||
myVal.registerValidatorModule(qaVal);
|
myVal.registerValidatorModule(qaVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAnswerWithWrongType() {
|
public void testAnswerWithWrongType() {
|
||||||
Questionnaire q = new Questionnaire();
|
Questionnaire q = new Questionnaire();
|
||||||
q.getGroup().addQuestion().setLinkId("link0").setRequired(true).setType(AnswerFormat.BOOLEAN);
|
q.getGroup().addQuestion().setLinkId("link0").setRequired(true).setType(AnswerFormat.BOOLEAN);
|
||||||
|
|
||||||
when(myResourceLoaderMock.load(Mockito.eq(Questionnaire.class), Mockito.eq(new IdType("http://example.com/Questionnaire/q1")))).thenReturn(q);
|
when(myResourceLoaderMock.load(Mockito.eq(Questionnaire.class), Mockito.eq(new IdType("http://example.com/Questionnaire/q1")))).thenReturn(q);
|
||||||
|
|
||||||
QuestionnaireAnswers qa = new QuestionnaireAnswers();
|
QuestionnaireAnswers qa = new QuestionnaireAnswers();
|
||||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new StringType("FOO"));
|
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new StringType("FOO"));
|
||||||
|
@ -66,10 +71,63 @@ public class QuestionnaireAnswersValidatorIntegrationTest {
|
||||||
assertThat(result.getMessages().toString(), containsString("Answer to question with linkId[link0] found of type [StringType] but this is invalid for question of type [boolean]"));
|
assertThat(result.getMessages().toString(), containsString("Answer to question with linkId[link0] found of type [StringType] but this is invalid for question of type [boolean]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRequiredOnlyTestedForFinishedQuestionnaires() {
|
||||||
|
Questionnaire q = new Questionnaire();
|
||||||
|
q.getGroup().addQuestion().setLinkId("link0").setRequired(true).setType(AnswerFormat.BOOLEAN);
|
||||||
|
GroupComponent qg = q.getGroup().addGroup().setLinkId("link1").setRequired(true);
|
||||||
|
qg.addQuestion().setLinkId("link2").setRequired(false).setType(AnswerFormat.BOOLEAN);
|
||||||
|
|
||||||
|
when(myResourceLoaderMock.load(Mockito.eq(Questionnaire.class), Mockito.eq(new IdType("http://example.com/Questionnaire/q1")))).thenReturn(q);
|
||||||
|
|
||||||
|
// Wrong type
|
||||||
|
{
|
||||||
|
QuestionnaireAnswers qa = new QuestionnaireAnswers();
|
||||||
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
|
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new IntegerType(123));
|
||||||
|
|
||||||
|
ValidationResult result = myVal.validateWithResult(qa);
|
||||||
|
ourLog.info(result.getMessages().toString());
|
||||||
|
assertThat(result.getMessages().toString(), containsString("Answer to question with linkId[link0] found of type [IntegerType] but this is invalid for question of type [boolean]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not populated, no status
|
||||||
|
{
|
||||||
|
QuestionnaireAnswers qa = new QuestionnaireAnswers();
|
||||||
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
|
|
||||||
|
ValidationResult result = myVal.validateWithResult(qa);
|
||||||
|
ourLog.info(result.getMessages().toString());
|
||||||
|
assertThat(result.getMessages(), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not populated, partial status
|
||||||
|
{
|
||||||
|
QuestionnaireAnswers qa = new QuestionnaireAnswers();
|
||||||
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
|
qa.setStatus(QuestionnaireAnswersStatus.INPROGRESS);
|
||||||
|
|
||||||
|
ValidationResult result = myVal.validateWithResult(qa);
|
||||||
|
ourLog.info(result.getMessages().toString());
|
||||||
|
assertThat(result.getMessages(), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not populated, finished status
|
||||||
|
{
|
||||||
|
QuestionnaireAnswers qa = new QuestionnaireAnswers();
|
||||||
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
|
qa.setStatus(QuestionnaireAnswersStatus.COMPLETED);
|
||||||
|
|
||||||
|
ValidationResult result = myVal.validateWithResult(qa);
|
||||||
|
ourLog.info(result.getMessages().toString());
|
||||||
|
assertThat(result.getMessages().toString(), containsString("Missing answer to required question with linkId[link0]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCodedAnswer() {
|
public void testCodedAnswer() {
|
||||||
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
||||||
|
|
||||||
Questionnaire q = new Questionnaire();
|
Questionnaire q = new Questionnaire();
|
||||||
q.getGroup().addQuestion().setLinkId("link0").setRequired(false).setType(AnswerFormat.CHOICE).setOptions(new Reference("http://somevalueset/ValueSet/123"));
|
q.getGroup().addQuestion().setLinkId("link0").setRequired(false).setType(AnswerFormat.CHOICE).setOptions(new Reference("http://somevalueset/ValueSet/123"));
|
||||||
when(myResourceLoaderMock.load(Mockito.eq(Questionnaire.class), Mockito.eq(new IdType("http://example.com/Questionnaire/q1")))).thenReturn(q);
|
when(myResourceLoaderMock.load(Mockito.eq(Questionnaire.class), Mockito.eq(new IdType("http://example.com/Questionnaire/q1")))).thenReturn(q);
|
||||||
|
@ -77,45 +135,45 @@ public class QuestionnaireAnswersValidatorIntegrationTest {
|
||||||
ValueSet options = new ValueSet();
|
ValueSet options = new ValueSet();
|
||||||
options.getDefine().setSystem("urn:system").addConcept().setCode("code0");
|
options.getDefine().setSystem("urn:system").addConcept().setCode("code0");
|
||||||
when(myResourceLoaderMock.load(Mockito.eq(ValueSet.class), Mockito.eq(new IdType("http://somevalueset/ValueSet/123")))).thenReturn(options);
|
when(myResourceLoaderMock.load(Mockito.eq(ValueSet.class), Mockito.eq(new IdType("http://somevalueset/ValueSet/123")))).thenReturn(options);
|
||||||
|
|
||||||
QuestionnaireAnswers qa;
|
QuestionnaireAnswers qa;
|
||||||
|
|
||||||
// Good code
|
// Good code
|
||||||
|
|
||||||
qa = new QuestionnaireAnswers();
|
qa = new QuestionnaireAnswers();
|
||||||
qa.getQuestionnaire().setReference(questionnaireRef);
|
qa.getQuestionnaire().setReference(questionnaireRef);
|
||||||
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new Coding().setSystem("urn:system").setCode("code0"));
|
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new Coding().setSystem("urn:system").setCode("code0"));
|
||||||
ValidationResult result = myVal.validateWithResult(qa);
|
ValidationResult result = myVal.validateWithResult(qa);
|
||||||
assertEquals(result.getMessages().toString(), 0, result.getMessages().size());
|
assertEquals(result.getMessages().toString(), 0, result.getMessages().size());
|
||||||
|
|
||||||
// Bad code
|
// Bad code
|
||||||
|
|
||||||
qa = new QuestionnaireAnswers();
|
qa = new QuestionnaireAnswers();
|
||||||
qa.getQuestionnaire().setReference(questionnaireRef);
|
qa.getQuestionnaire().setReference(questionnaireRef);
|
||||||
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new Coding().setSystem("urn:system").setCode("code1"));
|
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new Coding().setSystem("urn:system").setCode("code1"));
|
||||||
result = myVal.validateWithResult(qa);
|
result = myVal.validateWithResult(qa);
|
||||||
ourLog.info(result.getMessages().toString());
|
ourLog.info(result.getMessages().toString());
|
||||||
assertThat(result.getMessages().toString(), containsString("myLocationString=QuestionnaireAnswers.group(0).question(0).answer(0)"));
|
assertThat(result.getMessages().toString(), containsString("myLocationString=QuestionnaireAnswers.group(0).question(0).answer(0)"));
|
||||||
assertThat(result.getMessages().toString(), containsString("myMessage=Question with linkId[link0] has answer with system[urn:system] and code[code1] but this is not a valid answer for ValueSet[http://somevalueset/ValueSet/123]"));
|
assertThat(result.getMessages().toString(),
|
||||||
|
containsString("myMessage=Question with linkId[link0] has answer with system[urn:system] and code[code1] but this is not a valid answer for ValueSet[http://somevalueset/ValueSet/123]"));
|
||||||
|
|
||||||
result.toOperationOutcome();
|
result.toOperationOutcome();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnknownValueSet() {
|
public void testUnknownValueSet() {
|
||||||
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
||||||
|
|
||||||
Questionnaire q = new Questionnaire();
|
Questionnaire q = new Questionnaire();
|
||||||
q.getGroup().addQuestion().setLinkId("link0").setRequired(false).setType(AnswerFormat.CHOICE).setOptions(new Reference("http://somevalueset/ValueSet/123"));
|
q.getGroup().addQuestion().setLinkId("link0").setRequired(false).setType(AnswerFormat.CHOICE).setOptions(new Reference("http://somevalueset/ValueSet/123"));
|
||||||
when(myResourceLoaderMock.load(Mockito.eq(Questionnaire.class), Mockito.eq(new IdType("http://example.com/Questionnaire/q1")))).thenReturn(q);
|
when(myResourceLoaderMock.load(Mockito.eq(Questionnaire.class), Mockito.eq(new IdType("http://example.com/Questionnaire/q1")))).thenReturn(q);
|
||||||
|
|
||||||
when(myResourceLoaderMock.load(Mockito.eq(ValueSet.class), Mockito.eq(new IdType("http://somevalueset/ValueSet/123")))).thenThrow(new ResourceNotFoundException("Unknown"));
|
when(myResourceLoaderMock.load(Mockito.eq(ValueSet.class), Mockito.eq(new IdType("http://somevalueset/ValueSet/123")))).thenThrow(new ResourceNotFoundException("Unknown"));
|
||||||
|
|
||||||
QuestionnaireAnswers qa;
|
QuestionnaireAnswers qa;
|
||||||
|
|
||||||
// Bad code
|
// Bad code
|
||||||
|
|
||||||
qa = new QuestionnaireAnswers();
|
qa = new QuestionnaireAnswers();
|
||||||
qa.getQuestionnaire().setReference(questionnaireRef);
|
qa.getQuestionnaire().setReference(questionnaireRef);
|
||||||
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new Coding().setSystem("urn:system").setCode("code1"));
|
qa.getGroup().addQuestion().setLinkId("link0").addAnswer().setValue(new Coding().setSystem("urn:system").setCode("code1"));
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hl7.fhir.instance.model.Reference;
|
||||||
import org.hl7.fhir.instance.model.StringType;
|
import org.hl7.fhir.instance.model.StringType;
|
||||||
import org.hl7.fhir.instance.model.ValueSet;
|
import org.hl7.fhir.instance.model.ValueSet;
|
||||||
import org.hl7.fhir.instance.model.Questionnaire.AnswerFormat;
|
import org.hl7.fhir.instance.model.Questionnaire.AnswerFormat;
|
||||||
|
import org.hl7.fhir.instance.model.QuestionnaireAnswers.QuestionnaireAnswersStatus;
|
||||||
import org.hl7.fhir.instance.utils.WorkerContext;
|
import org.hl7.fhir.instance.utils.WorkerContext;
|
||||||
import org.hl7.fhir.instance.validation.QuestionnaireAnswersValidator;
|
import org.hl7.fhir.instance.validation.QuestionnaireAnswersValidator;
|
||||||
import org.hl7.fhir.instance.validation.ValidationMessage;
|
import org.hl7.fhir.instance.validation.ValidationMessage;
|
||||||
|
@ -99,6 +100,7 @@ public class QuestionnaireAnswersValidatorTest {
|
||||||
q.getGroup().addQuestion().setLinkId("link1").setRequired(true).setType(AnswerFormat.STRING);
|
q.getGroup().addQuestion().setLinkId("link1").setRequired(true).setType(AnswerFormat.STRING);
|
||||||
|
|
||||||
QuestionnaireAnswers qa = new QuestionnaireAnswers();
|
QuestionnaireAnswers qa = new QuestionnaireAnswers();
|
||||||
|
qa.setStatus(QuestionnaireAnswersStatus.COMPLETED);
|
||||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
qa.getGroup().addQuestion().setLinkId("link1").addAnswer().setValue(new StringType("FOO"));
|
qa.getGroup().addQuestion().setLinkId("link1").addAnswer().setValue(new StringType("FOO"));
|
||||||
|
|
||||||
|
|
|
@ -215,11 +215,11 @@ public class TinderStructuresMojo extends AbstractMojo {
|
||||||
// ProfileParser pp = new ProfileParser();
|
// ProfileParser pp = new ProfileParser();
|
||||||
// pp.parseSingleProfile(new File("../hapi-tinder-test/src/test/resources/profile/patient.xml"), "http://foo");
|
// pp.parseSingleProfile(new File("../hapi-tinder-test/src/test/resources/profile/patient.xml"), "http://foo");
|
||||||
|
|
||||||
ValueSetGenerator vsp = new ValueSetGenerator("dstu2");
|
ValueSetGenerator vsp = new ValueSetGenerator("dstu");
|
||||||
// vsp.setResourceValueSetFiles(theResourceValueSetFiles);Directory("src/main/resources/vs/");
|
// vsp.setResourceValueSetFiles(theResourceValueSetFiles);Directory("src/main/resources/vs/");
|
||||||
vsp.parse();
|
vsp.parse();
|
||||||
|
|
||||||
DatatypeGeneratorUsingSpreadsheet dtp = new DatatypeGeneratorUsingSpreadsheet("dstu2", ".");
|
DatatypeGeneratorUsingSpreadsheet dtp = new DatatypeGeneratorUsingSpreadsheet("dstu", ".");
|
||||||
dtp.parse();
|
dtp.parse();
|
||||||
dtp.markResourcesForImports();
|
dtp.markResourcesForImports();
|
||||||
dtp.bindValueSets(vsp);
|
dtp.bindValueSets(vsp);
|
||||||
|
@ -227,8 +227,8 @@ public class TinderStructuresMojo extends AbstractMojo {
|
||||||
|
|
||||||
String dtOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/composite";
|
String dtOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/composite";
|
||||||
|
|
||||||
ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet("dstu2", ".");
|
ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet("dstu", ".");
|
||||||
rp.setBaseResourceNames(Arrays.asList( "composition", "list"
|
rp.setBaseResourceNames(Arrays.asList( "patient", "list"
|
||||||
// //, "contract"
|
// //, "contract"
|
||||||
// "valueset", "organization", "location"
|
// "valueset", "organization", "location"
|
||||||
// , "observation", "conformance"
|
// , "observation", "conformance"
|
||||||
|
|
|
@ -308,7 +308,7 @@ public class ValueSetGenerator {
|
||||||
|
|
||||||
public static void main(String[] args) throws FileNotFoundException, IOException {
|
public static void main(String[] args) throws FileNotFoundException, IOException {
|
||||||
|
|
||||||
ValueSetGenerator p = new ValueSetGenerator("dev");
|
ValueSetGenerator p = new ValueSetGenerator("dstu1");
|
||||||
p.parse();
|
p.parse();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,10 @@
|
||||||
Operations in server generated conformance statement should only
|
Operations in server generated conformance statement should only
|
||||||
appear once per name, since the name needs to be unique.
|
appear once per name, since the name needs to be unique.
|
||||||
</action>
|
</action>
|
||||||
|
<action>
|
||||||
|
Resources and datatypes are now serializable. This is an
|
||||||
|
experimental feature which hasn't yet been extensively tested. Please test and give us your feedback!
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.1" date="2015-07-13">
|
<release version="1.1" date="2015-07-13">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue