private static Class findInterfaceImplementation(
      Map<String, Object> properties, Class topClass, EngineImportService engineImportService)
      throws ExprValidationException {
    String message = "Failed to find implementation for interface " + topClass.getName();

    // Allow to populate the special "class" field
    if (!properties.containsKey(CLASS_PROPERTY_NAME)) {
      throw new ExprValidationException(
          message
              + ", for interfaces please specified the '"
              + CLASS_PROPERTY_NAME
              + "' field that provides the class name either as a simple class name or fully qualified");
    }

    Class clazz = null;
    String className = (String) properties.get(CLASS_PROPERTY_NAME);
    try {
      clazz = JavaClassHelper.getClassForName(className);
    } catch (ClassNotFoundException e) {

      if (!className.contains(".")) {
        className = topClass.getPackage().getName() + "." + className;
        try {
          clazz = JavaClassHelper.getClassForName(className);
        } catch (ClassNotFoundException ex) {
        }
      }

      if (clazz == null) {
        throw new ExprValidationPropertyException(
            message + ", could not find class by name '" + className + "'");
      }
    }

    if (!JavaClassHelper.isSubclassOrImplementsInterface(clazz, topClass)) {
      throw new ExprValidationException(
          message
              + ", class "
              + JavaClassHelper.getClassNameFullyQualPretty(clazz)
              + " does not implement the interface");
    }
    return clazz;
  }
  public static void populateObject(
      String operatorName,
      int operatorNum,
      String dataFlowName,
      Map<String, Object> objectProperties,
      Object top,
      EngineImportService engineImportService,
      EPDataFlowOperatorParameterProvider optionalParameterProvider,
      Map<String, Object> optionalParameterURIs)
      throws ExprValidationException {
    Class applicableClass = top.getClass();
    Set<WriteablePropertyDescriptor> writables =
        PropertyHelper.getWritableProperties(applicableClass);
    Set<Field> annotatedFields =
        JavaClassHelper.findAnnotatedFields(top.getClass(), DataFlowOpParameter.class);
    Set<Method> annotatedMethods =
        JavaClassHelper.findAnnotatedMethods(top.getClass(), DataFlowOpParameter.class);

    // find catch-all methods
    Set<Method> catchAllMethods = new LinkedHashSet<Method>();
    if (annotatedMethods != null) {
      for (Method method : annotatedMethods) {
        DataFlowOpParameter anno =
            (DataFlowOpParameter)
                JavaClassHelper.getAnnotations(
                        DataFlowOpParameter.class, method.getDeclaredAnnotations())
                    .get(0);
        if (anno.all()) {
          if (method.getParameterTypes().length == 2
              && method.getParameterTypes()[0] == String.class
              && method.getParameterTypes()[1] == Object.class) {
            catchAllMethods.add(method);
            continue;
          }
          throw new ExprValidationException("Invalid annotation for catch-call");
        }
      }
    }

    // map provided values
    for (Map.Entry<String, Object> property : objectProperties.entrySet()) {
      boolean found = false;
      String propertyName = property.getKey();

      // invoke catch-all setters
      for (Method method : catchAllMethods) {
        try {
          method.invoke(top, new Object[] {propertyName, property.getValue()});
        } catch (IllegalAccessException e) {
          throw new ExprValidationException(
              "Illegal access invoking method for property '"
                  + propertyName
                  + "' for class "
                  + applicableClass.getName()
                  + " method "
                  + method.getName(),
              e);
        } catch (InvocationTargetException e) {
          throw new ExprValidationException(
              "Exception invoking method for property '"
                  + propertyName
                  + "' for class "
                  + applicableClass.getName()
                  + " method "
                  + method.getName()
                  + ": "
                  + e.getTargetException().getMessage(),
              e);
        }
        found = true;
      }

      if (propertyName.toLowerCase().equals(CLASS_PROPERTY_NAME)) {
        continue;
      }

      // use the writeable property descriptor (appropriate setter method) from writing the property
      WriteablePropertyDescriptor descriptor =
          findDescriptor(applicableClass, propertyName, writables);
      if (descriptor != null) {
        Object coerceProperty =
            coerceProperty(
                propertyName,
                applicableClass,
                property.getValue(),
                descriptor.getType(),
                engineImportService,
                false);

        try {
          descriptor.getWriteMethod().invoke(top, new Object[] {coerceProperty});
        } catch (IllegalArgumentException e) {
          throw new ExprValidationException(
              "Illegal argument invoking setter method for property '"
                  + propertyName
                  + "' for class "
                  + applicableClass.getName()
                  + " method "
                  + descriptor.getWriteMethod().getName()
                  + " provided value "
                  + coerceProperty,
              e);
        } catch (IllegalAccessException e) {
          throw new ExprValidationException(
              "Illegal access invoking setter method for property '"
                  + propertyName
                  + "' for class "
                  + applicableClass.getName()
                  + " method "
                  + descriptor.getWriteMethod().getName(),
              e);
        } catch (InvocationTargetException e) {
          throw new ExprValidationException(
              "Exception invoking setter method for property '"
                  + propertyName
                  + "' for class "
                  + applicableClass.getName()
                  + " method "
                  + descriptor.getWriteMethod().getName()
                  + ": "
                  + e.getTargetException().getMessage(),
              e);
        }
        continue;
      }

      // find the field annotated with {@link @GraphOpProperty}
      for (Field annotatedField : annotatedFields) {
        DataFlowOpParameter anno =
            (DataFlowOpParameter)
                JavaClassHelper.getAnnotations(
                        DataFlowOpParameter.class, annotatedField.getDeclaredAnnotations())
                    .get(0);
        if (anno.name().equals(propertyName) || annotatedField.getName().equals(propertyName)) {
          Object coerceProperty =
              coerceProperty(
                  propertyName,
                  applicableClass,
                  property.getValue(),
                  annotatedField.getType(),
                  engineImportService,
                  true);
          try {
            annotatedField.setAccessible(true);
            annotatedField.set(top, coerceProperty);
          } catch (Exception e) {
            throw new ExprValidationException(
                "Failed to set field '" + annotatedField.getName() + "': " + e.getMessage(), e);
          }
          found = true;
          break;
        }
      }
      if (found) {
        continue;
      }

      throw new ExprValidationException(
          "Failed to find writable property '"
              + propertyName
              + "' for class "
              + applicableClass.getName());
    }

    // second pass: if a parameter URI - value pairs were provided, check that
    if (optionalParameterURIs != null) {
      for (Field annotatedField : annotatedFields) {
        try {
          annotatedField.setAccessible(true);
          String uri = operatorName + "/" + annotatedField.getName();
          if (optionalParameterURIs.containsKey(uri)) {
            Object value = optionalParameterURIs.get(uri);
            annotatedField.set(top, value);
            if (log.isDebugEnabled()) {
              log.debug(
                  "Found parameter '"
                      + uri
                      + "' for data flow "
                      + dataFlowName
                      + " setting "
                      + value);
            }
          } else {
            if (log.isDebugEnabled()) {
              log.debug("Not found parameter '" + uri + "' for data flow " + dataFlowName);
            }
          }
        } catch (Exception e) {
          throw new ExprValidationException(
              "Failed to set field '" + annotatedField.getName() + "': " + e.getMessage(), e);
        }
      }
    }

    // third pass: if a parameter provider is provided, use that
    if (optionalParameterProvider != null) {
      for (Field annotatedField : annotatedFields) {
        try {
          annotatedField.setAccessible(true);
          Object provided = annotatedField.get(top);
          Object value =
              optionalParameterProvider.provide(
                  new EPDataFlowOperatorParameterProviderContext(
                      operatorName,
                      annotatedField.getName(),
                      top,
                      operatorNum,
                      provided,
                      dataFlowName));
          if (value != null) {
            annotatedField.set(top, value);
          }
        } catch (Exception e) {
          throw new ExprValidationException(
              "Failed to set field '" + annotatedField.getName() + "': " + e.getMessage(), e);
        }
      }
    }
  }
  private static Object coerceProperty(
      String propertyName,
      Class containingType,
      Object value,
      Class type,
      EngineImportService engineImportService,
      boolean forceNumeric)
      throws ExprValidationException {
    if (value instanceof ExprNode && type != ExprNode.class) {
      if (value instanceof ExprIdentNode) {
        ExprIdentNode identNode = (ExprIdentNode) value;
        Property prop;
        try {
          prop = PropertyParser.parse(identNode.getFullUnresolvedName(), false);
        } catch (Exception ex) {
          throw new ExprValidationException(
              "Failed to parse property '" + identNode.getFullUnresolvedName() + "'");
        }
        if (!(prop instanceof MappedProperty)) {
          throw new ExprValidationException(
              "Unrecognized property '" + identNode.getFullUnresolvedName() + "'");
        }
        MappedProperty mappedProperty = (MappedProperty) prop;
        if (mappedProperty.getPropertyNameAtomic().toLowerCase().equals(SYSTEM_PROPETIES_NAME)) {
          return System.getProperty(mappedProperty.getKey());
        }
      } else {
        ExprNode exprNode = (ExprNode) value;
        ExprEvaluator evaluator = exprNode.getExprEvaluator();
        if (evaluator == null) {
          throw new ExprValidationException(
              "Failed to evaluate expression '" + exprNode.toExpressionString() + "'");
        }
        value = evaluator.evaluate(null, true, null);
      }
    }

    if (value == null) {
      return null;
    }
    if (value.getClass() == type) {
      return value;
    }
    if (JavaClassHelper.isAssignmentCompatible(value.getClass(), type)) {
      if (forceNumeric
          && JavaClassHelper.getBoxedType(value.getClass()) != JavaClassHelper.getBoxedType(type)
          && JavaClassHelper.isNumeric(type)
          && JavaClassHelper.isNumeric(value.getClass())) {
        value = JavaClassHelper.coerceBoxed((Number) value, JavaClassHelper.getBoxedType(type));
      }
      return value;
    }
    if (JavaClassHelper.isSubclassOrImplementsInterface(value.getClass(), type)) {
      return value;
    }
    if (type.isArray()) {
      if (!(value instanceof Collection)) {
        throw new ExprValidationException(
            "Property '"
                + propertyName
                + "' of class "
                + JavaClassHelper.getClassNameFullyQualPretty(containingType)
                + " expects an array but receives a value of type "
                + value.getClass().getName());
      }
      Object[] items = ((Collection) value).toArray();
      Object coercedArray = Array.newInstance(type.getComponentType(), items.length);
      for (int i = 0; i < items.length; i++) {
        Object coercedValue =
            coerceProperty(
                propertyName + " (array element)",
                type,
                items[i],
                type.getComponentType(),
                engineImportService,
                false);
        Array.set(coercedArray, i, coercedValue);
      }
      return coercedArray;
    }
    if (!(value instanceof Map)) {
      throw new ExprValidationException(
          "Property '"
              + propertyName
              + "' of class "
              + JavaClassHelper.getClassNameFullyQualPretty(containingType)
              + " expects an "
              + JavaClassHelper.getClassNameFullyQualPretty(type)
              + " but receives a value of type "
              + value.getClass().getName());
    }
    Map<String, Object> props = (Map<String, Object>) value;
    return instantiatePopulateObject(props, type, engineImportService);
  }