update error handling to preserve message ids properly
This commit is contained in:
parent
f07a779d36
commit
dc791becaa
|
@ -62,6 +62,7 @@ import org.hl7.fhir.r5.model.TypeDetails;
|
|||
import org.hl7.fhir.r5.model.TypeDetails.ProfiledType;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine.IssueMessage;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathUtilityClasses.FHIRConstant;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathUtilityClasses.ClassTypeInfo;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathUtilityClasses.FunctionDetails;
|
||||
|
@ -119,6 +120,26 @@ import ca.uhn.fhir.util.ElementUtil;
|
|||
*/
|
||||
public class FHIRPathEngine {
|
||||
|
||||
public class IssueMessage {
|
||||
|
||||
private String message;
|
||||
private String id;
|
||||
|
||||
public IssueMessage(String message, String id) {
|
||||
this.message = message;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private enum Equality { Null, True, False }
|
||||
|
||||
private IWorkerContext worker;
|
||||
|
@ -136,7 +157,7 @@ public class FHIRPathEngine {
|
|||
private boolean doNotEnforceAsSingletonRule;
|
||||
private boolean doNotEnforceAsCaseSensitive;
|
||||
private boolean allowDoubleQuotes;
|
||||
private List<String> typeWarnings = new ArrayList<>();
|
||||
private List<IssueMessage> typeWarnings = new ArrayList<>();
|
||||
private boolean emitSQLonFHIRWarning;
|
||||
|
||||
// if the fhir path expressions are allowed to use constants beyond those defined in the specification
|
||||
|
@ -499,7 +520,7 @@ public class FHIRPathEngine {
|
|||
* @throws PathEngineException
|
||||
* @if the path is not valid
|
||||
*/
|
||||
public TypeDetails checkOnTypes(Object appContext, String resourceType, List<String> typeList, ExpressionNode expr, List<String> warnings) throws FHIRLexerException, PathEngineException, DefinitionException {
|
||||
public TypeDetails checkOnTypes(Object appContext, String resourceType, List<String> typeList, ExpressionNode expr, List<IssueMessage> warnings) throws FHIRLexerException, PathEngineException, DefinitionException {
|
||||
typeWarnings.clear();
|
||||
|
||||
// if context is a path that refers to a type, do that conversion now
|
||||
|
@ -550,7 +571,7 @@ public class FHIRPathEngine {
|
|||
return res;
|
||||
}
|
||||
|
||||
public TypeDetails checkOnTypes(Object appContext, String resourceType, TypeDetails types, ExpressionNode expr, List<String> warnings) throws FHIRLexerException, PathEngineException, DefinitionException {
|
||||
public TypeDetails checkOnTypes(Object appContext, String resourceType, TypeDetails types, ExpressionNode expr, List<IssueMessage> warnings) throws FHIRLexerException, PathEngineException, DefinitionException {
|
||||
typeWarnings.clear();
|
||||
TypeDetails res = executeType(new ExecutionTypeContext(appContext, resourceType, types, types), types, expr, null, true, false, expr);
|
||||
warnings.addAll(typeWarnings);
|
||||
|
@ -589,9 +610,9 @@ public class FHIRPathEngine {
|
|||
fmt = fmt + " "+worker.formatMessagePlural(num, I18nConstants.FHIRPATH_LOCATION, location);
|
||||
}
|
||||
if (holder != null) {
|
||||
return new PathEngineException(fmt, holder.getStart(), holder.toString());
|
||||
return new PathEngineException(fmt, constName, holder.getStart(), holder.toString());
|
||||
} else {
|
||||
return new PathEngineException(fmt);
|
||||
return new PathEngineException(fmt, constName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -601,9 +622,9 @@ public class FHIRPathEngine {
|
|||
fmt = fmt + " "+worker.formatMessage(I18nConstants.FHIRPATH_LOCATION, location);
|
||||
}
|
||||
if (holder != null) {
|
||||
return new PathEngineException(fmt, holder.getStart(), holder.toString());
|
||||
return new PathEngineException(fmt, constName, holder.getStart(), holder.toString());
|
||||
} else {
|
||||
return new PathEngineException(fmt);
|
||||
return new PathEngineException(fmt, constName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1600,10 +1621,10 @@ public class FHIRPathEngine {
|
|||
// special Logic for SQL-on-FHIR:
|
||||
if (focus.isChoice()) {
|
||||
if (expr.getInner() == null || expr.getInner().getFunction() != Function.OfType) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_CHOICE_NO_TYPE_SPECIFIER, expr.toString()));
|
||||
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_CHOICE_NO_TYPE_SPECIFIER, expr.toString()), I18nConstants.FHIRPATH_CHOICE_NO_TYPE_SPECIFIER));
|
||||
}
|
||||
} else if (expr.getInner() != null && expr.getInner().getFunction() == Function.OfType) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_CHOICE_SPURIOUS_TYPE_SPECIFIER, expr.toString()));
|
||||
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_CHOICE_SPURIOUS_TYPE_SPECIFIER, expr.toString()), I18nConstants.FHIRPATH_CHOICE_SPURIOUS_TYPE_SPECIFIER));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1816,10 +1837,10 @@ public class FHIRPathEngine {
|
|||
} else {
|
||||
String tn = convertToString(right);
|
||||
if (!isKnownType(tn)) {
|
||||
throw new PathEngineException("The type "+tn+" is not valid");
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_INVALID_TYPE, tn), I18nConstants.FHIRPATH_INVALID_TYPE);
|
||||
}
|
||||
if (!doNotEnforceAsSingletonRule && left.size() > 1) {
|
||||
throw new PathEngineException("Attempt to use as on more than one item ("+left.size()+", '"+expr.toString()+"')");
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_AS_COLLECTION, left.size(), expr.toString()), I18nConstants.FHIRPATH_AS_COLLECTION);
|
||||
}
|
||||
for (Base nextLeft : left) {
|
||||
if (compareTypeNames(tn, nextLeft.fhirType())) {
|
||||
|
@ -1904,18 +1925,18 @@ public class FHIRPathEngine {
|
|||
|
||||
private void checkCardinalityForComparabilitySame(TypeDetails left, Operation operation, TypeDetails right, ExpressionNode expr) {
|
||||
if (left.isList() && !right.isList()) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT, expr.toString()));
|
||||
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT, expr.toString()), I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT));
|
||||
} else if (!left.isList() && right.isList()) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT, expr.toString()));
|
||||
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT, expr.toString()), I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCardinalityForSingle(TypeDetails left, Operation operation, TypeDetails right, ExpressionNode expr) {
|
||||
if (left.isList()) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT, expr.toString()));
|
||||
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT, expr.toString()), I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT));
|
||||
}
|
||||
if (right.isList()) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT, expr.toString()));
|
||||
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT, expr.toString()), I18nConstants.FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1995,7 +2016,7 @@ public class FHIRPathEngine {
|
|||
if (right.hasType(worker, "Quantity")) {
|
||||
result.addType(left.getType());
|
||||
} else {
|
||||
throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType()), expr.getOpStart(), expr.toString());
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_ARITHMETIC_PLUS, right.getType(), left.getType()), I18nConstants.FHIRPATH_ARITHMETIC_PLUS, expr.getOpStart(), expr.toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -2012,7 +2033,7 @@ public class FHIRPathEngine {
|
|||
if (right.hasType(worker, "Quantity")) {
|
||||
result.addType(left.getType());
|
||||
} else {
|
||||
throw new PathEngineException(String.format("Error in date arithmetic: Unable to subtract type {0} from {1}", right.getType(), left.getType()));
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_ARITHMETIC_MINUS, right.getType(), left.getType()), I18nConstants.FHIRPATH_ARITHMETIC_MINUS, expr.getOpStart(), expr.toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -2654,13 +2675,13 @@ public class FHIRPathEngine {
|
|||
result.add(Calendar.YEAR, value);
|
||||
break;
|
||||
case "a":
|
||||
throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode()));
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_ARITHMETIC_QTY, q.getCode()), I18nConstants.FHIRPATH_ARITHMETIC_QTY, holder.getOpStart(), holder.toString());
|
||||
case "months":
|
||||
case "month":
|
||||
result.add(Calendar.MONTH, value);
|
||||
break;
|
||||
case "mo":
|
||||
throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode()), holder.getOpStart(), holder.toString());
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_ARITHMETIC_QTY, q.getCode()), I18nConstants.FHIRPATH_ARITHMETIC_QTY, holder.getOpStart(), holder.toString());
|
||||
case "weeks":
|
||||
case "week":
|
||||
case "wk":
|
||||
|
@ -2692,7 +2713,7 @@ public class FHIRPathEngine {
|
|||
result.add(Calendar.MILLISECOND, value);
|
||||
break;
|
||||
default:
|
||||
throw new PathEngineException(String.format("Error in date arithmetic: unrecognized time unit %s", q.getCode()));
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_ARITHMETIC_UNIT, q.getCode()), I18nConstants.FHIRPATH_ARITHMETIC_UNIT, holder.getOpStart(), holder.toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -2730,7 +2751,7 @@ public class FHIRPathEngine {
|
|||
p = worker.getUcumService().multiply(pl, pr);
|
||||
result.add(pairToQty(p));
|
||||
} catch (UcumException e) {
|
||||
throw new PathEngineException(e.getMessage(), expr.getOpStart(), expr.toString(), e);
|
||||
throw new PathEngineException(e.getMessage(), null, expr.getOpStart(), expr.toString(), e); // #FIXME
|
||||
}
|
||||
} else {
|
||||
throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "*", left.get(0).fhirType(), right.get(0).fhirType());
|
||||
|
@ -3221,7 +3242,7 @@ public class FHIRPathEngine {
|
|||
}
|
||||
if (exp.getFunction() == Function.First || exp.getFunction() == Function.Last || exp.getFunction() == Function.Tail || exp.getFunction() == Function.Skip || exp.getFunction() == Function.Take) {
|
||||
if (focus.getCollectionStatus() == CollectionStatus.SINGLETON) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_NOT_A_COLLECTION, container.toString()));
|
||||
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_NOT_A_COLLECTION, container.toString()), I18nConstants.FHIRPATH_NOT_A_COLLECTION));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -3297,7 +3318,7 @@ public class FHIRPathEngine {
|
|||
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
|
||||
String tn = exp.getParameters().get(0).getName();
|
||||
if (typeCastIsImpossible(focus, tn)) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_OFTYPE_IMPOSSIBLE, focus.describeMin(), tn, exp.toString()));
|
||||
typeWarnings.add(new IssueMessage(worker.formatMessage(I18nConstants.FHIRPATH_OFTYPE_IMPOSSIBLE, focus.describeMin(), tn, exp.toString()), I18nConstants.FHIRPATH_OFTYPE_IMPOSSIBLE));
|
||||
}
|
||||
TypeDetails td = new TypeDetails(CollectionStatus.SINGLETON, tn);
|
||||
if (td.typesHaveTargets()) {
|
||||
|
@ -4871,10 +4892,10 @@ public class FHIRPathEngine {
|
|||
tn = "FHIR."+expr.getParameters().get(0).getName();
|
||||
}
|
||||
if (!isKnownType(tn)) {
|
||||
throw new PathEngineException("The type "+tn+" is not valid");
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_INVALID_TYPE, tn), I18nConstants.FHIRPATH_INVALID_TYPE); // #FIXME
|
||||
}
|
||||
if (!doNotEnforceAsSingletonRule && focus.size() > 1) {
|
||||
throw new PathEngineException("Attempt to use as() on more than one item ("+focus.size()+")");
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_AS_COLLECTION, focus.size(), expr.toString()), I18nConstants.FHIRPATH_AS_COLLECTION); // #FIXME
|
||||
}
|
||||
|
||||
for (Base b : focus) {
|
||||
|
@ -4914,7 +4935,7 @@ public class FHIRPathEngine {
|
|||
tn = "FHIR."+expr.getParameters().get(0).getName();
|
||||
}
|
||||
if (!isKnownType(tn)) {
|
||||
throw new PathEngineException("The type "+tn+" is not valid");
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_INVALID_TYPE, tn), I18nConstants.FHIRPATH_INVALID_TYPE); // #FIXME
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,10 +54,12 @@ public class OperationOutcomeUtilities {
|
|||
issue.addExpression(message.getLocation());
|
||||
}
|
||||
// pass through line/col if they're present
|
||||
if (message.getLine() >= 0)
|
||||
if (message.getLine() >= 0) {
|
||||
issue.addExtension().setUrl(ToolingExtensions.EXT_ISSUE_LINE).setValue(new IntegerType(message.getLine()));
|
||||
if (message.getCol() >= 0)
|
||||
}
|
||||
if (message.getCol() >= 0) {
|
||||
issue.addExtension().setUrl(ToolingExtensions.EXT_ISSUE_COL).setValue(new IntegerType(message.getCol()));
|
||||
}
|
||||
issue.setSeverity(convert(message.getLevel()));
|
||||
CodeableConcept c = new CodeableConcept();
|
||||
c.setText(message.getMessage());
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.hl7.fhir.r5.model.TypeDetails;
|
|||
import org.hl7.fhir.r5.model.ExpressionNode;
|
||||
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine.IssueMessage;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||
import org.hl7.fhir.utilities.json.model.JsonBoolean;
|
||||
|
@ -253,7 +254,7 @@ public class Validator {
|
|||
} else {
|
||||
String expr = expression.asString();
|
||||
|
||||
List<String> warnings = new ArrayList<>();
|
||||
List<IssueMessage> warnings = new ArrayList<>();
|
||||
TypeDetails td = null;
|
||||
ExpressionNode node = null;
|
||||
try {
|
||||
|
@ -264,8 +265,8 @@ public class Validator {
|
|||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
||||
}
|
||||
if (td != null && node != null) {
|
||||
for (String s : warnings) {
|
||||
warning(path+".path", expression, s);
|
||||
for (IssueMessage s : warnings) {
|
||||
warning(path+".path", expression, s.getMessage());
|
||||
}
|
||||
String columnName = null;
|
||||
JsonElement nameJ = column.get("name");
|
||||
|
@ -419,7 +420,7 @@ public class Validator {
|
|||
} else {
|
||||
String expr = expression.asString();
|
||||
|
||||
List<String> warnings = new ArrayList<>();
|
||||
List<IssueMessage> warnings = new ArrayList<>();
|
||||
TypeDetails td = null;
|
||||
try {
|
||||
ExpressionNode n = fpe.parse(expr);
|
||||
|
@ -429,8 +430,8 @@ public class Validator {
|
|||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
||||
}
|
||||
if (td != null) {
|
||||
for (String s : warnings) {
|
||||
warning(path+".forEach", expression, s);
|
||||
for (IssueMessage s : warnings) {
|
||||
warning(path+".forEach", expression, s.getMessage());
|
||||
}
|
||||
}
|
||||
return td;
|
||||
|
@ -444,7 +445,7 @@ public class Validator {
|
|||
} else {
|
||||
String expr = expression.asString();
|
||||
|
||||
List<String> warnings = new ArrayList<>();
|
||||
List<IssueMessage> warnings = new ArrayList<>();
|
||||
TypeDetails td = null;
|
||||
try {
|
||||
ExpressionNode n = fpe.parse(expr);
|
||||
|
@ -454,8 +455,8 @@ public class Validator {
|
|||
error(path, expression, e.getMessage(), IssueType.INVALID);
|
||||
}
|
||||
if (td != null) {
|
||||
for (String s : warnings) {
|
||||
warning(path+".forEachOrNull", expression, s);
|
||||
for (IssueMessage s : warnings) {
|
||||
warning(path+".forEachOrNull", expression, s.getMessage());
|
||||
}
|
||||
}
|
||||
return td;
|
||||
|
@ -546,7 +547,7 @@ public class Validator {
|
|||
error(path, where, "No path provided", IssueType.REQUIRED);
|
||||
}
|
||||
List<String> types = new ArrayList<>();
|
||||
List<String> warnings = new ArrayList<>();
|
||||
List<IssueMessage> warnings = new ArrayList<>();
|
||||
types.add(resourceName);
|
||||
TypeDetails td = null;
|
||||
try {
|
||||
|
@ -560,8 +561,8 @@ public class Validator {
|
|||
if (td.getCollectionStatus() != CollectionStatus.SINGLETON || td.getTypes().size() != 1 || !td.hasType("boolean")) {
|
||||
error(path+".path", where.get("path"), "A where path must return a boolean, but the expression "+expr+" returns a "+td.describe(), IssueType.BUSINESSRULE);
|
||||
} else {
|
||||
for (String s : warnings) {
|
||||
warning(path+".path", where.get("path"), s);
|
||||
for (IssueMessage s : warnings) {
|
||||
warning(path+".path", where.get("path"), s.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,10 +39,8 @@ public class PathEngineException extends FHIRException {
|
|||
private static final long serialVersionUID = 31969342112856390L;
|
||||
private SourceLocation location;
|
||||
private String expression;
|
||||
|
||||
public PathEngineException() {
|
||||
super();
|
||||
}
|
||||
private String id;
|
||||
|
||||
|
||||
public PathEngineException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
|
@ -59,6 +57,26 @@ public class PathEngineException extends FHIRException {
|
|||
public PathEngineException(String message, SourceLocation location, String expression) {
|
||||
super(message+rep(location, expression));
|
||||
}
|
||||
|
||||
public PathEngineException(String message, String id, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public PathEngineException(String message, String id) {
|
||||
super(message);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public PathEngineException(String message, String id, SourceLocation location, String expression, Throwable cause) {
|
||||
super(message+rep(location, expression), cause);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public PathEngineException(String message, String id, SourceLocation location, String expression) {
|
||||
super(message+rep(location, expression));
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private static String rep(SourceLocation loc, String expr) {
|
||||
if (loc != null) {
|
||||
|
@ -94,4 +112,8 @@ public class PathEngineException extends FHIRException {
|
|||
this.location = location;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
|
@ -1015,6 +1015,12 @@ public class I18nConstants {
|
|||
public static final String UNABLE_TO_DETERMINE_TYPE_CONTEXT_INV = "UNABLE_TO_DETERMINE_TYPE_CONTEXT_INV";
|
||||
public static final String ED_CONTEXT_INVARIANT_EXPRESSION_ERROR = "ED_CONTEXT_INVARIANT_EXPRESSION_ERROR";
|
||||
public static final String VALIDATION_VAL_PROFILE_SIGNPOST_OBS = "VALIDATION_VAL_PROFILE_SIGNPOST_OBS";
|
||||
public static final String FHIRPATH_INVALID_TYPE = "FHIRPATH_INVALID_TYPE";
|
||||
public static final String FHIRPATH_AS_COLLECTION = "FHIRPATH_AS_COLLECTION";
|
||||
public static final String FHIRPATH_ARITHMETIC_QTY = "FHIRPATH_ARITHMETIC_QTY";
|
||||
public static final String FHIRPATH_ARITHMETIC_UNIT = "FHIRPATH_ARITHMETIC_UNIT";
|
||||
public static final String FHIRPATH_ARITHMETIC_PLUS = "FHIRPATH_ARITHMETIC_PLUS";
|
||||
public static final String FHIRPATH_ARITHMETIC_MINUS = "FHIRPATH_ARITHMETIC_MINUS";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1072,4 +1072,9 @@ CDA_UNKNOWN_TEMPLATE_EXT = The CDA Template {0} / {1} is not known
|
|||
UNABLE_TO_DETERMINE_TYPE_CONTEXT_INV = The types could not be determined from the extension context, so the invariant can't be validated (types = {0})
|
||||
ED_CONTEXT_INVARIANT_EXPRESSION_ERROR = Error in constraint ''{0}'': {1}
|
||||
VALIDATION_VAL_PROFILE_SIGNPOST_OBS = Validate Observation against {1} profile because the {2} code {3} was found
|
||||
|
||||
FHIRPATH_INVALID_TYPE = The type {0} is not valid
|
||||
FHIRPATH_AS_COLLECTION = Attempt to use ''as()'' on more than one item (''{0}'', ''{1}'')
|
||||
FHIRPATH_ARITHMETIC_QTY = Error in date arithmetic: attempt to add a definite quantity duration time unit {0}
|
||||
FHIRPATH_ARITHMETIC_UNIT = Error in date arithmetic: unrecognized time unit {0}
|
||||
FHIRPATH_ARITHMETIC_PLUS = Error in date arithmetic: Unable to add type {0} to {1}
|
||||
FHIRPATH_ARITHMETIC_MINUS = Error in date arithmetic: Unable to subtract type {0} to {1}
|
||||
|
|
|
@ -448,7 +448,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
protected boolean ruleInv(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String theMessage, String invId, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors()) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.ERROR, theMessage).setInvId(invId);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.ERROR, invId).setInvId(invId);
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
@ -472,7 +472,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
protected boolean txRule(List<ValidationMessage> errors, String ruleDate, String txLink, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass && doingErrors()) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
ValidationMessage vm = new ValidationMessage(Source.TerminologyEngine, type, line, col, path, message, IssueSeverity.ERROR).setMessageId(theMessage);
|
||||
ValidationMessage vm = new ValidationMessage(Source.TerminologyEngine, type, line, col, path, message, IssueSeverity.ERROR).setMessageId(idForMessage(theMessage, message));
|
||||
vm.setRuleDate(ruleDate);
|
||||
if (checkMsgId(theMessage, vm)) {
|
||||
errors.add(vm.setTxLink(txLink));
|
||||
|
@ -481,6 +481,10 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
return thePass;
|
||||
}
|
||||
|
||||
private String idForMessage(String theMessage, String message) {
|
||||
return theMessage.equals(message) ? null : theMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a rule and add a {@link IssueSeverity#ERROR} validation message if the validation fails
|
||||
*
|
||||
|
@ -605,18 +609,33 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
|
||||
}
|
||||
|
||||
protected boolean warning(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, String id, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings()) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
IssueSeverity severity = IssueSeverity.WARNING;
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, severity, id);
|
||||
}
|
||||
return thePass;
|
||||
|
||||
}
|
||||
|
||||
protected boolean warningInv(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, String invId, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings()) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
IssueSeverity severity = IssueSeverity.WARNING;
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, severity, msg).setInvId(invId);
|
||||
String id = idForMessage(msg, nmsg);
|
||||
addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, severity, id).setMessageId(id).setInvId(invId);
|
||||
}
|
||||
return thePass;
|
||||
|
||||
}
|
||||
|
||||
protected boolean warning(List<ValidationMessage> errors, String ruleDate, IssueType type, NodeStack stack, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
return warning(errors, ruleDate, type, stack.line(), stack.col(), stack.getLiteralPath(), thePass, msg, theMessageArguments);
|
||||
return warning(errors, ruleDate, type, stack, null, thePass, msg, theMessageArguments);
|
||||
}
|
||||
|
||||
protected boolean warning(List<ValidationMessage> errors, String ruleDate, IssueType type, NodeStack stack, String id, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
return warning(errors, ruleDate, type, stack.line(), stack.col(), stack.getLiteralPath(), id, thePass, msg, theMessageArguments);
|
||||
}
|
||||
|
||||
protected boolean warningPlural(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, int num, String msg, Object... theMessageArguments) {
|
||||
|
@ -664,7 +683,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
protected boolean txWarning(List<ValidationMessage> errors, String ruleDate, String txLink, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
|
||||
if (!thePass && doingWarnings()) {
|
||||
String nmsg = context.formatMessage(msg, theMessageArguments);
|
||||
ValidationMessage vmsg = new ValidationMessage(Source.TerminologyEngine, type, line, col, path, nmsg, IssueSeverity.WARNING).setTxLink(txLink).setMessageId(msg);
|
||||
ValidationMessage vmsg = new ValidationMessage(Source.TerminologyEngine, type, line, col, path, nmsg, IssueSeverity.WARNING).setTxLink(txLink).setMessageId(idForMessage(msg, nmsg));
|
||||
vmsg.setRuleDate(ruleDate);
|
||||
if (checkMsgId(msg, vmsg)) {
|
||||
errors.add(vmsg);
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.hl7.fhir.r5.model.ExpressionNode.Kind;
|
|||
import org.hl7.fhir.r5.model.ExpressionNode.Operation;
|
||||
import org.hl7.fhir.r5.model.SearchParameter;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine.IssueMessage;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
@ -77,10 +78,10 @@ public class SearchParameterValidator extends BaseValidator {
|
|||
private boolean checkExpression(List<ValidationMessage> errors, NodeStack stack, String expression, List<String> bases) {
|
||||
boolean ok = true;
|
||||
try {
|
||||
List<String> warnings = new ArrayList<>();
|
||||
List<IssueMessage> warnings = new ArrayList<>();
|
||||
fpe.checkOnTypes(null, null, bases, fpe.parse(expression), warnings);
|
||||
for (String s : warnings) {
|
||||
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, s);
|
||||
for (IssueMessage m : warnings) {
|
||||
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, m.getId(), false, m.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
|||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine.IssueMessage;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
@ -554,15 +555,15 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
// we got to the root before finding anything typed
|
||||
types.add(elements.get(0).getNamedChildValue("path"));
|
||||
}
|
||||
List<String> warnings = new ArrayList<>();
|
||||
List<IssueMessage> warnings = new ArrayList<>();
|
||||
ValidationContext vc = new ValidationContext(invariant);
|
||||
if (Utilities.existsInList(rootPath, context.getResourceNames())) {
|
||||
fpe.checkOnTypes(vc, rootPath, types, fpe.parse(exp), warnings);
|
||||
} else {
|
||||
fpe.checkOnTypes(vc, "DomainResource", types, fpe.parse(exp), warnings);
|
||||
}
|
||||
for (String s : warnings) {
|
||||
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, key+": "+s);
|
||||
for (IssueMessage s : warnings) {
|
||||
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, s.getId(), false, key+": "+s.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
|
@ -593,11 +594,11 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
hint(errors, "2023-10-31", IssueType.INFORMATIONAL, stack, false, I18nConstants.UNABLE_TO_DETERMINE_TYPE_CONTEXT_INV, listContexts(sd));
|
||||
} else
|
||||
try {
|
||||
List<String> warnings = new ArrayList<>();
|
||||
List<IssueMessage> warnings = new ArrayList<>();
|
||||
ValidationContext vc = new ValidationContext(invariant);
|
||||
fpe.checkOnTypes(vc, "DomainResource", types, fpe.parse(exp), warnings);
|
||||
for (String s : warnings) {
|
||||
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, s);
|
||||
for (IssueMessage s : warnings) {
|
||||
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, s.getId(), false, s.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -20,7 +20,7 @@
|
|||
<properties>
|
||||
<guava_version>32.0.1-jre</guava_version>
|
||||
<hapi_fhir_version>6.4.1</hapi_fhir_version>
|
||||
<validator_test_case_version>1.4.15</validator_test_case_version>
|
||||
<validator_test_case_version>1.4.16-SNAPSHOT</validator_test_case_version>
|
||||
<jackson_version>2.15.2</jackson_version>
|
||||
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||
|
|
Loading…
Reference in New Issue