public static FilterMappingMetaData parse(XMLStreamReader reader) throws XMLStreamException {
    FilterMappingMetaData filterMapping = new FilterMappingMetaData();

    // Handle attributes
    final int count = reader.getAttributeCount();
    for (int i = 0; i < count; i++) {
      final String value = reader.getAttributeValue(i);
      if (reader.getAttributeNamespace(i) != null) {
        continue;
      }
      final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
      switch (attribute) {
        case ID:
          {
            filterMapping.setId(value);
            break;
          }
        default:
          throw unexpectedAttribute(reader, i);
      }
    }

    // Handle elements
    while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
      final Element element = Element.forName(reader.getLocalName());
      switch (element) {
        case FILTER_NAME:
          filterMapping.setFilterName(getElementText(reader));
          break;
        case URL_PATTERN:
          List<String> urlPatterns = filterMapping.getUrlPatterns();
          if (urlPatterns == null) {
            urlPatterns = new ArrayList<String>();
            filterMapping.setUrlPatterns(urlPatterns);
          }
          urlPatterns.add(getElementText(reader));
          break;
        case SERVLET_NAME:
          List<String> servletNames = filterMapping.getServletNames();
          if (servletNames == null) {
            servletNames = new ArrayList<String>();
            filterMapping.setServletNames(servletNames);
          }
          servletNames.add(getElementText(reader));
          break;
        case DISPATCHER:
          List<DispatcherType> dispatchers = filterMapping.getDispatchers();
          if (dispatchers == null) {
            dispatchers = new ArrayList<DispatcherType>();
            filterMapping.setDispatchers(dispatchers);
          }
          dispatchers.add(DispatcherType.valueOf(getElementText(reader)));
          break;
        default:
          throw unexpectedElement(reader);
      }
    }

    return filterMapping;
  }