@Test
  public void discoversBoundTypeForSpecialization() {

    TypeInformation<SpecialGenericTypeWithBound> information =
        ClassTypeInformation.from(SpecialGenericTypeWithBound.class);
    assertEquals(SpecialPerson.class, information.getProperty("person").getType());
  }
  @Test
  public void returnsComponentTypeForMultiDimensionalArrayCorrectly() {

    TypeInformation<?> information = from(String[][].class);
    assertThat(information.getType(), is((Object) String[][].class));
    assertThat(information.getComponentType().getType(), is((Object) String[].class));
    assertThat(information.getActualType().getActualType().getType(), is((Object) String.class));
  }
  @Test
  @SuppressWarnings("rawtypes")
  public void discoversBoundType() {

    TypeInformation<GenericTypeWithBound> information =
        ClassTypeInformation.from(GenericTypeWithBound.class);
    assertEquals(Person.class, information.getProperty("person").getType());
  }
  @Test
  @SuppressWarnings("rawtypes")
  public void discoversBoundTypeForNested() {

    TypeInformation<AnotherGenericType> information =
        ClassTypeInformation.from(AnotherGenericType.class);
    assertEquals(GenericTypeWithBound.class, information.getProperty("nested").getType());
    assertEquals(Person.class, information.getProperty("nested.person").getType());
  }
  @Test
  public void typeInfoDoesNotEqualForGenericTypesWithDifferentParent() {

    TypeInformation<ConcreteWrapper> first = ClassTypeInformation.from(ConcreteWrapper.class);
    TypeInformation<AnotherConcreteWrapper> second =
        ClassTypeInformation.from(AnotherConcreteWrapper.class);

    assertFalse(first.getProperty("wrapped").equals(second.getProperty("wrapped")));
  }
  /** @see DATACMNS-309 */
  @Test
  @SuppressWarnings("rawtypes")
  public void findsGetterOnInterface() {

    TypeInformation<Product> information = from(Product.class);
    TypeInformation<?> categoryIdInfo = information.getProperty("category.id");

    assertThat(categoryIdInfo, is(notNullValue()));
    assertThat(categoryIdInfo, is((TypeInformation) from(Long.class)));
  }
  @Test
  public void resolvesNestedInheritedTypeParameters() {

    TypeInformation<SecondExtension> information = ClassTypeInformation.from(SecondExtension.class);
    TypeInformation<?> superTypeInformation = information.getSuperTypeInformation(Base.class);

    List<TypeInformation<?>> parameters = superTypeInformation.getTypeArguments();
    assertThat(parameters, hasSize(1));
    assertThat(parameters.get(0).getType(), is((Object) String.class));
  }
  @Test
  public void discoveresMethodParameterTypesCorrectly() throws Exception {

    TypeInformation<SecondExtension> information = ClassTypeInformation.from(SecondExtension.class);
    Method method = SecondExtension.class.getMethod("foo", Base.class);
    List<TypeInformation<?>> informations = information.getParameterTypes(method);
    TypeInformation<?> returnTypeInformation = information.getReturnType(method);

    assertThat(informations, hasSize(1));
    assertThat(informations.get(0).getType(), is((Object) Base.class));
    assertThat(informations.get(0), is((Object) returnTypeInformation));
  }
  @Test
  public void resolvesTypeParametersCorrectly() {

    TypeInformation<ConcreteType> information = ClassTypeInformation.from(ConcreteType.class);
    TypeInformation<?> superTypeInformation =
        information.getSuperTypeInformation(GenericType.class);

    List<TypeInformation<?>> parameters = superTypeInformation.getTypeArguments();
    assertThat(parameters, hasSize(2));
    assertThat(parameters.get(0).getType(), is((Object) String.class));
    assertThat(parameters.get(1).getType(), is((Object) Object.class));
  }
  @Test
  public void discoversTypeForNestedGenericField() {

    TypeInformation<ConcreteWrapper> discoverer = ClassTypeInformation.from(ConcreteWrapper.class);
    assertEquals(ConcreteWrapper.class, discoverer.getType());
    TypeInformation<?> wrapper = discoverer.getProperty("wrapped");
    assertEquals(GenericType.class, wrapper.getType());
    TypeInformation<?> content = wrapper.getProperty("content");

    assertEquals(String.class, content.getType());
    assertEquals(String.class, discoverer.getProperty("wrapped").getProperty("content").getType());
    assertEquals(String.class, discoverer.getProperty("wrapped.content").getType());
  }
  @Test
  public void discoversMapValueType() {

    TypeInformation<StringMapContainer> information =
        ClassTypeInformation.from(StringMapContainer.class);
    TypeInformation<?> genericMap = information.getProperty("genericMap");
    assertEquals(Map.class, genericMap.getType());
    assertEquals(String.class, genericMap.getMapValueType().getType());

    TypeInformation<?> map = information.getProperty("map");
    assertEquals(Map.class, map.getType());
    assertEquals(Calendar.class, map.getMapValueType().getType());
  }
  @Test
  public void discoversTypeForSimpleGenericField() {

    TypeInformation<ConcreteType> discoverer = ClassTypeInformation.from(ConcreteType.class);
    assertEquals(ConcreteType.class, discoverer.getType());
    TypeInformation<?> content = discoverer.getProperty("content");
    assertEquals(String.class, content.getType());
    assertNull(content.getComponentType());
    assertNull(content.getMapValueType());
  }
  @Test
  public void discoversImplementationBindingCorrectlyForString() throws Exception {

    TypeInformation<TypedClient> information = from(TypedClient.class);
    Method method = TypedClient.class.getMethod("stringMethod", GenericInterface.class);

    TypeInformation<?> parameterType = information.getParameterTypes(method).get(0);

    TypeInformation<StringImplementation> stringInfo = from(StringImplementation.class);
    assertThat(parameterType.isAssignableFrom(stringInfo), is(true));
    assertThat(
        stringInfo.getSuperTypeInformation(GenericInterface.class), is((Object) parameterType));
    assertThat(parameterType.isAssignableFrom(from(LongImplementation.class)), is(false));
    assertThat(
        parameterType.isAssignableFrom(
            from(StringImplementation.class).getSuperTypeInformation(GenericInterface.class)),
        is(true));
  }
  @Test
  public void handlesPropertyFieldMismatchCorrectly() {

    TypeInformation<PropertyGetter> from = ClassTypeInformation.from(PropertyGetter.class);

    TypeInformation<?> property = from.getProperty("_name");
    assertThat(property, is(notNullValue()));
    assertThat(property.getType(), is(typeCompatibleWith(String.class)));

    property = from.getProperty("name");
    assertThat(property, is(notNullValue()));
    assertThat(property.getType(), is(typeCompatibleWith(byte[].class)));
  }
  @Test
  public void discoversArraysAndCollections() {
    TypeInformation<StringCollectionContainer> information =
        ClassTypeInformation.from(StringCollectionContainer.class);

    TypeInformation<?> property = information.getProperty("array");
    assertEquals(property.getComponentType().getType(), String.class);

    Class<?> type = property.getType();
    assertEquals(String[].class, type);
    assertThat(type.isArray(), is(true));

    property = information.getProperty("foo");
    assertEquals(Collection[].class, property.getType());
    assertEquals(Collection.class, property.getComponentType().getType());
    assertEquals(String.class, property.getComponentType().getComponentType().getType());

    property = information.getProperty("rawSet");
    assertEquals(Set.class, property.getType());
    assertEquals(Object.class, property.getComponentType().getType());
    assertNull(property.getMapValueType());
  }
  /** @see DATACMNS-39 */
  @Test
  public void resolvesWildCardTypeCorrectly() {

    TypeInformation<ClassWithWildCardBound> information =
        ClassTypeInformation.from(ClassWithWildCardBound.class);

    TypeInformation<?> property = information.getProperty("wildcard");
    assertThat(property.isCollectionLike(), is(true));
    assertThat(property.getComponentType().getType(), is(typeCompatibleWith(String.class)));

    property = information.getProperty("complexWildcard");
    assertThat(property.isCollectionLike(), is(true));

    TypeInformation<?> component = property.getComponentType();
    assertThat(component.isCollectionLike(), is(true));
    assertThat(component.getComponentType().getType(), is(typeCompatibleWith(String.class)));
  }