Есть ли какая-либо ошибка в моем коде при использовании evaluate в groovy?

#groovy #evaluate

#groovy #оценить

Вопрос:

Я устанавливаю значение для вложенной карты, все ключи существуют, вот мой код:

 def map = [a1:[a2:[a3:'a123']], b1:[b2:[b3_1:'b234', b3_2:'b345']], d1:'d1']
def name2 = "b1:::b2:::b3_1"
def data = "test"
def separator = ":::"

def names = name2.split(separator)

setValue(map, names, data)

def setValue(def map, def keys, def data) {
    tmpMap = map
    String str = 'map' 
    for (i = 0; i < keys.size(); i  ) {
        str = str.concat('.'  keys[i])
    }
    str = str.concat(" = '"   data   "'")

    evaluate(str)
}
  

содержимое str будет «map.b1.b2.b3_1 = ‘test'»
Я могу запустить его вручную, и содержимое карты изменится, но когда я использую evaluate, появляется ошибка «java.lang.Исключение NullPointerException: не удается получить свойство ‘b2’ для нулевого объекта «, не могли бы вы, пожалуйста, сказать мне, что не так с кодом, большое спасибо.

Ответ №1:

То, что вы пытаетесь сделать, сложно…

Одним из методов было бы использовать Eval.x и передавать карту как x :

 def setValue(Map map, String[] keys, String data) {
    def command = "x.${keys.join('.')} = '$data'"
    Eval.x(map, command)
}
  

Итак, здесь команда будет: x.b1.b2.b3_1 = 'test' и мы оцениваем ее, x принимая за значение map

Другой (более уродливый) метод заключается в использовании inject для обхода карты до последнего ключа, а затем установки значения последнего ключа этого возвращаемого объекта:

 def setValue(Map map, String[] keys, String data) {
    keys[0..-2].inject(map) { a, b -> a."$b" }."${keys[-1]}" = data
}
  

Однако вам следует остерегаться оценивать код волей-неволей….

Например, следующий ввод, который вы можете получить:

 def name2 = "val = { -> println "${System.properties.'user.name'}" }.call(); def a"
  

Выполняется вычисление выражения (для меня):

 x.val = { -> println "tim" }.call(); def a = 'test'
  

Который затем печатает имя пользователя… Вы можете увидеть, как это можно адаптировать для загрузки файла из Интернета и размещения его на чьем-либо компьютере…

Если вы можете… Вам следует избегать этого… Или, по крайней мере, иметь строгие белые списки того, что разрешено

Комментарии:

1. спасибо за ваш ответ, я попробовал ваш первый метод, и он сработал, как вы и сказали, он показался мне немного уродливым, поэтому я использовал рекурсивный метод для его решения, большое спасибо за вашу разогревающую помощь!

Ответ №2:

рекурсивный подход:

 def setValue(def map, List keys, def data) {
    return keys.size()>1 ? 
        setValue(map[keys[0]],keys.subList(1,keys.size()),data) : 
            map.put(keys[0],data)
}
  

Комментарии:

1. Привет, твоя идея хороша, но результат не тот, который я хочу, я пробовал, возвращаемое значение равно b234

2. Он возвращает старое значение из map. И изменяет карту. Вы можете это проверить.

3. Прошу прощения, что так долго не отвечал, вы правы, это сработало и решило мою проблему, большое спасибо!