Skip to content

Java: outbound HTTP calls through an injected client, a format-string URL or a request builder yield no HTTP_CALLS #2668

Open

Description

@emouty

Version

codebase-memory-mcp 0.12.0

Platform

Linux (x64)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

ui

What happened, and what did you expect?

Indexing a Java client that calls a Java server produces HTTP_CALLS edges only when the HTTP client is
constructed inline at the call site (new RestTemplate().getForObject("/v1/orders", …)) and the URL is a
literal or an expr + "literal" concatenation. Three common production shapes produce no HTTP_CALLS edge:

  1. the client is an injected field, parameter or local whose type comes from a jar
    (private final RestTemplate restTemplate;), or an in-house wrapper around such a client;
  2. the URL is a formatted string ("%s/challenges/%s/verified/%s".formatted(base, id, token));
  3. the URL goes into a request builder and the request is dispatched by a later call
    (like for OkHttp new Request.Builder().url("/v1/orders") … client.newCall(request).execute())

Expected: see the table under "Result vs expected" in the Reproduction section.

Nearest existing issues, none covering Java: #706 , #1147, #1009.

Reproduction

1. Code. Two dummy repos

Client repo /tmp/cbm-java-http-client, all files under src/main/java/com/acme/client/:

// InlineClient.java   (control: these two DO produce HTTP_CALLS)
package com.acme.client;
import org.springframework.web.client.RestTemplate;
public class InlineClient {
    public String literal() {
        return new RestTemplate().getForObject("/v1/orders", String.class);
    }
    public String concat(String baseUrl) {
        return new RestTemplate().getForObject(baseUrl + "/challenges/state", String.class);
    }
}
// JarFieldClient.java   (gap 1: jar-typed field; `verified` also hits gap 2)
package com.acme.client;
import org.springframework.web.client.RestTemplate;
public class JarFieldClient {
    private final RestTemplate restTemplate;
    public JarFieldClient(RestTemplate restTemplate) { this.restTemplate = restTemplate; }
    public String orders() {
        return restTemplate.getForObject("/v1/orders", String.class);
    }
    public String verified(String baseUrl, String challengeId, String token) {
        return restTemplate.getForObject("%s/challenges/%s/verified/%s".formatted(baseUrl, challengeId, token), String.class);
    }
}
// LocalVarClient.java   (gap 1: jar-typed parameter and local)
package com.acme.client;
import org.springframework.web.client.RestTemplate;
public class LocalVarClient {
    public String orders(RestTemplate rt) {
        return rt.getForObject("/v1/orders", String.class);
    }
    public String byId(RestTemplate rt) {
        var t = rt;
        return t.getForObject("/v1/orders/{id}", String.class, "42");
    }
}
// WrapperClient.java   (gap 1: in-house wrapper type from a jar; build() returns a RestTemplate)
package com.acme.client;
import com.acme.http.AcmeHttpClientBuilder;
public class WrapperClient {
    private final AcmeHttpClientBuilder builder;
    public WrapperClient(AcmeHttpClientBuilder builder) { this.builder = builder; }
    public String orders() {
        return builder.build().getForObject("/v1/orders", String.class);
    }
}
// FormatInlineClient.java   (gap 2 alone: inline client, format-string URL)
package com.acme.client;
import org.springframework.web.client.RestTemplate;
public class FormatInlineClient {
    public String verified(String baseUrl, String challengeId, String token) {
        return new RestTemplate().getForObject("%s/challenges/%s/verified/%s".formatted(baseUrl, challengeId, token), String.class);
    }
}
// OkClient.java   (gap 3 alone: inline client, URL into a builder, dispatched by a later call)
package com.acme.client;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OkClient {
    public Response orders() throws Exception {
        Request request = new Request.Builder().url("/v1/orders").get().build();
        return new OkHttpClient().newCall(request).execute();
    }
}

Server repo /tmp/cbm-java-server, under src/main/java/com/acme/server/ (JAX-RS; indexes correctly):

// OrderResource.java
package com.acme.server;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
@Path("/v1/orders")
public class OrderResource {
    @GET public String list() { return "[]"; }
    @GET @Path("/{id}") public String get(@PathParam("id") String id) { return id; }
    @POST public String create(String body) { return body; }
}
// ChallengeResource.java
package com.acme.server;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
@Path("/challenges")
public class ChallengeResource {
    @GET @Path("/state") public String state() { return "ok"; }
    @GET @Path("/{id}/verified/{token}")
    public String verified(@PathParam("id") String id, @PathParam("token") String token) { return id; }
}

2. Commands. The project ids below are what the indexer derives from the /tmp/... paths.

codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-java-http-client","mode":"moderate"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-java-server","mode":"moderate"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-java-http-client","query":"MATCH (f)-[e:HTTP_CALLS]->(r:Route) RETURN f.file_path, f.name, r.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-java-http-client","query":"MATCH (f)-[e:CALLS]->(g) RETURN f.file_path, f.name, g.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-java-server","query":"MATCH (r:Route) RETURN r.qualified_name"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-java-http-client","mode":"cross-repo-intelligence","target_projects":["tmp-cbm-java-server"]}'

3. Result vs expected.

Client HTTP_CALLS (CLI output; expected 9 rows, one per call site in the table below):

rows: 2  (cols: f.file_path f.name r.qualified_name)
  src/main/java/com/acme/client/InlineClient.java literal __route__GET__/v1/orders
  src/main/java/com/acme/client/InlineClient.java concat __route__GET__/challenges/state
returned: 2

Server Route nodes (correct):

rows: 5  (cols: r.qualified_name)
  __route__GET__/v1/orders
  __route__GET__/v1/orders/{}
  __route__POST__/v1/orders
  __route__GET__/challenges/state
  __route__GET__/challenges/{}/verified/{}
returned: 5

cross-repo-intelligence: "cross_http_calls":2,"total_cross_edges":2 (the two InlineClient edges).

Expected 9 (all rows below should be a HTTP_CALLS).

call site shape expected Route current HTTP_CALLS
InlineClient.literal new RestTemplate().getForObject("/v1/orders", …) __route__GET__/v1/orders yes
InlineClient.concat new RestTemplate().getForObject(baseUrl + "/challenges/state", …) __route__GET__/challenges/state yes
JarFieldClient.orders restTemplate.getForObject("/v1/orders", …), RestTemplate field typed from a jar __route__GET__/v1/orders no
LocalVarClient.orders rt.getForObject("/v1/orders", …), RestTemplate rt parameter __route__GET__/v1/orders no
LocalVarClient.byId var t = rt; t.getForObject("/v1/orders/{id}", …) __route__GET__/v1/orders/{} no
WrapperClient.orders builder.build().getForObject("/v1/orders", …), wrapper type from a jar __route__GET__/v1/orders no
FormatInlineClient.verified new RestTemplate().getForObject("%s/challenges/%s/verified/%s".formatted(…), …) __route__GET__/challenges/{}/verified/{} no
JarFieldClient.verified same format string on the jar-typed field (gaps 1 and 2) __route__GET__/challenges/{}/verified/{} no
OkClient.orders new Request.Builder().url("/v1/orders").get().build() then new OkHttpClient().newCall(request).execute() __route__GET__/v1/orders no

Logs


Diagnostics trajectory (memory / performance / leak issues)


Project scale (if relevant)

No response

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Activity

  1. added
    parsing/qualityGraph extraction bugs, false positives, missing edges
    ux/behaviorDisplay bugs, docs, adoption UX
    windowsWindows-specific issues
    on Oct 16, 2026
  2. added
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    and removed
    windowsWindows-specific issues
    on Oct 19, 2026
  3. DeusData commented on Oct 19, 2026

    @DeusData
    Owner

    Thank you for the shareable client/server fixtures and the comparison table. Separating injected receivers, formatted URLs, and builder-based requests makes the missing HTTP_CALLS reports much easier to evaluate independently. There is no verified fix to report yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.ux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions