public String buildUiXml(
      final String templateContents,
      final String destFile,
      final List<MethodMetadata> proxyMethods) {
    FileReader fileReader = null;
    try {
      final DocumentBuilder builder = XmlUtils.getDocumentBuilder();
      builder.setEntityResolver(
          new EntityResolver() {
            public InputSource resolveEntity(final String publicId, final String systemId)
                throws SAXException, IOException {
              if (systemId.equals("http://dl.google.com/gwt/DTD/xhtml.ent")) {
                return new InputSource(
                    FileUtils.getInputStream(GwtScaffoldMetadata.class, "templates/xhtml.ent"));
              }

              // Use the default behaviour
              return null;
            }
          });

      InputSource source = new InputSource();
      source.setCharacterStream(new StringReader(templateContents));

      final Document templateDocument = builder.parse(source);

      if (!new File(destFile).exists()) {
        return transformXml(templateDocument);
      }

      source = new InputSource();
      fileReader = new FileReader(destFile);
      source.setCharacterStream(fileReader);
      final Document existingDocument = builder.parse(source);

      // Look for the element holder denoted by the 'debugId' attribute
      // first
      Element existingHoldingElement =
          XmlUtils.findFirstElement(
              "//*[@debugId='" + "boundElementHolder" + "']",
              existingDocument.getDocumentElement());
      Element templateHoldingElement =
          XmlUtils.findFirstElement(
              "//*[@debugId='" + "boundElementHolder" + "']",
              templateDocument.getDocumentElement());

      // If holding element isn't found then the holding element is either
      // not widget based or using the old convention of 'id' so look for
      // the element holder with an 'id' attribute
      if (existingHoldingElement == null) {
        existingHoldingElement =
            XmlUtils.findFirstElement(
                "//*[@id='" + "boundElementHolder" + "']", existingDocument.getDocumentElement());
      }
      if (templateHoldingElement == null) {
        templateHoldingElement =
            XmlUtils.findFirstElement(
                "//*[@id='" + "boundElementHolder" + "']", templateDocument.getDocumentElement());
      }

      if (existingHoldingElement != null) {
        final Map<String, Element> templateElementMap = new LinkedHashMap<String, Element>();
        for (final Element element : XmlUtils.findElements("//*[@id]", templateHoldingElement)) {
          templateElementMap.put(element.getAttribute("id"), element);
        }

        final Map<String, Element> existingElementMap = new LinkedHashMap<String, Element>();
        for (final Element element : XmlUtils.findElements("//*[@id]", existingHoldingElement)) {
          existingElementMap.put(element.getAttribute("id"), element);
        }

        if (existingElementMap.keySet().containsAll(templateElementMap.values())) {
          return transformXml(existingDocument);
        }

        final List<Element> elementsToAdd = new ArrayList<Element>();
        for (final Map.Entry<String, Element> entry : templateElementMap.entrySet()) {
          if (!existingElementMap.keySet().contains(entry.getKey())) {
            elementsToAdd.add(entry.getValue());
          }
        }

        final List<Element> elementsToRemove = new ArrayList<Element>();
        for (final Map.Entry<String, Element> entry : existingElementMap.entrySet()) {
          if (!templateElementMap.keySet().contains(entry.getKey())) {
            elementsToRemove.add(entry.getValue());
          }
        }

        for (final Element element : elementsToAdd) {
          final Node importedNode = existingDocument.importNode(element, true);
          existingHoldingElement.appendChild(importedNode);
        }

        for (final Element element : elementsToRemove) {
          existingHoldingElement.removeChild(element);
        }

        if (elementsToAdd.size() > 0) {
          final List<Element> sortedElements = new ArrayList<Element>();
          for (final MethodMetadata method : proxyMethods) {
            final String propertyName =
                StringUtils.uncapitalize(
                    BeanInfoUtils.getPropertyNameForJavaBeanMethod(method).getSymbolName());
            final Element element =
                XmlUtils.findFirstElement(
                    "//*[@id='" + propertyName + "']", existingHoldingElement);
            if (element != null) {
              sortedElements.add(element);
            }
          }
          for (final Element el : sortedElements) {
            if (el.getParentNode() != null && el.getParentNode().equals(existingHoldingElement)) {
              existingHoldingElement.removeChild(el);
            }
          }
          for (final Element el : sortedElements) {
            existingHoldingElement.appendChild(el);
          }
        }

        return transformXml(existingDocument);
      }

      return transformXml(templateDocument);
    } catch (final Exception e) {
      throw new IllegalStateException(e);
    } finally {
      IOUtils.closeQuietly(fileReader);
    }
  }
  /**
   * Obtains the "toString" method for this type, if available.
   *
   * <p>If the user provided a non-default name for "toString", that method will be returned.
   *
   * @return the "toString" method declared on this type or that will be introduced (or null if
   *     undeclared and not introduced)
   */
  public MethodMetadata getToStringMethod() {
    // Compute the relevant toString method name
    JavaSymbolName methodName = new JavaSymbolName("toString");
    if (!this.toStringMethod.equals("")) {
      methodName = new JavaSymbolName(this.toStringMethod);
    }

    // See if the type itself declared the method
    MethodMetadata result =
        MemberFindingUtils.getDeclaredMethod(governorTypeDetails, methodName, null);
    if (result != null) {
      return result;
    }

    // Decide whether we need to produce the toString method
    if (this.toStringMethod.equals("")) {
      return null;
    }

    InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
    bodyBuilder.appendFormalLine("StringBuilder sb = new StringBuilder();");

    /** Key: field name, Value: accessor name */
    Map<String, String> map = new LinkedHashMap<String, String>();

    /** Field names */
    List<String> order = new ArrayList<String>();

    Set<String> excludeFieldsSet = new LinkedHashSet<String>();
    if (excludeFields != null && excludeFields.length > 0) {
      Collections.addAll(excludeFieldsSet, excludeFields);
    }

    for (MethodMetadata accessor : locatedAccessors) {
      String accessorName = accessor.getMethodName().getSymbolName();
      String fieldName = BeanInfoUtils.getPropertyNameForJavaBeanMethod(accessor).getSymbolName();
      if (!excludeFieldsSet.contains(StringUtils.uncapitalize(fieldName))
          && !map.containsKey(fieldName)) {
        String accessorText = accessorName + "()";
        if (accessor.getReturnType().isCommonCollectionType()) {
          accessorText = accessorName + "() == null ? \"null\" : " + accessorName + "().size()";
        } else if (accessor.getReturnType().isArray()) {
          accessorText = "java.util.Arrays.toString(" + accessorName + "())";
        } else if (Calendar.class
            .getName()
            .equals(accessor.getReturnType().getFullyQualifiedTypeName())) {
          accessorText = accessorName + "() == null ? \"null\" : " + accessorName + "().getTime()";
        }
        map.put(fieldName, accessorText);
        order.add(fieldName);
      }
    }

    if (!order.isEmpty()) {
      int index = 0;
      int size = map.keySet().size();
      for (String fieldName : order) {
        index++;
        String accessorText = map.get(fieldName);
        StringBuilder string = new StringBuilder();
        string
            .append("sb.append(\"")
            .append(fieldName)
            .append(": \").append(")
            .append(accessorText)
            .append(")");
        if (index < size) {
          string.append(".append(\", \")");
        }
        string.append(";");
        bodyBuilder.appendFormalLine(string.toString());
      }

      bodyBuilder.appendFormalLine("return sb.toString();");

      MethodMetadataBuilder methodBuilder =
          new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, STRING, bodyBuilder);
      result = methodBuilder.build();
    }

    return result;
  }