This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push: new 6cfb392756 Use '+=' rather than '+' for merging collections. 6cfb392756 is described below commit 6cfb3927562a992fdab9d72555bb7a7943c5d539 Author: Mark Thomas <ma...@apache.org> AuthorDate: Fri May 23 16:44:57 2025 +0100 Use '+=' rather than '+' for merging collections. The concatenation operator seems more appropriate here than the additional operator. --- java/org/apache/el/parser/AstConcatenation.java | 26 +++++ java/org/apache/el/parser/AstPlus.java | 23 ---- .../org/apache/el/parser/TestAstConcatenation.java | 100 +++++++++++++++++ test/org/apache/el/parser/TestAstPlus.java | 124 --------------------- webapps/docs/changelog.xml | 2 +- 5 files changed, 127 insertions(+), 148 deletions(-) diff --git a/java/org/apache/el/parser/AstConcatenation.java b/java/org/apache/el/parser/AstConcatenation.java index ae83893170..95a4dc85f9 100644 --- a/java/org/apache/el/parser/AstConcatenation.java +++ b/java/org/apache/el/parser/AstConcatenation.java @@ -17,6 +17,11 @@ /* Generated By:JJTree: Do not edit this line. AstConcatenation.java Version 4.3 */ package org.apache.el.parser; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + import jakarta.el.ELException; import org.apache.el.lang.ELSupport; @@ -29,8 +34,29 @@ public class AstConcatenation extends SimpleNode { } + @SuppressWarnings("unchecked") @Override public Object getValue(EvaluationContext ctx) throws ELException { + + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + + if (obj0 != null) { + if (obj0 instanceof Map m0 && obj1 instanceof Map m1) { + // Maps are merged + m0.putAll(m1); + return obj0; + } else if (obj0 instanceof Set s0 && obj1 instanceof Collection c1) { + // If obj0 is a Set then merge + s0.addAll(c1); + return obj0; + } else if (obj0 instanceof List l0 && obj1 instanceof Collection c1) { + // If obj0 is a List then concatenate + l0.addAll(c1); + return obj0; + } + } + // Coerce the two child nodes to string and then concatenate String s1 = ELSupport.coerceToString(ctx, children[0].getValue(ctx)); String s2 = ELSupport.coerceToString(ctx, children[1].getValue(ctx)); diff --git a/java/org/apache/el/parser/AstPlus.java b/java/org/apache/el/parser/AstPlus.java index fb59c06b4c..ab6121612b 100644 --- a/java/org/apache/el/parser/AstPlus.java +++ b/java/org/apache/el/parser/AstPlus.java @@ -17,17 +17,11 @@ /* Generated By:JJTree: Do not edit this line. AstPlus.java */ package org.apache.el.parser; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - import jakarta.el.ELException; import org.apache.el.lang.ELArithmetic; import org.apache.el.lang.EvaluationContext; - /** * @author Jacob Hookom [ja...@hookom.net] */ @@ -38,28 +32,11 @@ public final class AstPlus extends ArithmeticNode { } - @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); - if (obj0 != null) { - if (obj0 instanceof Map && obj1 instanceof Map) { - // Maps are merged - ((Map) obj0).putAll((Map) obj1); - return obj0; - } else if (obj0 instanceof Set && obj1 instanceof Collection) { - // If obj0 is a Set then merge - ((Set<?>) obj0).addAll((Collection) obj1); - return obj0; - } else if (obj0 instanceof List && obj1 instanceof Collection) { - // If obj0 is a List then concatenate - ((List) obj0).addAll((Collection) obj1); - return obj0; - } - } - return ELArithmetic.add(obj0, obj1); } } diff --git a/test/org/apache/el/parser/TestAstConcatenation.java b/test/org/apache/el/parser/TestAstConcatenation.java index 68c51a8782..be47030c9a 100644 --- a/test/org/apache/el/parser/TestAstConcatenation.java +++ b/test/org/apache/el/parser/TestAstConcatenation.java @@ -16,6 +16,13 @@ */ package org.apache.el.parser; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + import jakarta.el.ELContext; import jakarta.el.ELManager; import jakarta.el.ELProcessor; @@ -27,6 +34,99 @@ import org.junit.Test; public class TestAstConcatenation { + private static final List<String> simpleList = new ArrayList<>(); + private static final Map<String,String> simpleMap = new HashMap<>(); + private static final Set<String> simpleSet = new HashSet<>(); + + static { + simpleList.add("a"); + simpleList.add("b"); + simpleList.add("c"); + simpleList.add("b"); + simpleList.add("c"); + + simpleMap.put("a", "1"); + simpleMap.put("b", "2"); + simpleMap.put("c", "3"); + + simpleSet.add("a"); + simpleSet.add("b"); + simpleSet.add("c"); + } + + + @Test + public void testNullConcatNull() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("null += null", Integer.class); + Assert.assertEquals(Integer.valueOf(0), result); + } + + + @Test + public void testMapConcatMapNoConflicts() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("{'a':'1','b':'2'} += {'c':'3'}", Map.class); + Assert.assertEquals(simpleMap, result); + } + + + @Test + public void testMapConcatMapConflicts() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("{'a':'1','b':'3'} += {'b':'2','c':'3'}", Map.class); + Assert.assertEquals(simpleMap, result); + } + + + @Test + public void testSetConcatSetNoConflicts() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("{'a','b'} += {'c'}", Set.class); + Assert.assertEquals(simpleSet, result); + } + + + @Test + public void testSetConcatSetConflicts() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("{'a','b'} += {'b','c'}", Set.class); + Assert.assertEquals(simpleSet, result); + } + + + @Test + public void testSetConcatListNoConflicts() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("{'a','b'} += ['c']", Set.class); + Assert.assertEquals(simpleSet, result); + } + + + @Test + public void testSetConcatListConflicts() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("{'a','b'} += ['b','c','c']", Set.class); + Assert.assertEquals(simpleSet, result); + } + + + @Test + public void testListConcatList() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("['a','b','c'] += ['b','c']", List.class); + Assert.assertEquals(simpleList, result); + } + + + @Test + public void testListConcatSet() { + ELProcessor processor = new ELProcessor(); + Object result = processor.getValue("['a','b','c'] += {'b','c'}", List.class); + Assert.assertEquals(simpleList, result); + } + + /** * Test string concatenation. */ diff --git a/test/org/apache/el/parser/TestAstPlus.java b/test/org/apache/el/parser/TestAstPlus.java deleted file mode 100644 index b31c572611..0000000000 --- a/test/org/apache/el/parser/TestAstPlus.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.el.parser; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import jakarta.el.ELProcessor; - -import org.junit.Assert; -import org.junit.Test; - -public class TestAstPlus { - - private static final List<String> simpleList = new ArrayList<>(); - private static final Map<String,String> simpleMap = new HashMap<>(); - private static final Set<String> simpleSet = new HashSet<>(); - - static { - simpleList.add("a"); - simpleList.add("b"); - simpleList.add("c"); - simpleList.add("b"); - simpleList.add("c"); - - simpleMap.put("a", "1"); - simpleMap.put("b", "2"); - simpleMap.put("c", "3"); - - simpleSet.add("a"); - simpleSet.add("b"); - simpleSet.add("c"); - } - - - @Test - public void testNullAddNull() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("null + null", Integer.class); - Assert.assertEquals(Integer.valueOf(0), result); - } - - - @Test - public void testMapAddMapNoConflicts() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("{'a':'1','b':'2'} + {'c':'3'}", Map.class); - Assert.assertEquals(simpleMap, result); - } - - - @Test - public void testMapAddMapConflicts() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("{'a':'1','b':'3'} + {'b':'2','c':'3'}", Map.class); - Assert.assertEquals(simpleMap, result); - } - - - @Test - public void testSetAddSetNoConflicts() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("{'a','b'} + {'c'}", Set.class); - Assert.assertEquals(simpleSet, result); - } - - - @Test - public void testSetAddSetConflicts() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("{'a','b'} + {'b','c'}", Set.class); - Assert.assertEquals(simpleSet, result); - } - - - @Test - public void testSetAddListNoConflicts() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("{'a','b'} + ['c']", Set.class); - Assert.assertEquals(simpleSet, result); - } - - - @Test - public void testSetAddListConflicts() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("{'a','b'} + ['b','c','c']", Set.class); - Assert.assertEquals(simpleSet, result); - } - - - @Test - public void testListAddList() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("['a','b','c'] + ['b','c']", List.class); - Assert.assertEquals(simpleList, result); - } - - - @Test - public void testListAddSet() { - ELProcessor processor = new ELProcessor(); - Object result = processor.getValue("['a','b','c'] + {'b','c'}", List.class); - Assert.assertEquals(simpleList, result); - } -} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 5296c30230..0f5905ab02 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -206,7 +206,7 @@ (<code>??</code>) operators in Jakarta Expression language. (markt) </add> <add> - Extend the existing <code>+</code> operator in Jakarta Expression + Extend the existing <code>+=</code> operator in Jakarta Expression Language to support merging <code>Map</code>Map and <code>Set</code>Set and concatenating <code>List</code>s. (markt) </add> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org