update error handling to preserve message ids properly

This commit is contained in:
Grahame Grieve 2023-11-09 16:51:15 +11:00
parent f07a779d36
commit dc791becaa
10 changed files with 138 additions and 60 deletions

View File

@ -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
}

View File

@ -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());

View File

@ -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());
}
}
}

View File

@ -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;
}
}

View File

@ -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";
}

View File

@ -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}

View File

@ -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);

View File

@ -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) {

View File

@ -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) {

View File

@ -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>