diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/AbstractCachingScriptEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/AbstractCachingScriptEvaluator.java index 43f52f6fbcd..8aec070b2a5 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/AbstractCachingScriptEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/AbstractCachingScriptEvaluator.java @@ -11,6 +11,9 @@ import java.util.List; import javax.xml.namespace.QName; +import com.evolveum.midpoint.util.DOMUtil; +import com.evolveum.midpoint.util.QNameUtil; + import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.common.LocalizationService; @@ -90,25 +93,7 @@ public List evaluate(ScriptExpressionEvaluationCont return evalPrismValues; } - QName xsdReturnType = context.getOutputDefinition().getTypeName(); - - Class javaReturnType = XsdTypeMapper.toJavaType(xsdReturnType); - if (javaReturnType == null) { - javaReturnType = getPrismContext().getSchemaRegistry().getCompileTimeClass(xsdReturnType); - } - - if (javaReturnType == null && (context.getOutputDefinition() instanceof PrismContainerDefinition)) { - // This is the case when we need a container, but we do not have compile-time class for that - // E.g. this may be container in object extension (MID-5080) - javaReturnType = (Class) PrismContainerValue.class; - } - - if (javaReturnType == null) { - // TODO quick and dirty hack - because this could be because of enums defined in schema extension (MID-2399) - // ...and enums (xsd:simpleType) are not parsed into ComplexTypeDefinitions - javaReturnType = (Class) String.class; - } - LOGGER.trace("expected return type: XSD={}, Java={}", xsdReturnType, javaReturnType); + Class javaReturnType = determineJavaReturnType(context); List values = new ArrayList<>(); @@ -132,6 +117,36 @@ public List evaluate(ScriptExpressionEvaluationCont return values; } + @NotNull + private Class determineJavaReturnType(ScriptExpressionEvaluationContext context) { + QName xsdReturnType = context.getOutputDefinition().getTypeName(); + + // Ugly hack. Indented to allow xsd:anyType return type, see MID-6775. + if (QNameUtil.match(xsdReturnType, DOMUtil.XSD_ANYTYPE)) { + //noinspection unchecked + return (Class) Object.class; + } + + Class javaReturnType = XsdTypeMapper.toJavaType(xsdReturnType); + if (javaReturnType == null) { + javaReturnType = getPrismContext().getSchemaRegistry().getCompileTimeClass(xsdReturnType); + } + + if (javaReturnType == null && (context.getOutputDefinition() instanceof PrismContainerDefinition)) { + // This is the case when we need a container, but we do not have compile-time class for that + // E.g. this may be container in object extension (MID-5080) + javaReturnType = (Class) PrismContainerValue.class; + } + + if (javaReturnType == null) { + // TODO quick and dirty hack - because this could be because of enums defined in schema extension (MID-2399) + // ...and enums (xsd:simpleType) are not parsed into ComplexTypeDefinitions + javaReturnType = (Class) String.class; + } + LOGGER.trace("expected return type: XSD={}, Java={}", xsdReturnType, javaReturnType); + return javaReturnType; + } + private C getCompiledScript(String codeString, ScriptExpressionEvaluationContext context) throws ExpressionEvaluationException, SecurityViolationException { C compiledScript = scriptCache.getCode(context.getExpressionProfile(), codeString); if (compiledScript != null) { diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/expr/TestModelExpressions.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/expr/TestModelExpressions.java index e8509da4f04..feec6ff3087 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/expr/TestModelExpressions.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/expr/TestModelExpressions.java @@ -307,8 +307,25 @@ public void testCustomFunctionWrongParameter() throws Exception { } } + @Test + public void testCustomFunctionUntyped() throws Exception { + PrismContainer customPc = createCustomContainer(); + PrismContainerValue customPcv = createCustomValue(); + + VariablesMap variables = VariablesMap.create(prismContext, + "var1", customPc.clone().getValues(), customPc.getDefinition(), + "var2", customPcv.clone(), customPcv.getDefinition()); + + assertExecuteScriptExpressionString(variables, "s-1"); + } + @NotNull private PrismContainerValue createCustomValue() throws SchemaException { + return createCustomContainer().getValue(); + } + + @NotNull + private PrismContainer createCustomContainer() throws SchemaException { PrismContainerDefinition customDef = prismContext.getSchemaRegistry().findContainerDefinitionByElementName(CUSTOM); PrismContainer customPc = customDef.instantiate(); @@ -320,7 +337,7 @@ private PrismContainerValue createCustomValue() throws SchemaExce customPcv.add(stringPp); customPcv.add(intPp); - return customPcv; + return customPc; } private void assertExecuteScriptExpressionString( @@ -335,7 +352,8 @@ private String executeScriptExpressionString(VariablesMap variables) throws SecurityViolationException, ExpressionEvaluationException, SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, IOException { // GIVEN - OperationResult result = createOperationResult(); + Task task = getTestTask(); + OperationResult result = task.getResult(); String shortTestName = getTestNameShort(); ScriptExpressionEvaluatorType scriptType = parseScriptType("expression-" + shortTestName + ".xml"); @@ -374,7 +392,8 @@ private String executeScriptExpressionString(VariablesMap variables) @SuppressWarnings("SameParameterValue") private List> evaluate(ScriptExpression scriptExpression, VariablesMap variables, boolean useNew, - String contextDescription, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { + String contextDescription, Task task, OperationResult result) throws ExpressionEvaluationException, + ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { if (task == null) { task = taskManager.createTaskInstance(); } @@ -394,5 +413,4 @@ private List> evaluate(ScriptExpression scriptExpressi ModelExpressionThreadLocalHolder.popExpressionEnvironment(); } } - } diff --git a/model/model-impl/src/test/resources/expr/expression-testCustomFunctionUntyped.xml b/model/model-impl/src/test/resources/expr/expression-testCustomFunctionUntyped.xml new file mode 100644 index 00000000000..0e4f5abb256 --- /dev/null +++ b/model/model-impl/src/test/resources/expr/expression-testCustomFunctionUntyped.xml @@ -0,0 +1,17 @@ + + + + diff --git a/model/model-impl/src/test/resources/expr/function-library.xml b/model/model-impl/src/test/resources/expr/function-library.xml index 8284839e944..e4caeb9bdf1 100644 --- a/model/model-impl/src/test/resources/expr/function-library.xml +++ b/model/model-impl/src/test/resources/expr/function-library.xml @@ -35,4 +35,28 @@ + + + untyped + + container + + xsd:anyType + + + containerValue + xsd:anyType + + xsd:anyType + +