/**
   * Parses the given set of input stream representing XML constraint mappings.
   *
   * @param mappingStreams The streams to parse. Must support the mark/reset contract.
   */
  public final void parse(Set<InputStream> mappingStreams) {

    try {
      JAXBContext jc = JAXBContext.newInstance(ConstraintMappingsType.class);

      for (InputStream in : mappingStreams) {

        String schemaVersion = xmlParserHelper.getSchemaVersion("constraint mapping file", in);
        String schemaResourceName = getSchemaResourceName(schemaVersion);
        Schema schema = xmlParserHelper.getSchema(schemaResourceName);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setSchema(schema);

        ConstraintMappingsType mapping = getValidationConfig(in, unmarshaller);
        String defaultPackage = mapping.getDefaultPackage();

        parseConstraintDefinitions(mapping.getConstraintDefinition(), defaultPackage);

        for (BeanType bean : mapping.getBean()) {
          Class<?> beanClass = getClass(bean.getClazz(), defaultPackage);
          checkClassHasNotBeenProcessed(processedClasses, beanClass);
          annotationProcessingOptions.ignoreAnnotationConstraintForClass(
              beanClass, bean.getIgnoreAnnotations());
          parseClassLevelOverrides(bean.getClassType(), beanClass, defaultPackage);
          parseFieldLevelOverrides(bean.getField(), beanClass, defaultPackage);
          parsePropertyLevelOverrides(bean.getGetter(), beanClass, defaultPackage);
          processedClasses.add(beanClass);
        }
      }
    } catch (JAXBException e) {
      throw log.getErrorParsingMappingFileException(e);
    }
  }
  private void parseClassLevelOverrides(
      ClassType classType, Class<?> beanClass, String defaultPackage) {
    if (classType == null) {
      return;
    }

    // ignore annotation
    if (classType.getIgnoreAnnotations() != null) {
      annotationProcessingOptions.ignoreClassLevelConstraintAnnotations(
          beanClass, classType.getIgnoreAnnotations());
    }

    // group sequence
    List<Class<?>> groupSequence =
        createGroupSequence(classType.getGroupSequence(), defaultPackage);
    if (!groupSequence.isEmpty()) {
      defaultSequences.put(beanClass, groupSequence);
    }

    // constraints
    for (ConstraintType constraint : classType.getConstraint()) {
      MetaConstraint<?> metaConstraint =
          createMetaConstraint(constraint, beanClass, null, defaultPackage);
      addMetaConstraint(beanClass, metaConstraint);
    }
  }
  private void parsePropertyLevelOverrides(
      List<GetterType> getters, Class<?> beanClass, String defaultPackage) {
    List<String> getterNames = newArrayList();
    for (GetterType getterType : getters) {
      String getterName = getterType.getName();
      if (getterNames.contains(getterName)) {
        throw log.getIsDefinedTwiceInMappingXmlForBeanException(getterName, beanClass.getName());
      } else {
        getterNames.add(getterName);
      }
      boolean containsMethod =
          ReflectionHelper.containsMethodWithPropertyName(beanClass, getterName);
      if (!containsMethod) {
        throw log.getBeanDoesNotContainThePropertyException(beanClass.getName(), getterName);
      }
      final Method method = ReflectionHelper.getMethodFromPropertyName(beanClass, getterName);

      // ignore annotations
      boolean ignoreGetterAnnotation =
          getterType.getIgnoreAnnotations() == null ? false : getterType.getIgnoreAnnotations();
      if (ignoreGetterAnnotation) {
        annotationProcessingOptions.ignorePropertyLevelConstraintAnnotationsOnMember(method);
      }

      // valid
      if (getterType.getValid() != null) {
        addCascadedMember(beanClass, method);
      }

      // constraints
      for (ConstraintType constraint : getterType.getConstraint()) {
        MetaConstraint<?> metaConstraint =
            createMetaConstraint(constraint, beanClass, method, defaultPackage);
        addMetaConstraint(beanClass, metaConstraint);
      }
    }
  }
  private void parseFieldLevelOverrides(
      List<FieldType> fields, Class<?> beanClass, String defaultPackage) {
    List<String> fieldNames = newArrayList();
    for (FieldType fieldType : fields) {
      String fieldName = fieldType.getName();
      if (fieldNames.contains(fieldName)) {
        throw log.getIsDefinedTwiceInMappingXmlForBeanException(fieldName, beanClass.getName());
      } else {
        fieldNames.add(fieldName);
      }
      final boolean containsField = ReflectionHelper.containsDeclaredField(beanClass, fieldName);
      if (!containsField) {
        throw log.getBeanDoesNotContainTheFieldException(beanClass.getName(), fieldName);
      }
      final Field field = ReflectionHelper.getDeclaredField(beanClass, fieldName);

      // ignore annotations
      boolean ignoreFieldAnnotation =
          fieldType.getIgnoreAnnotations() == null ? false : fieldType.getIgnoreAnnotations();
      if (ignoreFieldAnnotation) {
        annotationProcessingOptions.ignorePropertyLevelConstraintAnnotationsOnMember(field);
      }

      // valid
      if (fieldType.getValid() != null) {
        addCascadedMember(beanClass, field);
      }

      // constraints
      for (ConstraintType constraint : fieldType.getConstraint()) {
        MetaConstraint<?> metaConstraint =
            createMetaConstraint(constraint, beanClass, field, defaultPackage);
        addMetaConstraint(beanClass, metaConstraint);
      }
    }
  }