private <T> QName determineRerturnType(
      Class<T> type,
      ScriptExpressionEvaluatorType expressionType,
      ItemDefinition outputDefinition,
      ScriptExpressionReturnTypeType suggestedReturnType)
      throws ExpressionEvaluationException {

    if (expressionType.getReturnType() == ScriptExpressionReturnTypeType.LIST
        || suggestedReturnType == ScriptExpressionReturnTypeType.LIST) {
      return XPathConstants.NODESET;
    }

    if (expressionType.getReturnType() == ScriptExpressionReturnTypeType.SCALAR) {
      return toXPathReturnType(outputDefinition.getTypeName());
    }

    if (suggestedReturnType == ScriptExpressionReturnTypeType.LIST) {
      return XPathConstants.NODESET;
    }

    if (suggestedReturnType == ScriptExpressionReturnTypeType.SCALAR) {
      return toXPathReturnType(outputDefinition.getTypeName());
    }

    if (outputDefinition.isMultiValue()) {
      return XPathConstants.NODESET;
    } else {
      return toXPathReturnType(outputDefinition.getTypeName());
    }
  }
  public <IV extends PrismValue, ID extends ItemDefinition> XNode serializeItem(
      Item<IV, ID> item, SerializationContext ctx) throws SchemaException {
    ListXNode xlist = new ListXNode();
    List<IV> values = item.getValues();
    ItemDefinition definition = item.getDefinition();

    for (IV val : values) {
      XNode xsubnode = serializeItemValue(val, definition, ctx);
      xlist.add(xsubnode);
    }

    boolean asList;
    if (definition != null) {
      asList = definition.isMultiValue();
    } else {
      asList = values.size() > 1;
    }

    if (asList) {
      return xlist;
    } else {
      if (xlist.isEmpty()) {
        return null;
      } else {
        return xlist.iterator().next();
      }
    }
  }
  @Override
  public <T, V extends PrismValue> List<V> evaluate(
      ScriptExpressionEvaluatorType expressionType,
      ExpressionVariables variables,
      ItemDefinition outputDefinition,
      ScriptExpressionReturnTypeType suggestedReturnType,
      ObjectResolver objectResolver,
      Collection<FunctionLibrary> functions,
      String contextDescription,
      Task task,
      OperationResult result)
      throws ExpressionEvaluationException, ObjectNotFoundException, ExpressionSyntaxException {

    String codeString = expressionType.getCode();
    if (codeString == null) {
      throw new ExpressionEvaluationException("No script code in " + contextDescription);
    }

    Class<T> type = null;

    if (outputDefinition != null) {
      QName xsdReturnType = outputDefinition.getTypeName();
      type = XsdTypeMapper.toJavaType(xsdReturnType); // may return null if unknown
    }
    if (type == null) {
      type =
          (Class<T>)
              Element
                  .class; // actually, if outputDefinition is null, the return value is of no
                          // interest for us
    }

    QName returnType =
        determineRerturnType(type, expressionType, outputDefinition, suggestedReturnType);

    Object evaluatedExpression =
        evaluate(
            returnType,
            codeString,
            variables,
            objectResolver,
            functions,
            contextDescription,
            result);

    List<V> propertyValues;

    boolean scalar = !outputDefinition.isMultiValue();
    if (expressionType.getReturnType() != null) {
      scalar = isScalar(expressionType.getReturnType());
    } else if (suggestedReturnType != null) {
      scalar = isScalar(suggestedReturnType);
    }

    if (scalar) {
      if (evaluatedExpression instanceof NodeList) {
        NodeList evaluatedExpressionNodeList = (NodeList) evaluatedExpression;
        if (evaluatedExpressionNodeList.getLength() > 1) {
          throw new ExpressionEvaluationException(
              "Expected scalar expression result but got a list result with "
                  + evaluatedExpressionNodeList.getLength()
                  + " elements in "
                  + contextDescription);
        }
        if (evaluatedExpressionNodeList.getLength() == 0) {
          evaluatedExpression = null;
        } else {
          evaluatedExpression = evaluatedExpressionNodeList.item(0);
        }
      }
      propertyValues = new ArrayList<V>(1);
      V pval = convertScalar(type, returnType, evaluatedExpression, contextDescription);
      if (pval instanceof PrismPropertyValue
          && !isNothing(((PrismPropertyValue<T>) pval).getValue())) {
        propertyValues.add(pval);
      }
    } else {
      if (!(evaluatedExpression instanceof NodeList)) {
        throw new IllegalStateException(
            "The expression "
                + contextDescription
                + " resulted in "
                + evaluatedExpression.getClass().getName()
                + " while exprecting NodeList in "
                + contextDescription);
      }
      propertyValues = convertList(type, (NodeList) evaluatedExpression, contextDescription);
    }

    return (List<V>) PrismValue.cloneCollection(propertyValues);
  }