class ShouldHaveExactlyTypes extends BasicErrorMessageFactory {

  public static ErrorMessageFactory shouldHaveTypes(Object actual, Iterable<Class<?>> expectedTypes,
                                                    Iterable<Class<?>> expectedTypesNotFoundInActual,
                                                    Iterable<Class<?>> actualTypesNotExpected) {<FILL_FUNCTION_BODY>}

  public static ErrorMessageFactory elementsTypesDifferAtIndex(Object actualElement, Class<?> expectedElement,
                                                               int indexOfDifference) {
    return new ShouldHaveExactlyTypes(actualElement, expectedElement, indexOfDifference);
  }

  private ShouldHaveExactlyTypes(Object actual, Iterable<Class<?>> expected, Iterable<Class<?>> expectedTypesNotFoundInActual,
                                 Iterable<Class<?>> actualTypesNotExpected) {
    super("%n" +
          "Expecting actual elements:%n" +
          "  %s%n" +
          "to have the following types (in this order):%n" +
          "  %s%n" +
          "but there were no actual elements with these types:%n" +
          "  %s%n" +
          "and these actual elements types were not expected:%n" +
          "  %s",
          actual, expected, expectedTypesNotFoundInActual, actualTypesNotExpected);
  }

  private ShouldHaveExactlyTypes(Object actual, Iterable<Class<?>> expected, Iterable<Class<?>> diff,
                                 boolean expectedTypesNotFoundInActualOnly) {
    // @format:off
    super("%n" +
          "Expecting actual elements:%n" +
          "  %s%n" +
          "to have the following types (in this order):%n" +
          "  %s%n" +
          (expectedTypesNotFoundInActualOnly
              ? "but there were no actual elements with these types"
              : "but these actual elements types were not expected") + ":%n" +
          "  %s",
          actual, expected, diff);
    // @format:on
  }

  private ShouldHaveExactlyTypes(Object actualElement, Class<?> expectedType, int indexOfDifference) {
    super("%n" +
          "actual element at index %s does not have the expected type, element was:%s%n" +
          "actual element type: %s%n" +
          "expected type      : %s",
          indexOfDifference, actualElement, actualElement.getClass(), expectedType);
  }

}

    if (!isNullOrEmpty(actualTypesNotExpected) && !isNullOrEmpty(expectedTypesNotFoundInActual)) {
      return new ShouldHaveExactlyTypes(actual, expectedTypes, expectedTypesNotFoundInActual, actualTypesNotExpected);
    }
    // empty actualTypesNotExpected means expectedTypesNotFoundInActual is not empty
    boolean expectedTypesNotFoundInActualOnly = isNullOrEmpty(actualTypesNotExpected);
    Iterable<Class<?>> diff = expectedTypesNotFoundInActualOnly ? expectedTypesNotFoundInActual : actualTypesNotExpected;
    return new ShouldHaveExactlyTypes(actual, expectedTypes, diff, expectedTypesNotFoundInActualOnly);
  
<methods>public transient void <init>(java.lang.String, java.lang.Object[]) ,public java.lang.String create(org.assertj.core.description.Description, org.assertj.core.presentation.Representation) ,public java.lang.String create(org.assertj.core.description.Description) ,public java.lang.String create() ,public boolean equals(java.lang.Object) ,public int hashCode() ,public java.lang.String toString() <variables>protected final non-sealed java.lang.Object[] arguments,protected final non-sealed java.lang.String format,org.assertj.core.error.MessageFormatter formatter