private void generateTraversalSource()

in gremlin-annotations/src/main/java/com/jetbrains/youtrackdb/internal/annotations/gremlin/dsl/GremlinDslProcessor.java [232:429]


  private void generateTraversalSource(final Context ctx) throws IOException {
    final var graphTraversalSourceElement = ctx.traversalSourceDslType;
    final var traversalSourceClass = TypeSpec.classBuilder(ctx.traversalSourceClazz)
        .addModifiers(Modifier.PUBLIC)
        .superclass(TypeName.get(graphTraversalSourceElement.asType()));

    // add the required constructors for instantiation
    traversalSourceClass.addMethod(MethodSpec.constructorBuilder()
        .addModifiers(Modifier.PUBLIC)
        .addParameter(Graph.class, "graph")
        .addStatement("super($N)", "graph")
        .build());
    traversalSourceClass.addMethod(MethodSpec.constructorBuilder()
        .addModifiers(Modifier.PUBLIC)
        .addParameter(Graph.class, "graph")
        .addParameter(TraversalStrategies.class, "strategies")
        .addStatement("super($N, $N)", "graph", "strategies")
        .build());
    traversalSourceClass.addMethod(MethodSpec.constructorBuilder()
        .addModifiers(Modifier.PUBLIC)
        .addParameter(RemoteConnection.class, "connection")
        .addStatement("super($N)", "connection")
        .build());

    // override methods to return the DSL TraversalSource. find GraphTraversalSource class somewhere in the hierarchy
    final var tinkerPopsGraphTraversalSource = findClassAsElement(graphTraversalSourceElement,
        GraphTraversalSource.class);
    final Predicate<ExecutableElement> notGraphTraversalSourceReturnValues = e -> !(
        e.getReturnType().getKind() == TypeKind.DECLARED
            && ((DeclaredType) e.getReturnType()).asElement().getSimpleName()
            .contentEquals(GraphTraversalSource.class.getSimpleName()));
    for (var elementOfGraphTraversalSource : findMethodsOfElement(
        tinkerPopsGraphTraversalSource, notGraphTraversalSourceReturnValues)) {
      // first copy/override methods that return a GraphTraversalSource so that we can instead return
      // the DSL TraversalSource class.
      traversalSourceClass.addMethod(
          constructMethod(elementOfGraphTraversalSource, ctx.traversalSourceClassName, "",
              Modifier.PUBLIC));
    }

    // override methods that return GraphTraversal that come from the user defined extension of GraphTraversal
    if (!graphTraversalSourceElement.getSimpleName()
        .contentEquals(GraphTraversalSource.class.getSimpleName())) {
      final Predicate<ExecutableElement> notGraphTraversalReturnValues = e -> !(
          e.getReturnType().getKind() == TypeKind.DECLARED
              && ((DeclaredType) e.getReturnType()).asElement().getSimpleName()
              .contentEquals(GraphTraversal.class.getSimpleName()));
      for (var templateMethod : findMethodsOfElement(graphTraversalSourceElement,
          notGraphTraversalReturnValues)) {
        final var methodToAdd = MethodSpec.methodBuilder(
                templateMethod.getSimpleName().toString())
            .addModifiers(Modifier.PUBLIC)
            .addAnnotation(Override.class);

        methodToAdd.addStatement("$T clone = this.clone()", ctx.traversalSourceClassName);
        addMethodBody(methodToAdd, templateMethod, "return new $T (clone, super.$L(",
            ").asAdmin())",
            ctx.defaultTraversalClassName, templateMethod.getSimpleName());
        methodToAdd.returns(getReturnTypeDefinition(ctx.traversalClassName, templateMethod));

        traversalSourceClass.addMethod(methodToAdd.build());
      }
    }

    if (ctx.generateDefaultMethods) {
      // override methods that return GraphTraversal
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("addV")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addStatement("$N clone = this.clone()", ctx.traversalSourceClazz)
          .addStatement("clone.getBytecode().addStep($T.addV)", GraphTraversal.Symbols.class)
          .addStatement("$N traversal = new $N(clone)", ctx.defaultTraversalClazz,
              ctx.defaultTraversalClazz)
          .addStatement("return ($T) traversal.asAdmin().addStep(new $T(traversal, (String) null))",
              ctx.traversalClassName, AddVertexStartStep.class)
          .returns(ParameterizedTypeName.get(ctx.traversalClassName, ClassName.get(Vertex.class),
              ClassName.get(Vertex.class)))
          .build());
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("addV")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addParameter(String.class, "label")
          .addStatement("$N clone = this.clone()", ctx.traversalSourceClazz)
          .addStatement("clone.getBytecode().addStep($T.addV, label)", GraphTraversal.Symbols.class)
          .addStatement("$N traversal = new $N(clone)", ctx.defaultTraversalClazz,
              ctx.defaultTraversalClazz)
          .addStatement("return ($T) traversal.asAdmin().addStep(new $T(traversal, label))",
              ctx.traversalClassName, AddVertexStartStep.class)
          .returns(ParameterizedTypeName.get(ctx.traversalClassName, ClassName.get(Vertex.class),
              ClassName.get(Vertex.class)))
          .build());
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("addV")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addParameter(Traversal.class, "vertexLabelTraversal")
          .addStatement("$N clone = this.clone()", ctx.traversalSourceClazz)
          .addStatement("clone.getBytecode().addStep($T.addV, vertexLabelTraversal)",
              GraphTraversal.Symbols.class)
          .addStatement("$N traversal = new $N(clone)", ctx.defaultTraversalClazz,
              ctx.defaultTraversalClazz)
          .addStatement(
              "return ($T) traversal.asAdmin().addStep(new $T(traversal, vertexLabelTraversal))",
              ctx.traversalClassName, AddVertexStartStep.class)
          .returns(ParameterizedTypeName.get(ctx.traversalClassName, ClassName.get(Vertex.class),
              ClassName.get(Vertex.class)))
          .build());
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("addE")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addParameter(String.class, "label")
          .addStatement("$N clone = this.clone()", ctx.traversalSourceClazz)
          .addStatement("clone.getBytecode().addStep($T.addE, label)", GraphTraversal.Symbols.class)
          .addStatement("$N traversal = new $N(clone)", ctx.defaultTraversalClazz,
              ctx.defaultTraversalClazz)
          .addStatement("return ($T) traversal.asAdmin().addStep(new $T(traversal, label))",
              ctx.traversalClassName, AddEdgeStartStep.class)
          .returns(ParameterizedTypeName.get(ctx.traversalClassName, ClassName.get(Edge.class),
              ClassName.get(Edge.class)))
          .build());
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("addE")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addParameter(Traversal.class, "edgeLabelTraversal")
          .addStatement("$N clone = this.clone()", ctx.traversalSourceClazz)
          .addStatement("clone.getBytecode().addStep($T.addE, edgeLabelTraversal)",
              GraphTraversal.Symbols.class)
          .addStatement("$N traversal = new $N(clone)", ctx.defaultTraversalClazz,
              ctx.defaultTraversalClazz)
          .addStatement(
              "return ($T) traversal.asAdmin().addStep(new $T(traversal, edgeLabelTraversal))",
              ctx.traversalClassName, AddEdgeStartStep.class)
          .returns(ParameterizedTypeName.get(ctx.traversalClassName, ClassName.get(Edge.class),
              ClassName.get(Edge.class)))
          .build());
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("V")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addParameter(Object[].class, "vertexIds")
          .varargs(true)
          .addStatement("final Object[] ids = null == vertexIds ? new Object[] { null } : vertexIds;")
          .addStatement("$N clone = this.clone()", ctx.traversalSourceClazz)
          .addStatement("clone.getBytecode().addStep($T.V, ids)",
              GraphTraversal.Symbols.class)
          .addStatement("$N traversal = new $N(clone)", ctx.defaultTraversalClazz,
              ctx.defaultTraversalClazz)
          .addStatement(
              "return ($T) traversal.asAdmin().addStep(new $T(traversal, $T.class, true, ids))",
              ctx.traversalClassName, GraphStep.class, Vertex.class)
          .returns(ParameterizedTypeName.get(ctx.traversalClassName, ClassName.get(Vertex.class),
              ClassName.get(Vertex.class)))
          .build());
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("E")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addParameter(Object[].class, "edgeIds")
          .varargs(true)
          .addStatement("final Object[] ids = null == edgeIds ? new Object[] { null } : edgeIds;")
          .addStatement("$N clone = this.clone()", ctx.traversalSourceClazz)
          .addStatement("clone.getBytecode().addStep($T.E, ids)", GraphTraversal.Symbols.class)
          .addStatement("$N traversal = new $N(clone)", ctx.defaultTraversalClazz,
              ctx.defaultTraversalClazz)
          .addStatement(
              "return ($T) traversal.asAdmin().addStep(new $T(traversal, $T.class, true, ids))",
              ctx.traversalClassName, GraphStep.class, Edge.class)
          .returns(ParameterizedTypeName.get(ctx.traversalClassName, ClassName.get(Edge.class),
              ClassName.get(Edge.class)))
          .build());
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("inject")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addParameter(ArrayTypeName.of(TypeVariableName.get("S")), "starts")
          .varargs(true)
          .addTypeVariable(TypeVariableName.get("S"))
          .addStatement("final S[] s = null == starts ? (S[]) new Object[] { null } : starts;")
          .addStatement("$N clone = this.clone()", ctx.traversalSourceClazz)
          .addStatement("clone.getBytecode().addStep($T.inject, s)",
              GraphTraversal.Symbols.class)
          .addStatement("$N traversal = new $N(clone)", ctx.defaultTraversalClazz,
              ctx.defaultTraversalClazz)
          .addStatement("return ($T) traversal.asAdmin().addStep(new $T(traversal, s))",
              ctx.traversalClassName, InjectStep.class)
          .returns(ParameterizedTypeName.get(ctx.traversalClassName, TypeVariableName.get("S"),
              TypeVariableName.get("S")))
          .build());
      traversalSourceClass.addMethod(MethodSpec.methodBuilder("getAnonymousTraversalClass")
          .addModifiers(Modifier.PUBLIC)
          .addAnnotation(Override.class)
          .addStatement("return Optional.of(__.class)")
          .returns(ParameterizedTypeName.get(ClassName.get(Optional.class),
              ParameterizedTypeName.get(ClassName.get(Class.class),
                  WildcardTypeName.subtypeOf(Object.class))))
          .build());
    }

    final var traversalSourceJavaFile = JavaFile.builder(ctx.packageName,
        traversalSourceClass.build()).build();
    traversalSourceJavaFile.writeTo(filer);
  }