Исключение нулевого указателя с накоплением Drools()

Я пытаюсь выполнить очень простой пример, демонстрирующий использование accumulate() функция Drools, но я получаю исключение java.lang.NullPointerException.

Вот код:

Metric.java:

package com.sample;

public class Metric
{
  public String id;
  public double value;

  public Metric(String id, double value)
  {
    this.id = id;
    this.value = value;
  }
}

ruleFile1.drl:

package com.sample

declare Metric
    @role( event )
end

rule "rule1"
when
    Metric()
    metricAverage: Number() from accumulate(
        Metric( $value : value ),
        average( $value ) )
then
    System.out.println("metric value average " + metricAverage);
end

KSessionGenerator.java:

package com.sample;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import org.kie.api.KieBase;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class KSessionGenerator {

  public KieSession buildKSession(String ruleFilePath){
    KieServices kieServices = KieServices.Factory.get();

    FileInputStream fis = null;
    try {
      fis = new FileInputStream(ruleFilePath);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
      return null;
    }

    String virtualRuleFilePath = "src/main/resources/ruleFile1.drl";
    KieFileSystem kfs = kieServices.newKieFileSystem();
    kfs.write(virtualRuleFilePath, kieServices.getResources().newInputStreamResource(fis));

    KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
    Results results = kieBuilder.getResults();
    if (results.hasMessages(Message.Level.ERROR)) {
      System.out.println(results.getMessages());
      throw new IllegalStateException("### errors ###");
    }

    KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());

    // Change the engine mode to 'stream'
    KieBaseConfiguration config = kieServices.newKieBaseConfiguration();
    config.setOption( EventProcessingOption.STREAM );

    KieBase kieBase = kieContainer.newKieBase( config );
    KieSession kSession = kieBase.newKieSession();

    return kSession;
  }
}

DroolsTest1.java:

package com.sample;

import org.kie.api.runtime.KieSession;

public class DroolsTest1 {

  public static final void main(String[] args) {
    try {
      String ruleFilePath = "src/main/resources/rules/ruleFile1.drl";
      KieSession kSession = (new KSessionGenerator()).buildKSession(ruleFilePath);

      // go !
      Metric metric1 = new Metric("m1", 50);
      Metric metric2 = new Metric("m2", 60);

      kSession.insert(metric1);
      kSession.insert(metric2);

      System.out.println("Firing all rules ...");
      kSession.fireAllRules();
      System.out.println("Rules fired!");

      System.out.println("Bye");
    } catch (Throwable t) {
      t.printStackTrace();
    }
  }
}

kmodule.xml:

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
    <kbase name="rules" packages="rules">
        <ksession name="ksession-rules"/>
    </kbase>
</kmodule>

Полная трассировка стека исключения:

Firing all rules ...
java.lang.RuntimeException: java.lang.NullPointerException
  at org.drools.core.rule.SingleAccumulate.accumulate(SingleAccumulate.java:90)
  at org.drools.core.phreak.PhreakAccumulateNode.addMatch(PhreakAccumulateNode.java:759)
  at org.drools.core.phreak.PhreakAccumulateNode.doLeftInserts(PhreakAccumulateNode.java:163)
  at org.drools.core.phreak.PhreakAccumulateNode.doNode(PhreakAccumulateNode.java:80)
  at org.drools.core.phreak.RuleNetworkEvaluator.switchOnDoBetaNode(RuleNetworkEvaluator.java:562)
  at org.drools.core.phreak.RuleNetworkEvaluator.evalBetaNode(RuleNetworkEvaluator.java:533)
  at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:334)
  at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:161)
  at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:116)
  at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:235)
  at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:106)
  at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:1016)
  at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1302)
  at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1289)
  at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1262)
  at com.sample.DroolsTest1.main(DroolsTest1.java:20)
Caused by: java.lang.NullPointerException
  at org.drools.core.rule.Declaration.getValue(Declaration.java:228)
  at com.sample.Rule_rule11017979978AccumulateExpression0Invoker.evaluate(Rule_rule11017979978AccumulateExpression0Invoker.java:19)
  at org.drools.core.base.accumulators.JavaAccumulatorFunctionExecutor.accumulate(JavaAccumulatorFunctionExecutor.java:109)
  at org.drools.core.rule.SingleAccumulate.accumulate(SingleAccumulate.java:82)
  ... 15 more

Я использую Drools версии 6.2.0 Final через плагин на Eclipse Mars 4.5.2.

Может ли кто-нибудь сказать мне причину ошибки вместе с ее решением?


person Anmol Singh Jaggi    schedule 30.09.2016    source источник
comment
Возможный дубликат Что такое исключение NullPointerException и как его исправить?   -  person Raedwald    schedule 30.09.2016
comment
@Raedwald Как это дубликат этого вопроса?   -  person Anmol Singh Jaggi    schedule 30.09.2016
comment
@Raedwald: я думаю, что ОП хорошо знает, что такое NPE, и вопрос нацелен на конкретный, нетривиальный случай, см. мой ответ ниже. ИМХО, это определенно не дубликат общего вопроса, который вы связали   -  person hammerfest    schedule 30.09.2016


Ответы (1)


Пробовал код, NPE вызвано

"$value" -> "Method threw 'java.lang.NullPointerException' exception. 
Cannot evaluate org.drools.core.rule.Declaration.toString()"

Это связано с тем, что у класса Metric нет методов получения для своих полей. Добавьте геттеры и код выполнится без проблем

person hammerfest    schedule 30.09.2016
comment
Это устраняет ошибку. Но я не понимаю, как? Почему наличие геттеров должно влиять на выполнение правил? Свойства класса в любом случае общедоступны. Кроме того, упомянутая вами ошибка - Cannot evaluate org.drools.core.rule.Declaration.toString()" отсутствует в трассировке стека, которую я написал в вопросе. Как вы это получили? - person Anmol Singh Jaggi; 30.09.2016
comment
Трассировка стека включает org.drools.core.rule.Declaration.getValue(Declaration.java:228). Поставьте точку останова в этом методе, и вы увидите завернутую ошибку в отладчике. Открытость полей класса не обязательно означает, что они видны для обработки механизмами фреймворка, которые часто работают только через геттеры, используя отражение. Я не проверял это более подробно в отношении Drools, но встречал подобные проблемы в прошлом в других фреймворках. Использование закрытых полей и общедоступных методов получения обычно является хорошей практикой. - person hammerfest; 30.09.2016