private void generateBuilder(JType optionsDeclaredInNode, BuilderModel model) {
    boolean markGenerated = model.isMarkGenerated();

    JSourceFile source = optionsDeclaredInNode.getCompilationUnit().getSource();
    JType pojo = source.getMainType();
    JType builder;

    boolean isAbstract = model.isSupportSubclassing();

    if (pojo.getSimpleName().equals(model.getBuilderTypeSimpleRaw())) {
      builder = pojo;
    } else {
      builder = pojo.getChildTypeWithNameOrNull(model.getBuilderTypeSimpleRaw());
      if (builder == null) {
        SourceTemplate t =
            newSourceTemplate()
                .var("typeBounds", model.getPojoType().getTypeBoundsOrNull())
                .var(
                    "type",
                    model.getBuilderTypeSimpleRaw()
                        + Strings.nullToEmpty(model.getBuilderTypeBoundsOrNull()))
                .var("modifier", (isAbstract ? "abstract" : ""))
                .pl("public static ${modifier} class ${type} { }");

        pojo.asMutator(getContext()).addType(t.asResolvedTypeNodeNamed(null));
        builder = pojo.getChildTypeWithName(model.getBuilderTypeSimpleRaw());
        getGeneratorMeta().addGeneratedMarkers(builder.asAbstractTypeDecl());
      }
    }
    // generate the with() method and aliases
    generateStaticBuilderCreateMethods(model, pojo);
    // TODO:builder ctor
    // TODO:builder clone/from method

    // add the self() method
    if (!"this".equals(model.getBuilderSelfAccessor())) {
      SourceTemplate selfMethod =
          newSourceTemplate()
              .var("selfType", model.getBuilderSelfType())
              .var("selfGetter", model.getBuilderSelfAccessor())
              .pl("protected ${selfType} ${selfGetter} { return (${selfType})this; }");

      addMethod(builder, selfMethod.asMethodNodeSnippet(), markGenerated);
    }

    for (BuilderPropertyModel property : model.getProperties()) {
      if (property.isWriteable()) {
        generateField(markGenerated, builder, property);
        generateSetter(model, markGenerated, builder, property);
        generateCollectionAddRemove(builder, model, property);
        generateMapAddRemove(builder, model, property);
      }
    }

    generateAllArgCtor(pojo, model);
    generateBuildMethod(builder, model);

    writeToDiskIfChanged(source);
  }