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

В Spel легко присвоить некоторые значения свойству List. Например, имея объект foo со свойством, определенным как List, я обычно делаю:

SpelParserConfiguration config = new SpelParserConfiguration(true,true);
ExpressionParser parser = new SpelExpressionParser(config);
Foo foo = new Foo();
EvaluationContext context = new StandardEvaluationContext(foo);
parser.parseExpression("barList[1].test='11111111'")
    .getValue(context);

Но что делать, если вы хотите присвоить значения данному списку, определенному как переменная в методе. например:

List<String> fooList = new ArrayList<String>();
context = new StandardEvaluationContext(fooList);       
parser.parseExpression("SOMETHING[0]='come on'")
.getValue(context);

В приведенном выше примере я не знаю, что поставить вместо SOMETHING, чтобы все заработало. Если я поставлю "fooList[0]='....'", будет выдано исключение, жалующееся на отсутствие свойства fooList в fooList.

Если я поставлю "[0]='....'", он выдает Невозможно увеличить коллекцию: невозможно определить тип элемента списка.

Затем я пришел к определению универсальной оболочки следующим образом:

public static class SpelWrapper<T>
{
    T obj;

    public SpelWrapper(T obj)
    {
        this.obj = obj;
    }

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

а затем попытался проверить это:

List<String> fooList = new ArrayList<String>();
    SpelWrapper<List<String>> no = new SpelWrapper<List<String>>(fooList);
    context = new StandardEvaluationContext(no);

    parser.parseExpression("obj[0]='olaaa'")
    .getValue(context);

Но это не сработало, и я все еще получаю это уродливое сообщение:

Unable to grow collection: unable to determine list element type

Я пробовал другие языки выражений, такие как MVEL, OGNL, JEXL, но заметил, что они не поддерживают автоматическую инициализацию нулевой ссылки, что для меня важно. Однако у них, похоже, тоже не было решения вышеуказанной проблемы.

Я также начал думать, что, если то, что мне нужно, не относится к языкам выражений! Дело в том, что мне нужно не просто определить переменную и попытаться присвоить значения с помощью EL.

В моем случае у меня есть несколько простых bean-компонентов класса домена POJO и некоторые входные строки, такие как

 "bar[0].foo.value=3434"

Теперь я должен иметь возможность создать List of Bar и поместить экземпляр Bar в качестве его первого элемента, затем установить свойство foo с экземпляром Foo и, наконец, установить значение Foo как 3434.

Любая идея по этой проблеме?

заранее спасибо

Да Я был неправ в "Однако у них, похоже, тоже не было решения вышеуказанной проблемы". Например, в МВЭЛ это очень легко сделать. Но, к сожалению, способность SPLE автоматически расширять списки и автоматически назначать инициаторов в нулевых цепочках делает его невероятно подходящим для моего случая.


person madz    schedule 11.02.2015    source источник


Ответы (3)


Проблема связана с стиранием типа в Java, Spring или других Els, которые не знают, как автоматически инициировать нули в цепочке для общих корневых объектов, включая списки. Например, в таком выражении в SpEl:

#root[10].mySet='ohoy'

Если он обнаружит, что ему нужно сначала инициировать ArrayList, нет способа узнать, какой тип элемента является правильным для инициации по данному индексу. Вот почему ему нужна оболочка для использования отражения возвращаемого типа геттера.

Еще одна работа — использование массива. Поскольку тип компонента массива сохраняется во время выполнения. Но загвоздка в том, что размер массивов нельзя изменить во время выполнения. Таким образом, они должны быть инициированы с достаточным размером, чтобы предотвратить выход индекса за пределы допустимого диапазона.

В любом случае, стирание шрифта — это настоящая головная боль, чтобы делать такие вещи, кажется, что они (применяется и к другим EL) все еще могут приложить некоторые усилия, чтобы сделать некоторые работы вокруг этого. Например

1) Если список не пустой, можно получить из него реальный тип элемента во время выполнения.
2) Изменить getValue, чтобы получить переданный параметр универсального типа и использовать его для инициализации.
3) В случае массивов вернуть расширенный массив.
4) ...

Хотя реализация хорошего EL, который обещает обрабатывать все виды инициации или расширения, кажется действительно тяжелой работой, я работал над расширением Ognl, чтобы добиться этого. я начал с

PropertyAccessor

и получил действительно многообещающие результаты. Однако я не знаю, что не так с apache, когда дело доходит до разработки библиотек. Например, мне не нравится, как они помещают обработчики в статический класс. Я думаю, что обработчик - это вопрос контекста, и все же я не знаю, стоит ли тратить время на расширение Ognl, но как только я закончу работу, я поделюсь результатом.

person madz    schedule 13.02.2015

Вам нужно будет определить переменную в своем выражении и заполнить ее списком для обработки, например.

context.setVariable("mylist", fooList);

Затем вы можете получить к нему доступ следующим образом:

parser.parseExpression("#mylist.set(0)='come on'").getValue(context);

Список в переменной используется отражением; вы можете вызывать методы и т. д. Надеюсь, это поможет.

person Uwe Allner    schedule 11.02.2015
comment
Спасибо @Uwe Aliner за ответ. Но у меня есть пара проблем с этим решением. 1) Наличие контекста = новый StandardEvaluationContext(); а затем context.setVariable(fooList, fooList); и, наконец, парсер = новый SpelExpressionParser(config); parser.parseExpression(#fooList.set(0)='ооооооо') .getValue(контекст); выдает это исключение: setValue (ExpressionState, Object) не поддерживается для «класса org.springframework.expression.spel.ast.MethodReference» - person madz; 11.02.2015
comment
2) Я не мог определить переменную и после установки контекста просто сделал: #root[0]='ooooo'. Проблема в том, что он выдает Cannot index в нулевое значение. Затем создание контекста, способного автоматически расширять списки (с помощью th SpelParserConfiguration), снова приводит к сбою с Невозможно увеличить коллекцию: невозможно определить тип элемента списка - person madz; 11.02.2015
comment
Если я сам расширю список в первом решении, проблема будет решена. Но из-за выражений (вроде как я не могу манипулировать выражением в их источнике, они такие, какие они есть. Я могу изменить их только после того, как получу их. например, с помощью регулярного выражения) я хотел посмотреть, есть ли способ решите это с помощью простого решения EL и не пачкайте руки;) - person madz; 11.02.2015

В соответствии с этим ответом должно работать следующее:

parser.parseExpression("obj").getValue(context, "olaaa"); // or is it "'olaaa'"?

или даже что-то вроде

parser.parseExpression("obj").getValue(context, "'olaaa', 'alooo'");
person crusy    schedule 09.07.2020