Правило Drools, проверяющее объекты в типе Scala Option

(Обязательный отказ от ответственности для новичков)

Я пытаюсь написать правило, которое срабатывает всякий раз, когда объект в списке (scala) соответствует условию. Проблема здесь в том, что список на самом деле является Option(List[TypeA])... (Кроме того, я понимаю, что не рекомендуется хранить списки в рабочей памяти, но я не могу поступить иначе, учитывая обстоятельства)

Классы case, которые я использую, имеют следующую структуру:

TypeA {
    arg1 : Option[List[TypeB]]
}

с участием

TypeB {
    value : String
}

Я написал правило, подобное этому:

when
    $a : TypeA($l : arg1)
    $b : TypeB() from $l.get()
then
    System.out.println($b)

Я пробовал это без ".get()" только для получения объекта типа Some().

Используя ".get()", мне удалось вернуть содержимое Option, но оно, похоже, не соответствует ожидаемому типу (List[TypeB]). Вместо этого тип возвращаемого значения кажется scala.collection.immutable.$colon$colon.

Есть идеи, в чем проблема? И есть ли какой-нибудь правильный способ обработки параметров в Drools?


person GroomedGorilla    schedule 09.02.2015    source источник
comment
Это снова ты! Мы с @laune не предупреждали вас об использовании Scala с Drools. Люди из Drools не подтвердили официально, что эти два инструмента совместимы.   -  person M.K.    schedule 09.02.2015
comment
Ага, снова я ;) Предупреждение получено, но я работаю с объектами Scala (на данный момент нет выбора) и на этот раз взаимодействую с ними, используя методы Java... на данный момент это скорее доказательство концепции. До сих пор мне удавалось хорошо использовать объекты Scala в Java, только это небольшое раздражение удерживает меня в данный момент... Идеи?   -  person GroomedGorilla    schedule 09.02.2015
comment
Нет ничего плохого в том, что список является свойством некоторых объектов. Это список (или любая другая коллекция или карта), используемый как факт, который не является хорошим дизайном.   -  person laune    schedule 09.02.2015
comment
Насколько это важно из вашего списка с Option? Пытались ли вы увидеть тип, который вы получите обратно с этим? Мне было бы очень интересно узнать тип, который возвращается. Вы можете это сделать?   -  person M.K.    schedule 10.02.2015
comment
К сожалению, классы case не принадлежат мне, но это то, с чем мне приходится работать (не могу их изменить). Я сделал это с помощью .get(), но все, что я получил, было что-то типа scala.collection.immutable.$colon$colon ... который я принял за общий список с головой и хвостом. Глядя на ваш ответ re: javaconverters в mo ... кажется очень полезным! Спасибо   -  person GroomedGorilla    schedule 11.02.2015


Ответы (2)


Поскольку вы много взаимодействуете с Java и Scala, я предлагаю вам хорошо ознакомиться с javaconverters. Этот удобный набор утилит позволяет преобразовывать коллекции Scala в коллекции Java и наоборот.

В вашем случае, я думаю, вам нужно преобразовать коллекцию Java в коллекцию Scala. Попробуйте следующее:

import scala.collection.JavaConverters._

val myScalaList = $b.asScala.toList

Пример из документации:

import scala.collection.JavaConverters._

val sl = new scala.collection.mutable.ListBuffer[Int]
val jl : java.util.List[Int] = sl.asJava
val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala
assert(sl eq sl2)

Дополнительная проблема, с которой вы сталкиваетесь, связана с изменяемыми и неизменяемыми структурами данных. Стандартная структура списка в Java является изменяемой, но по умолчанию Scala предлагает вам неизменяемый список, если вы явно не укажете, что вам нужен изменяемый список. Следовательно, при простом преобразовании между двумя мирами будет некоторое несоответствие импеданса.

Как я упоминал в предыдущем посте, вы можете избежать многих проблем, создав классы Java для сущностей, которые вам нужно отправить в Drools. Смешивание классов Java с классами Scala в проектах на основе Scala не является проблемой.

Альтернативный метод заключается в создании функции в классе case Scala, которая преобразует коллекцию Scala в коллекцию Java с помощью метода asJava и возвращает ее. В вашем файле DRL всякий раз, когда вам нужно сослаться на эту коллекцию scala, вызывайте этот метод, чтобы вместо этого получить коллекцию Java.

В идеале, JBoss Drools, если они того пожелают, должны либо улучшить свой текущий компилятор, чтобы лучше справляться с типами Scala, либо создать специальный компилятор Drools Scala, который не будет искажать типы Scala.

person M.K.    schedule 10.02.2015
comment
Не большая удача. Проблема в том, что я не могу попасть в список. Я пытался вызвать $l.get().asJava() / asScala() в правой части правила, но продолжал получать ошибки, связанные со строгим режимом: [Error: unable to resolve method using strict-mode: java.lang.Object.asScala()] (для которого я не нашел решения с версии 6.1 KieSessions). Я пробовал .get() для аргументов Option, которые не являются списками, и Drools, похоже, возвращают объект класса case Scala, но опять же я не могу копаться в его аргументах (т.е. я бы получил TypeB, но получил бы ошибки при чтении typeBObj .ценность). - person GroomedGorilla; 11.02.2015
comment
вы импортировали эти методы, т.е. import scala.collection.JavaConverters._ - person M.K.; 11.02.2015
comment
да, импортировали как scala.collections.JavaConverters.*, так и scala.collections.JavaConversions.* в файл drl - person GroomedGorilla; 11.02.2015
comment
Drools не может найти эти методы, потому что не знает, где искать. Если вы посмотрите на сообщение об ошибке, оно пытается найти эти методы в API Java, хотя на самом деле они находятся в API Scala. - person M.K.; 11.02.2015
comment
Вы правы, слишком долго смотрели на эту проблему, чтобы понять... Итак... нет способа конвертировать между ними в самих правилах? - person GroomedGorilla; 11.02.2015
comment
Попробуйте этот прием: создайте функцию в своем кейс-классе Scala, которая преобразует коллекцию Scala в коллекцию Java с помощью метода asJava и возвращает ее. В вашем файле DRL всякий раз, когда вам нужно сослаться на эту коллекцию scala, вызывайте этот метод, чтобы вместо этого получить коллекцию Java. - person M.K.; 11.02.2015
comment
Святое дерьмо, кажется, работает! Написание функций-оболочек для каждого параметра, с которым мне нужно иметь дело, будет сложной задачей, но, по крайней мере, это обходной путь! Если вы хотите опубликовать это как ответ, я отмечу это как решение. Спасибо! - person GroomedGorilla; 11.02.2015
comment
РЖУ НЕ МОГУ. Обновил ответ. Давайте продолжим обсуждение в чате. - person M.K.; 11.02.2015

Единственное, что я могу придумать, чтобы попробовать:

when
    $a : TypeA($l : arg)
    $b : TypeB() from (ArrayList)$l.get() // or some other Java *-List
then
    System.out.println($b)

Стоит еще раз попробовать:

when
    $a : TypeA($l : arg)
    $b : TypeB() from $l.get()asJava()*-List
then
    System.out.println($b)
person laune    schedule 09.02.2015
comment
Что еще - тут только Java. Если вы знаете лучший целевой класс для приведения, используйте его. - person laune; 09.02.2015
comment
@laune, у ОП также есть проблемы с изменчивостью и неизменностью. Из сообщения видно, что список Scala неизменяем. Однако, как вы знаете, ArrayList изменчив. Получение однозначного сопоставления со структурами данных Scala из Java будет, по меньшей мере, сложным. - person M.K.; 10.02.2015
comment
Спасибо @laune. Пробовал и это, но он возвращает пустой список и вообще не соответствует LHS. - person GroomedGorilla; 11.02.2015
comment
Можно ли написать $l.get().asJava()? Это должно вернуть изменяемый список Java (если я правильно понял IK). - person laune; 11.02.2015
comment
Однако не в файле drl. Вместо этого я вызываю метод scala, который возвращает $l.get.asJava. Очень похоже на оболочку Java, которую вы упомянули в другом вопросе @laune. - person GroomedGorilla; 11.02.2015