docs: @Override
    public Optional<Property.Builder> getPropertyNames(
        TypeElement valueType, ExecutableElement method) {
      boolean declaredOnValueType = method.getEnclosingElement().equals(valueType);
      String name = method.getSimpleName().toString();
      Matcher getterMatcher = GETTER_PATTERN.matcher(name);
      if (!getterMatcher.matches()) {
        if (declaredOnValueType) {
          messager.printMessage(
              ERROR,
              "Only getter methods (starting with '" + GET_PREFIX
                  + "' or '" + IS_PREFIX + "') may be declared abstract on FreeBuilder types",
              method);
        } else {
          printNoImplementationMessage(valueType, method);
        }
        return Optional.empty();
      }
      String prefix = getterMatcher.group(1);
      String capitalizedName = getterMatcher.group(2);
      if (hasUpperCase(capitalizedName.codePointAt(0))) {
        if (declaredOnValueType) {
          String message = new StringBuilder()
              .append("Getter methods cannot have a lowercase character immediately after the '")
              .append(prefix)
              .append("' prefix on FreeBuilder types (did you mean '")
              .append(prefix)
              .appendCodePoint(Character.toUpperCase(capitalizedName.codePointAt(0)))
              .append(capitalizedName.substring(capitalizedName.offsetByCodePoints(0, 1)))
              .append("'?)")
              .toString();
          messager.printMessage(ERROR, message, method);
        } else {
          printNoImplementationMessage(valueType, method);
        }
        return Optional.empty();
      }
      TypeMirror returnType = getReturnType(valueType, method, types);
      if (returnType.getKind() == TypeKind.VOID) {
        if (declaredOnValueType) {
          messager.printMessage(
              ERROR, "Getter methods must not be void on FreeBuilder types", method);
        } else {
          printNoImplementationMessage(valueType, method);
        }
        return Optional.empty();
      }
      if (prefix.equals(IS_PREFIX) && (returnType.getKind() != TypeKind.BOOLEAN)) {
        if (declaredOnValueType) {
          messager.printMessage(
              ERROR,
              "Getter methods starting with '" + IS_PREFIX
                  + "' must return a boolean on FreeBuilder types",
              method);
        } else {
          printNoImplementationMessage(valueType, method);
        }
        return Optional.empty();
      }
      if (!method.getParameters().isEmpty()) {
        if (declaredOnValueType) {
          messager.printMessage(
              ERROR, "Getter methods cannot take parameters on FreeBuilder types", method);
        } else {
          printNoImplementationMessage(valueType, method);
        }
        return Optional.empty();
      }
      if (!isLegalType(returnType)) {
        // The compiler should already have issued an error.
        return Optional.empty();
      }
  
      String camelCaseName = Introspector.decapitalize(capitalizedName);
      return Optional.of(new Property.Builder()
          .setUsingBeanConvention(true)
          .setName(camelCaseName)
          .setCapitalizedName(capitalizedName)
          .setGetterName(getterMatcher.group(0)));
    }