diff --git a/modules/core/test/com/haulmont/cuba/namepattern/NamePatternTest.java b/modules/core/test/com/haulmont/cuba/namepattern/NamePatternTest.java new file mode 100644 index 0000000000..b7f4902551 --- /dev/null +++ b/modules/core/test/com/haulmont/cuba/namepattern/NamePatternTest.java @@ -0,0 +1,85 @@ +package com.haulmont.cuba.namepattern; + +import com.haulmont.cuba.testmodel.namepattern.MethodNamePatternEntity; +import com.haulmont.cuba.testmodel.namepattern.SpelNamePatternEntity; +import com.haulmont.cuba.testmodel.namepattern.SimpleNamePatternEntity; +import com.haulmont.cuba.testsupport.TestContainer; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +/** + * @author Rushan Zagidullin + * @since 17.07.2018 + */ +public class NamePatternTest { + + @ClassRule + public static TestContainer container = TestContainer.Common.INSTANCE; + + SimpleNamePatternEntity simpleNamePatternEntity1; + SimpleNamePatternEntity simpleNamePatternEntity2; + MethodNamePatternEntity methodNamePatternEntity1; + MethodNamePatternEntity methodNamePatternEntity2; + SpelNamePatternEntity spelNamePatternEntity1; + SpelNamePatternEntity spelNamePatternEntity2; + + @SuppressWarnings("IncorrectCreateEntity") + @Before + public void setUp() { + simpleNamePatternEntity1 = new SimpleNamePatternEntity(); + simpleNamePatternEntity1.setName("name1"); + + simpleNamePatternEntity2 = new SimpleNamePatternEntity(); + simpleNamePatternEntity2.setName(null); + + methodNamePatternEntity1 = new MethodNamePatternEntity(); + methodNamePatternEntity1.setName("name1"); + + methodNamePatternEntity2 = new MethodNamePatternEntity(); + methodNamePatternEntity2.setName(null); + + spelNamePatternEntity1 = new SpelNamePatternEntity(); + spelNamePatternEntity1.setName("name1"); + spelNamePatternEntity1.setNumber(5); + spelNamePatternEntity1.setNumber2(null); + + spelNamePatternEntity2 = new SpelNamePatternEntity(); + spelNamePatternEntity2.setName("name2"); + spelNamePatternEntity2.setNumber(null); + spelNamePatternEntity2.setNumber2(null); + } + + @Test + public void testSimpleNamePatternEntity1() { + assertEquals("name1", simpleNamePatternEntity1.getInstanceName()); + } + + @Test + public void testSimpleNamePatternEntity2() { + assertEquals("", simpleNamePatternEntity2.getInstanceName()); + } + + @Test + public void testMethodNamePatternEntity1() { + assertEquals("name1", methodNamePatternEntity1.getInstanceName()); + } + + @Test + public void testMethodNamePatternEntity2() { + assertNull(methodNamePatternEntity2.getInstanceName()); + } + + @Test + public void testComplexNamePatternEntity1() { + assertEquals("Hello, my name is name1. Sum of numbers = 5", spelNamePatternEntity1.getInstanceName()); + } + + @Test + public void testComplexNamePatternEntity2() { + assertEquals("Hello, my name is name2. Sum of numbers = 0", spelNamePatternEntity2.getInstanceName()); + } +} diff --git a/modules/core/test/com/haulmont/cuba/namepattern/NamePatternTestBean.java b/modules/core/test/com/haulmont/cuba/namepattern/NamePatternTestBean.java new file mode 100644 index 0000000000..49e94fbbf3 --- /dev/null +++ b/modules/core/test/com/haulmont/cuba/namepattern/NamePatternTestBean.java @@ -0,0 +1,31 @@ +package com.haulmont.cuba.namepattern; + +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * @author Rushan Zagidullin + * @since 17.07.2018 + */ +@Component("cuba_NamePatternTestBean") +public class NamePatternTestBean { + public int sum(Integer... values) { + return Optional.ofNullable(values) + .map(ints -> Arrays.stream(ints) + .filter(Objects::nonNull) + .mapToInt(Integer::intValue) + .sum()) + .orElse(0); + } + + public String concat(String... values) { + return Optional.ofNullable(values) + .map(strings -> Arrays.stream(strings) + .collect(Collectors.joining())) + .orElse(""); + } +} diff --git a/modules/core/test/com/haulmont/cuba/testmodel/namepattern/MethodNamePatternEntity.java b/modules/core/test/com/haulmont/cuba/testmodel/namepattern/MethodNamePatternEntity.java new file mode 100644 index 0000000000..6c388c4162 --- /dev/null +++ b/modules/core/test/com/haulmont/cuba/testmodel/namepattern/MethodNamePatternEntity.java @@ -0,0 +1,34 @@ +package com.haulmont.cuba.testmodel.namepattern; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @author Rushan Zagidullin + * @since 17.07.2018 + */ +@NamePattern("#formatName|name") +@Table(name = "TEST_METHOD_NAME_PATTERN_ENTITY") +@Entity(name = "test$MethodNamePatternEntity") +public class MethodNamePatternEntity extends StandardEntity { + private static final long serialVersionUID = -833743669993760614L; + + @Column(name = "NAME") + protected String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String formatName() { + return getName(); + } +} \ No newline at end of file diff --git a/modules/core/test/com/haulmont/cuba/testmodel/namepattern/SimpleNamePatternEntity.java b/modules/core/test/com/haulmont/cuba/testmodel/namepattern/SimpleNamePatternEntity.java new file mode 100644 index 0000000000..c463c72f47 --- /dev/null +++ b/modules/core/test/com/haulmont/cuba/testmodel/namepattern/SimpleNamePatternEntity.java @@ -0,0 +1,30 @@ +package com.haulmont.cuba.testmodel.namepattern; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @author Rushan Zagidullin + * @since 17.07.2018 + */ +@NamePattern("%s|name") +@Table(name = "TEST_SIMPLE_NAME_PATTERN_ENTITY") +@Entity(name = "test$SimpleNamePatternEntity") +public class SimpleNamePatternEntity extends StandardEntity { + private static final long serialVersionUID = -833743669993760614L; + + @Column(name = "NAME") + protected String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/modules/core/test/com/haulmont/cuba/testmodel/namepattern/SpelNamePatternEntity.java b/modules/core/test/com/haulmont/cuba/testmodel/namepattern/SpelNamePatternEntity.java new file mode 100644 index 0000000000..1a81f09d3e --- /dev/null +++ b/modules/core/test/com/haulmont/cuba/testmodel/namepattern/SpelNamePatternEntity.java @@ -0,0 +1,52 @@ +package com.haulmont.cuba.testmodel.namepattern; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @author Rushan Zagidullin + * @since 17.07.2018 + */ +@NamePattern("#{@cuba_NamePatternTestBean.concat('Hello, my name is ', name, '. Sum of numbers = ', @cuba_NamePatternTestBean.sum(number, number2))}|name") +@Table(name = "TEST_SPEL_NAME_PATTERN_ENTITY") +@Entity(name = "test$SpelNamePatternEntity") +public class SpelNamePatternEntity extends StandardEntity { + private static final long serialVersionUID = -833743669993760614L; + + @Column(name = "NAME") + protected String name; + + @Column(name = "NUMBER") + protected Integer number; + + @Column(name = "NUMBER_2") + protected Integer number2; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } + + public Integer getNumber2() { + return number2; + } + + public void setNumber2(Integer number2) { + this.number2 = number2; + } +} \ No newline at end of file diff --git a/modules/core/test/cuba-test-persistence.xml b/modules/core/test/cuba-test-persistence.xml index b79535257d..6dce56295e 100644 --- a/modules/core/test/cuba-test-persistence.xml +++ b/modules/core/test/cuba-test-persistence.xml @@ -91,5 +91,9 @@ com.haulmont.cuba.testmodel.jpa_cascade.JpaCascadeItem com.haulmont.cuba.testmodel.not_persistent.CustomerWithNonPersistentRef + + com.haulmont.cuba.testmodel.namepattern.MethodNamePatternEntity + com.haulmont.cuba.testmodel.namepattern.SimpleNamePatternEntity + com.haulmont.cuba.testmodel.namepattern.SpelNamePatternEntity \ No newline at end of file diff --git a/modules/global/src/com/haulmont/chile/core/model/utils/InstanceUtils.java b/modules/global/src/com/haulmont/chile/core/model/utils/InstanceUtils.java index e681a77b34..ea2190a709 100644 --- a/modules/global/src/com/haulmont/chile/core/model/utils/InstanceUtils.java +++ b/modules/global/src/com/haulmont/chile/core/model/utils/InstanceUtils.java @@ -25,8 +25,16 @@ import com.haulmont.cuba.core.global.DevelopmentException; import com.haulmont.cuba.core.global.Messages; import com.haulmont.cuba.core.global.MetadataTools; +import com.haulmont.cuba.core.sys.AppContext; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.expression.BeanResolver; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.common.TemplateParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; import javax.annotation.Nullable; import java.lang.reflect.InvocationTargetException; @@ -226,6 +234,9 @@ public static String getInstanceName(Instance instance) { throw new RuntimeException("Error getting instance name", e); } } + if (rec.isSpEL) { + return evaluateSpEL(instance, rec.format); + } // lazy initialized messages, used only for enum values Messages messages = null; @@ -252,6 +263,15 @@ public static String getInstanceName(Instance instance) { } } + public static String evaluateSpEL(Instance instance, String format) { + ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(instance); + BeanResolver beanResolver = new BeanFactoryResolver(AppContext.getApplicationContext()); + evaluationContext.setBeanResolver(beanResolver); + Expression expression = parser.parseExpression(format, new TemplateParserContext()); + return expression.getValue(evaluationContext, String.class); + } + /** * Parse a name pattern defined by {@link NamePattern} annotation. * @param metaClass entity meta-class @@ -272,10 +292,13 @@ public static NamePatternRec parseNamePattern(MetaClass metaClass) { String format = StringUtils.substring(pattern, 0, pos); String trimmedFormat = format.trim(); - String methodName = trimmedFormat.startsWith("#") ? trimmedFormat.substring(1) : null; + boolean isSpEL = trimmedFormat.startsWith("#{"); + String methodName = trimmedFormat.startsWith("#") && !isSpEL ? + trimmedFormat.substring(1) : + null; String fieldsStr = StringUtils.substring(pattern, pos + 1); String[] fields = INSTANCE_NAME_SPLIT_PATTERN.split(fieldsStr); - return new NamePatternRec(format, methodName, fields); + return new NamePatternRec(format, methodName, fields, isSpEL); } public static class NamePatternRec { @@ -291,11 +314,16 @@ public static class NamePatternRec { * Array of property names */ public final String[] fields; + /** + * Is name pattern described as SpEL + */ + public final boolean isSpEL; - public NamePatternRec(String format, String methodName, String[] fields) { + public NamePatternRec(String format, String methodName, String[] fields, boolean isSpEL) { this.fields = fields; this.format = format; this.methodName = methodName; + this.isSpEL = isSpEL; } }