Camunda can not handle java.sql.Date type

Hi All,
we have a dmn rule, which accepts an input variable with ‘date’ type, and the actual input data object type is java.sql.Date, as the input is from a spark reader doing a DB2 db query.

when we run evaluateDecisionTable, it will throw exception, how to make FEEL engine support java.sql.Date type? our jar is feel-engine-1.13.1.jar

Exception in thread “main” java.lang.UnsupportedOperationException
at java.sql/java.sql.Date.toInstant(Date.java:316)
at org.camunda.feel.impl.DefaultValueMapper.toVal(DefaultValueMapper.scala:90)
at org.camunda.feel.valuemapper.ValueMapper$CompositeValueMapper.$anonfun$toVal$1(ValueMapper.scala:41)
at org.camunda.feel.valuemapper.ValueMapper$CompositeValueMapper.$anonfun$toVal$1$adapted(ValueMapper.scala:40)
at camundajar.impl.scala.collection.immutable.List.foreach(List.scala:333)
at org.camunda.feel.valuemapper.ValueMapper$CompositeValueMapper.toVal(ValueMapper.scala:40)
at org.camunda.feel.impl.interpreter.EvalContext.$anonfun$variable$1(EvalContext.scala:33)
at camundajar.impl.scala.Option.map(Option.scala:242)
at org.camunda.feel.impl.interpreter.EvalContext.variable(EvalContext.scala:33)
at org.camunda.feel.impl.interpreter.FeelInterpreter.eval(FeelInterpreter.scala:133)
at org.camunda.feel.FeelEngine.eval(FeelEngine.scala:203)
at org.camunda.feel.FeelEngine.$anonfun$eval$2(FeelEngine.scala:199)
at camundajar.impl.scala.util.Either.flatMap(Either.scala:352)
at org.camunda.feel.FeelEngine.eval(FeelEngine.scala:199)
at org.camunda.feel.FeelEngine.$anonfun$eval$1(FeelEngine.scala:176)
at camundajar.impl.scala.util.Either.flatMap(Either.scala:352)
at org.camunda.feel.FeelEngine.eval(FeelEngine.scala:176)
at org.camunda.feel.FeelEngine.evalExpression(FeelEngine.scala:149)
at org.camunda.bpm.dmn.feel.impl.scala.ScalaFeelEngine.evaluateSimpleExpression(ScalaFeelEngine.java:72)
at org.camunda.bpm.dmn.engine.impl.evaluation.ExpressionEvaluationHandler.evaluateFeelSimpleExpression(ExpressionEvaluationHandler.java:130)
at org.camunda.bpm.dmn.engine.impl.evaluation.ExpressionEvaluationHandler.evaluateExpression(ExpressionEvaluationHandler.java:59)
at org.camunda.bpm.dmn.engine.impl.evaluation.DecisionTableEvaluationHandler.evaluateInputExpression(DecisionTableEvaluationHandler.java:193)
at org.camunda.bpm.dmn.engine.impl.evaluation.DecisionTableEvaluationHandler.evaluateInput(DecisionTableEvaluationHandler.java:122)
at org.camunda.bpm.dmn.engine.impl.evaluation.DecisionTableEvaluationHandler.evaluateDecisionTable(DecisionTableEvaluationHandler.java:104)

my test code is:

public static void main(String[] args) throws FileNotFoundException {
    String ruleDefinition = Files.readFileText("c:\\msde\\shenghaw\\JOSH_RULE_12_Version_2.dmn");
    var config = new DefaultDmnEngineConfiguration();
    DmnEngine dmnEngine = config.buildEngine();

    List<DmnDecision> decisions = null;
    try (var stream = new ByteArrayInputStream(ruleDefinition.getBytes(UTF_8))) {
        long s3 = System.currentTimeMillis();
        decisions = dmnEngine.parseDecisions(stream);
        long s4 = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName() + "/parseDecision duration:" + (s4 - s3));

    } catch (IOException e) {
        e.printStackTrace();
    }

    VariableMap variables = createVariables();
    variables.putValue("ASOF_DATE", new java.sql.Date(new java.util.Date().getTime()));
    DmnDecision dmnDecision = decisions.get(0);

    List<Map<String, Object>> dmnDecisionRuleResults = dmnEngine.evaluateDecisionTable(dmnDecision, variables).getResultList();
    for (var i : dmnDecisionRuleResults) {
        for (var j : i.entrySet()) {
            System.out.println(String.format("%s=>%s, %s", j.getKey(), j.getValue(), j.getValue().getClass().getTypeName()));
        }
    }
}

the rule definition is:
JOSH_RULE_12_Version_2.dmn (1.4 KB)

Hi @Shenghao_Wu. :wave:

My first idea would be to not pass a java.sql.Data to the DMN engine but transfer the value into a support type, for example java.util.Date.

If you really want to pass the java.sql.Data, you could look into the following options:

Does this help you?

Hi @Philipp_Ossler ,
Thanks for your suggestions, I tried:

  1. extend DateDataTypeTransformer, but it seems not works, no code run into my custom DateDataTypeTransformer.
    public static class GermanDateDataTypeTransformer extends DateDataTypeTransformer {

        @Override
        public TypedValue transform(Object value) throws IllegalArgumentException {
            if(value instanceof java.sql.Date){
                java.util.Date d1 = new java.util.Date(((java.sql.Date)value).getTime());
                return Variables.dateValue((Date) d1);
            }else{
                return super.transform(value);
            }
        }
    }
  1. for value mapper, can you tell me how to register my custom value mapper, by NOT using service locator mode. and one more questoin, if input
    java.util.Date and java.sql.Date all are translated into DMN internal DateType.
    then when convert out, from DMN internal DateType, how to decide convert to which type? java.util.Date or java.sql.Date.

It sounds like your transformer is not registered or not configured correctly.

Make sure to register your transformer: Embedding the DMN Engine | docs.camunda.org

And to use the same type name in your DMN.

The SPI method is the default behavior that works out of the box. Setting the value mapper programmatically is maybe possible but would require more configuration code. I can’t provide you any examples here.

The value mapper decided the result type.