/**
   * Creates a new {@link BeanMetaDataImpl}
   *
   * @param beanClass The Java type represented by this meta data object.
   * @param defaultGroupSequence The default group sequence.
   * @param defaultGroupSequenceProvider The default group sequence provider if set.
   * @param constraintMetaDataSet All constraint meta data relating to the represented type.
   */
  public BeanMetaDataImpl(
      Class<T> beanClass,
      List<Class<?>> defaultGroupSequence,
      DefaultGroupSequenceProvider<? super T> defaultGroupSequenceProvider,
      Set<ConstraintMetaData> constraintMetaDataSet) {

    this.beanClass = beanClass;
    this.propertyMetaDataMap = newHashMap();

    Set<PropertyMetaData> propertyMetaDataSet = newHashSet();
    Set<ExecutableMetaData> executableMetaDataSet = newHashSet();

    for (ConstraintMetaData constraintMetaData : constraintMetaDataSet) {
      if (constraintMetaData.getKind() == ElementKind.PROPERTY) {
        propertyMetaDataSet.add((PropertyMetaData) constraintMetaData);
      } else {
        executableMetaDataSet.add((ExecutableMetaData) constraintMetaData);
      }
    }

    Set<Cascadable> cascadedProperties = newHashSet();
    Set<MetaConstraint<?>> allMetaConstraints = newHashSet();

    for (PropertyMetaData propertyMetaData : propertyMetaDataSet) {
      propertyMetaDataMap.put(propertyMetaData.getName(), propertyMetaData);

      if (propertyMetaData.isCascading()) {
        cascadedProperties.add(propertyMetaData);
      }

      allMetaConstraints.addAll(propertyMetaData.getConstraints());
    }

    this.cascadedProperties = Collections.unmodifiableSet(cascadedProperties);
    this.allMetaConstraints = Collections.unmodifiableSet(allMetaConstraints);

    this.classHierarchyWithoutInterfaces =
        ClassHierarchyHelper.getHierarchy(beanClass, Filters.excludeInterfaces());

    setDefaultGroupSequenceOrProvider(defaultGroupSequence, defaultGroupSequenceProvider);

    this.directMetaConstraints = getDirectConstraints();

    this.executableMetaDataMap = Collections.unmodifiableMap(byIdentifier(executableMetaDataSet));

    this.beanDescriptor =
        new BeanDescriptorImpl(
            beanClass,
            getClassLevelConstraintsAsDescriptors(),
            getConstrainedPropertiesAsDescriptors(),
            getConstrainedMethodsAsDescriptors(),
            getConstrainedConstructorsAsDescriptors(),
            defaultGroupSequenceIsRedefined(),
            getDefaultGroupSequence(null));
  }
  private Set<MetaConstraint<?>> getDirectConstraints() {
    Set<MetaConstraint<?>> constraints = newHashSet();

    Set<Class<?>> classAndInterfaces = newHashSet();
    classAndInterfaces.add(beanClass);
    classAndInterfaces.addAll(ClassHierarchyHelper.getDirectlyImplementedInterfaces(beanClass));

    for (Class<?> clazz : classAndInterfaces) {
      for (MetaConstraint<?> metaConstraint : allMetaConstraints) {
        if (metaConstraint.getLocation().getDeclaringClass().equals(clazz)) {
          constraints.add(metaConstraint);
        }
      }
    }

    return Collections.unmodifiableSet(constraints);
  }